am 292e62aa: am babc7880: am 38e59046: am dd0fcf2f: am 9f1005fd: am 84e3386e: am 5fff297a: am e2ee1baf: resolved conflicts for merge of 6458c80c to jb-mr1.1-docs

* commit '292e62aa0d092de56c7b26e75a59beaa0f26fb4e':
diff --git a/apps/Development/res/layout/connectivity.xml b/apps/Development/res/layout/connectivity.xml
index 2df645c..53f1ed7 100644
--- a/apps/Development/res/layout/connectivity.xml
+++ b/apps/Development/res/layout/connectivity.xml
@@ -213,6 +213,33 @@
 
     <LinearLayout
       android:orientation="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content">
+        <Button android:id="@+id/startTdls"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="@string/start_tdls" />
+        <TextView
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="@string/mac_tdls" />
+        <EditText android:id="@+id/sc_ip_mac"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:minEms="10" />
+        <Button android:id="@+id/stopTdls"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="@string/stop_tdls" />
+    </LinearLayout>
+
+    <!-- divider line -->
+    <View android:background="#FFFFFFFF"
+      android:layout_width="match_parent"
+      android:layout_height="3dip" />
+
+    <LinearLayout
+      android:orientation="horizontal"
       android:paddingTop="4dip"
       android:layout_width="match_parent"
       android:layout_height="wrap_content">
diff --git a/apps/Development/res/values/strings.xml b/apps/Development/res/values/strings.xml
index b7ed5e1..ced7b72 100644
--- a/apps/Development/res/values/strings.xml
+++ b/apps/Development/res/values/strings.xml
@@ -34,6 +34,10 @@
     <string name="scan_cycles">Scan Cycles: </string>
     <string name="disconnect">Disconnect</string>
 
+    <string name="start_tdls">Start TDLS</string>
+    <string name="stop_tdls">Stop TDLS</string>
+    <string name="mac_tdls"> IP/MAC: </string>
+
     <string name="start_mms">Start MMS</string>
     <string name="stop_mms">Stop MMS</string>
     <string name="start_hipri">Start HiPri</string>
diff --git a/apps/Development/src/com/android/development/Connectivity.java b/apps/Development/src/com/android/development/Connectivity.java
index 95487dc..7d4491b 100644
--- a/apps/Development/src/com/android/development/Connectivity.java
+++ b/apps/Development/src/com/android/development/Connectivity.java
@@ -117,6 +117,8 @@
     private long mTotalScanTime = 0;
     private long mTotalScanCount = 0;
 
+    private String mTdlsAddr = null;
+
     private WifiManager mWm;
     private PowerManager mPm;
     private ConnectivityManager mCm;
@@ -235,6 +237,7 @@
                     unregisterReceiver(mScanRecv);
                     mScanButton.setText(GET_SCAN_RES);
                 } else {
+                    Log.d(TAG, "Scan: START " + mScanCur);
                     mStartTime = SystemClock.elapsedRealtime();
                     mWm.startScan();
                 }
@@ -289,6 +292,9 @@
         mIntentFilter = new IntentFilter();
         mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
 
+        findViewById(R.id.startTdls).setOnClickListener(mClickListener);
+        findViewById(R.id.stopTdls).setOnClickListener(mClickListener);
+
         findViewById(R.id.start_mms).setOnClickListener(mClickListener);
         findViewById(R.id.stop_mms).setOnClickListener(mClickListener);
         findViewById(R.id.start_hipri).setOnClickListener(mClickListener);
@@ -338,6 +344,12 @@
                 case R.id.startScan:
                     onStartScanCycle();
                     break;
+                case R.id.startTdls:
+                    onStartTdls();
+                    break;
+                case R.id.stopTdls:
+                    onStopTdls();
+                    break;
                 case R.id.start_mms:
                     mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                             Phone.FEATURE_ENABLE_MMS);
@@ -469,6 +481,7 @@
                 mWm.disconnect();
             mTotalScanTime = 0;
             mTotalScanCount = 0;
+            Log.d(TAG, "Scan: START " + mScanCur);
             mStartTime = SystemClock.elapsedRealtime();
             mWm.startScan();
         } else {
@@ -485,6 +498,30 @@
         }
     }
 
+    private void onStartTdls() {
+        mTdlsAddr = ((EditText)findViewById(R.id.sc_ip_mac)).getText().toString();
+        Log.d(TAG, "TDLS: START " + mTdlsAddr);
+        InetAddress inetAddress = null;
+        try {
+            inetAddress = InetAddress.getByName(mTdlsAddr);
+            mWm.setTdlsEnabled(inetAddress, true);
+        } catch (Exception e) {
+            mWm.setTdlsEnabledWithMacAddress(mTdlsAddr, true);
+        }
+    }
+
+    private void onStopTdls() {
+        if (mTdlsAddr == null) return;
+        Log.d(TAG, "TDLS: STOP " + mTdlsAddr);
+        InetAddress inetAddress = null;
+        try {
+            inetAddress = InetAddress.getByName(mTdlsAddr);
+            mWm.setTdlsEnabled(inetAddress, false);
+        } catch (Exception e) {
+            mWm.setTdlsEnabledWithMacAddress(mTdlsAddr, false);
+        }
+    }
+
     private void onAddDefaultRoute() {
         try {
             mNetd.addRoute("eth0", new RouteInfo(null,
diff --git a/apps/Fallback/res/values-en-rIN/strings.xml b/apps/Fallback/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..a7c82cb
--- /dev/null
+++ b/apps/Fallback/res/values-en-rIN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"Unsupported action"</string>
+    <string name="error" msgid="6539615832923362301">"That action is not currently supported."</string>
+</resources>
diff --git a/apps/Fallback/res/values-et-rEE/strings.xml b/apps/Fallback/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..181b324
--- /dev/null
+++ b/apps/Fallback/res/values-et-rEE/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Taandepilt"</string>
+    <string name="title" msgid="8156274565006125136">"Toetuseta toiming"</string>
+    <string name="error" msgid="6539615832923362301">"Seda toimingut praegu ei toetata."</string>
+</resources>
diff --git a/apps/Fallback/res/values-fr-rCA/strings.xml b/apps/Fallback/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..a751b97
--- /dev/null
+++ b/apps/Fallback/res/values-fr-rCA/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Application de secours"</string>
+    <string name="title" msgid="8156274565006125136">"Action non prise en charge"</string>
+    <string name="error" msgid="6539615832923362301">"Cette action n\'est actuellement pas prise en charge."</string>
+</resources>
diff --git a/apps/Fallback/res/values-hy-rAM/strings.xml b/apps/Fallback/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..1547741
--- /dev/null
+++ b/apps/Fallback/res/values-hy-rAM/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"Չաջակցվող գործողություն"</string>
+    <string name="error" msgid="6539615832923362301">"Այդ գործողությունն այժմ չի աջակցվում:"</string>
+</resources>
diff --git a/apps/Fallback/res/values-ka-rGE/strings.xml b/apps/Fallback/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..469a135
--- /dev/null
+++ b/apps/Fallback/res/values-ka-rGE/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"შემოვლით რეჟიმში გადასვლა"</string>
+    <string name="title" msgid="8156274565006125136">"მოქმედება მხარდაჭერილი არ არის"</string>
+    <string name="error" msgid="6539615832923362301">"ეს მოქმედება ამჟამად მხარდაუჭერელია."</string>
+</resources>
diff --git a/apps/Fallback/res/values-km-rKH/strings.xml b/apps/Fallback/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..a442335
--- /dev/null
+++ b/apps/Fallback/res/values-km-rKH/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"សកម្មភាព​មិន​បាន​គាំទ្រ"</string>
+    <string name="error" msgid="6539615832923362301">"បច្ចុប្បន្ន​សកម្មភាព​នោះ​មិន​ត្រូវ​បាន​គាំទ្រ​ទេ។"</string>
+</resources>
diff --git a/apps/Fallback/res/values-lo-rLA/strings.xml b/apps/Fallback/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..948b60f
--- /dev/null
+++ b/apps/Fallback/res/values-lo-rLA/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"ການເຮັດວຽກທີ່ບໍ່ຮອງຮັບ"</string>
+    <string name="error" msgid="6539615832923362301">"ການເຮັດວຽກນັ້ນຍັງບໍ່ຮອງຮັບເທື່ອ"</string>
+</resources>
diff --git a/apps/Fallback/res/values-mn-rMN/strings.xml b/apps/Fallback/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..8cb3870
--- /dev/null
+++ b/apps/Fallback/res/values-mn-rMN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"Дэмжигдээгүй үйлдэл"</string>
+    <string name="error" msgid="6539615832923362301">"Энэ үйлдэл одоогоор дэмжигдээгүй."</string>
+</resources>
diff --git a/apps/Fallback/res/values-ms-rMY/strings.xml b/apps/Fallback/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..930fe79
--- /dev/null
+++ b/apps/Fallback/res/values-ms-rMY/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Jatuh balik"</string>
+    <string name="title" msgid="8156274565006125136">"Tindakan tidak disokong"</string>
+    <string name="error" msgid="6539615832923362301">"Tindakan tidak disokong pada masa ini."</string>
+</resources>
diff --git a/apps/Fallback/res/values-zh-rHK/strings.xml b/apps/Fallback/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..ce01c92
--- /dev/null
+++ b/apps/Fallback/res/values-zh-rHK/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"後備"</string>
+    <string name="title" msgid="8156274565006125136">"不支援的操作"</string>
+    <string name="error" msgid="6539615832923362301">"目前不支援該操作。"</string>
+</resources>
diff --git a/apps/SettingInjectorSample/Android.mk b/apps/SettingInjectorSample/Android.mk
new file mode 100644
index 0000000..8cc0c5e
--- /dev/null
+++ b/apps/SettingInjectorSample/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := SettingInjectorSample
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/apps/SettingInjectorSample/AndroidManifest.xml b/apps/SettingInjectorSample/AndroidManifest.xml
new file mode 100644
index 0000000..ef8f838
--- /dev/null
+++ b/apps/SettingInjectorSample/AndroidManifest.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Declare the contents of this Android application.  The namespace
+     attribute brings in the Android platform namespace, and the package
+     supplies a unique name for the application.  When writing your
+     own application, the package name must be changed from "com.example.*"
+     to come from a domain that you own or have control over. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.injector">
+    <application android:label="My Setting Activity!">
+        <activity android:name="MySettingActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
+        <service android:name="com.example.android.injector.MyInjectorService" >
+            <intent-filter>
+                <action android:name="android.location.SettingInjectorService" />
+            </intent-filter>
+
+            <meta-data
+                android:name="android.location.SettingInjectorService"
+                android:resource="@xml/my_injected_location_setting" />
+        </service>
+
+        <service android:name="com.example.android.injector.DisabledInjectorService" >
+            <intent-filter>
+                <action android:name="android.location.SettingInjectorService" />
+            </intent-filter>
+
+            <meta-data
+                android:name="android.location.SettingInjectorService"
+                android:resource="@xml/disabled_injected_location_setting" />
+        </service>
+
+        <service android:name="com.example.android.injector.FailingInjectorService" >
+            <intent-filter>
+                <action android:name="android.location.SettingInjectorService" />
+            </intent-filter>
+
+            <meta-data
+                android:name="android.location.SettingInjectorService"
+                android:resource="@xml/failing_injected_location_setting" />
+        </service>
+
+        <service android:name="com.example.android.injector.SlowInjectorService" >
+            <intent-filter>
+                <action android:name="android.location.SettingInjectorService" />
+            </intent-filter>
+
+            <meta-data
+                android:name="android.location.SettingInjectorService"
+                android:resource="@xml/slow_injected_location_setting" />
+        </service>
+
+        <service android:name="com.example.android.injector.UpdatingInjectorService" >
+            <intent-filter>
+                <action android:name="android.location.SettingInjectorService" />
+            </intent-filter>
+
+            <meta-data
+                android:name="android.location.SettingInjectorService"
+                android:resource="@xml/updating_injected_location_setting" />
+        </service>
+
+    </application>
+</manifest>
diff --git a/apps/SettingInjectorSample/res/drawable-hdpi/ic_launcher.png b/apps/SettingInjectorSample/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..c1b44cc
--- /dev/null
+++ b/apps/SettingInjectorSample/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/apps/SettingInjectorSample/res/drawable-hdpi/ic_my_injected_setting.png b/apps/SettingInjectorSample/res/drawable-hdpi/ic_my_injected_setting.png
new file mode 100644
index 0000000..053b527
--- /dev/null
+++ b/apps/SettingInjectorSample/res/drawable-hdpi/ic_my_injected_setting.png
Binary files differ
diff --git a/apps/SettingInjectorSample/res/drawable-mdpi/ic_launcher.png b/apps/SettingInjectorSample/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a1bf709
--- /dev/null
+++ b/apps/SettingInjectorSample/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/apps/SettingInjectorSample/res/drawable-mdpi/ic_my_injected_setting.png b/apps/SettingInjectorSample/res/drawable-mdpi/ic_my_injected_setting.png
new file mode 100644
index 0000000..7fe282f
--- /dev/null
+++ b/apps/SettingInjectorSample/res/drawable-mdpi/ic_my_injected_setting.png
Binary files differ
diff --git a/apps/SettingInjectorSample/res/drawable-xhdpi/ic_launcher.png b/apps/SettingInjectorSample/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..a1bf709
--- /dev/null
+++ b/apps/SettingInjectorSample/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/apps/SettingInjectorSample/res/drawable-xhdpi/ic_my_injected_setting.png b/apps/SettingInjectorSample/res/drawable-xhdpi/ic_my_injected_setting.png
new file mode 100644
index 0000000..a625b3a
--- /dev/null
+++ b/apps/SettingInjectorSample/res/drawable-xhdpi/ic_my_injected_setting.png
Binary files differ
diff --git a/apps/SettingInjectorSample/res/drawable-xxhdpi/ic_launcher.png b/apps/SettingInjectorSample/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b7df51b
--- /dev/null
+++ b/apps/SettingInjectorSample/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/apps/SettingInjectorSample/res/layout/my_setting_activity.xml b/apps/SettingInjectorSample/res/layout/my_setting_activity.xml
new file mode 100644
index 0000000..4703a35
--- /dev/null
+++ b/apps/SettingInjectorSample/res/layout/my_setting_activity.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<EditText xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:textSize="18sp"
+    android:autoText="true"
+    android:capitalize="sentences"
+    android:text="@string/my_setting_activity_text" />
+
diff --git a/apps/SettingInjectorSample/res/values/strings.xml b/apps/SettingInjectorSample/res/values/strings.xml
new file mode 100644
index 0000000..6657499
--- /dev/null
+++ b/apps/SettingInjectorSample/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+
+    <string name="my_setting_activity_text">Hello, World!</string>
+
+    <string name="my_injected_setting_label">Injected setting</string>
+    <string name="disabled_setting_label">Disabled injected setting</string>
+    <string name="failing_setting_label">Failing injected setting</string>
+    <string name="slow_setting_label">Slow injected setting</string>
+    <string name="updating_setting_label">Updating injected setting</string>
+
+</resources>
diff --git a/apps/SettingInjectorSample/res/xml/disabled_injected_location_setting.xml b/apps/SettingInjectorSample/res/xml/disabled_injected_location_setting.xml
new file mode 100644
index 0000000..86e7d2d
--- /dev/null
+++ b/apps/SettingInjectorSample/res/xml/disabled_injected_location_setting.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<injected-location-setting xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/disabled_setting_label"
+    android:icon="@drawable/ic_launcher"
+    android:settingsActivity="com.example.android.injector.MySettingActivity"
+/>
diff --git a/apps/SettingInjectorSample/res/xml/failing_injected_location_setting.xml b/apps/SettingInjectorSample/res/xml/failing_injected_location_setting.xml
new file mode 100644
index 0000000..ae68d9d
--- /dev/null
+++ b/apps/SettingInjectorSample/res/xml/failing_injected_location_setting.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<injected-location-setting xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/failing_setting_label"
+    android:icon="@drawable/ic_launcher"
+    android:settingsActivity="com.example.android.injector.MySettingActivity"
+/>
diff --git a/apps/SettingInjectorSample/res/xml/my_injected_location_setting.xml b/apps/SettingInjectorSample/res/xml/my_injected_location_setting.xml
new file mode 100644
index 0000000..716cf39
--- /dev/null
+++ b/apps/SettingInjectorSample/res/xml/my_injected_location_setting.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<injected-location-setting xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/my_injected_setting_label"
+    android:icon="@drawable/ic_my_injected_setting"
+    android:settingsActivity="com.example.android.injector.MySettingActivity"
+/>
diff --git a/apps/SettingInjectorSample/res/xml/slow_injected_location_setting.xml b/apps/SettingInjectorSample/res/xml/slow_injected_location_setting.xml
new file mode 100644
index 0000000..f902cf3
--- /dev/null
+++ b/apps/SettingInjectorSample/res/xml/slow_injected_location_setting.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<injected-location-setting xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/slow_setting_label"
+    android:icon="@drawable/ic_launcher"
+    android:settingsActivity="com.example.android.injector.MySettingActivity"
+/>
diff --git a/apps/SettingInjectorSample/res/xml/updating_injected_location_setting.xml b/apps/SettingInjectorSample/res/xml/updating_injected_location_setting.xml
new file mode 100644
index 0000000..0e16125
--- /dev/null
+++ b/apps/SettingInjectorSample/res/xml/updating_injected_location_setting.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<injected-location-setting xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/updating_setting_label"
+    android:icon="@drawable/ic_launcher"
+    android:settingsActivity="com.example.android.injector.MySettingActivity"
+/>
diff --git a/apps/SettingInjectorSample/src/com/example/android/injector/DisabledInjectorService.java b/apps/SettingInjectorSample/src/com/example/android/injector/DisabledInjectorService.java
new file mode 100644
index 0000000..c122639
--- /dev/null
+++ b/apps/SettingInjectorSample/src/com/example/android/injector/DisabledInjectorService.java
@@ -0,0 +1,48 @@
+/*
+ * 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.injector;
+
+import android.location.SettingInjectorService;
+import android.util.Log;
+
+/**
+ * Receiver that returns the status disabled for an injected setting.
+ */
+public class DisabledInjectorService extends SettingInjectorService {
+
+    private static final String TAG = "DisabledInjectorService";
+
+    public DisabledInjectorService() {
+        super(TAG);
+    }
+
+    @Override
+    protected String onGetSummary() {
+        try {
+            // Simulate a delay while reading the setting from disk
+            Thread.sleep(500);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "", e);
+        }
+        return null;
+    }
+
+    @Override
+    protected boolean onGetEnabled() {
+        return false;
+    }
+}
diff --git a/apps/SettingInjectorSample/src/com/example/android/injector/FailingInjectorService.java b/apps/SettingInjectorSample/src/com/example/android/injector/FailingInjectorService.java
new file mode 100644
index 0000000..bdd15eb
--- /dev/null
+++ b/apps/SettingInjectorSample/src/com/example/android/injector/FailingInjectorService.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.injector;
+
+import android.location.SettingInjectorService;
+import android.util.Log;
+
+/**
+ * Receiver that returns the status of the injected setting.
+ */
+public class FailingInjectorService extends SettingInjectorService {
+
+    private static final String TAG = "FailingInjectorService";
+
+    /**
+     * Whether to actually throw an exception here. Pretty disruptive when true, because it causes
+     * a "Unfortunately, My Setting Activity! has stopped" dialog to appear and also blocks the
+     * update of other settings from this app. So only set true when need to test the handling
+     * of the exception.
+     */
+    private static final boolean ACTUALLY_THROW = false;
+
+    public FailingInjectorService() {
+        super(TAG);
+    }
+
+    @Override
+    protected String onGetSummary() {
+        try {
+            // Simulate a delay while reading the setting from disk
+            Thread.sleep(100);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "", e);
+        }
+
+        if (ACTUALLY_THROW) {
+            throw new RuntimeException("Simulated failure reading setting");
+        }
+        return "Decided not to throw exception after all";
+    }
+
+    @Override
+    protected boolean onGetEnabled() {
+        return false;
+    }
+}
diff --git a/apps/SettingInjectorSample/src/com/example/android/injector/MyInjectorService.java b/apps/SettingInjectorSample/src/com/example/android/injector/MyInjectorService.java
new file mode 100644
index 0000000..8797d69
--- /dev/null
+++ b/apps/SettingInjectorSample/src/com/example/android/injector/MyInjectorService.java
@@ -0,0 +1,48 @@
+/*
+ * 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.injector;
+
+import android.location.SettingInjectorService;
+import android.util.Log;
+
+/**
+ * Receiver that returns the status of the injected setting.
+ */
+public class MyInjectorService extends SettingInjectorService {
+
+    private static final String TAG = "MyInjectorService";
+
+    public MyInjectorService() {
+        super(TAG);
+    }
+
+    @Override
+    protected String onGetSummary() {
+        try {
+            // Simulate a delay while reading the setting from disk
+            Thread.sleep(500);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "", e);
+        }
+        return "Example status value";
+    }
+
+    @Override
+    protected boolean onGetEnabled() {
+        return true;
+    }
+}
diff --git a/apps/SettingInjectorSample/src/com/example/android/injector/MySettingActivity.java b/apps/SettingInjectorSample/src/com/example/android/injector/MySettingActivity.java
new file mode 100644
index 0000000..1e5e048
--- /dev/null
+++ b/apps/SettingInjectorSample/src/com/example/android/injector/MySettingActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.injector;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+
+/**
+ * A minimal "Hello, World!" application.
+ */
+public class MySettingActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set the layout for this activity.  You can find it
+        // in res/layout/my_setting_activity.xml
+        View view = getLayoutInflater().inflate(R.layout.my_setting_activity, null);
+        setContentView(view);
+    }
+}
+
diff --git a/apps/SettingInjectorSample/src/com/example/android/injector/SlowInjectorService.java b/apps/SettingInjectorSample/src/com/example/android/injector/SlowInjectorService.java
new file mode 100644
index 0000000..7cb32c9
--- /dev/null
+++ b/apps/SettingInjectorSample/src/com/example/android/injector/SlowInjectorService.java
@@ -0,0 +1,48 @@
+/*
+ * 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.injector;
+
+import android.location.SettingInjectorService;
+import android.util.Log;
+
+/**
+ * Receiver that returns the status of the injected setting.
+ */
+public class SlowInjectorService extends SettingInjectorService {
+
+    private static final String TAG = "SlowInjectorService";
+
+    public SlowInjectorService() {
+        super(TAG);
+    }
+
+    @Override
+    protected String onGetSummary() {
+        try {
+            // Simulate a delay while reading the setting from disk
+            Thread.sleep(5000);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "", e);
+        }
+        return "Dang that took a long time!";
+    }
+
+    @Override
+    protected boolean onGetEnabled() {
+        return true;
+    }
+}
diff --git a/apps/SettingInjectorSample/src/com/example/android/injector/UpdatingInjectorService.java b/apps/SettingInjectorSample/src/com/example/android/injector/UpdatingInjectorService.java
new file mode 100644
index 0000000..3db619a
--- /dev/null
+++ b/apps/SettingInjectorSample/src/com/example/android/injector/UpdatingInjectorService.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.injector;
+
+import android.content.Intent;
+import android.location.SettingInjectorService;
+import android.util.Log;
+
+/**
+ * Receiver that returns a constantly-updating status for an injected setting.
+ */
+public class UpdatingInjectorService extends SettingInjectorService {
+
+    private static final String TAG = "UpdatingInjectorService";
+
+    public UpdatingInjectorService() {
+        super(TAG);
+    }
+
+    @Override
+    protected String onGetSummary() {
+        // Every time it asks for our status, we tell it the setting has just changed. This will
+        // test the handling of races where we're getting many UPDATE_INTENT broadcasts in a short
+        // period of time
+        Intent intent = new Intent(ACTION_INJECTED_SETTING_CHANGED);
+        sendBroadcast(intent);
+        Log.d(TAG, "Broadcasting: " + intent);
+        return String.valueOf(System.currentTimeMillis());
+    }
+
+    @Override
+    protected boolean onGetEnabled() {
+        return true;
+    }
+}
diff --git a/build/sdk.atree b/build/sdk.atree
index ed1fd36..b2359ef 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -82,25 +82,27 @@
 external/clang/LICENSE.TXT                    build-tools/${PLATFORM_NAME}/renderscript/clang-include/LICENSE.TXT
 
 prebuilts/sdk/renderscript/lib/javalib.jar            build-tools/${PLATFORM_NAME}/renderscript/lib/renderscript-v8.jar
-prebuilts/sdk/renderscript/lib/arm/libclcore.bc       build-tools/${PLATFORM_NAME}/renderscript/lib/libclcore.bc
 
 prebuilts/sdk/renderscript/lib/arm/libc.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/armeabi-v7a/libc.so
 prebuilts/sdk/renderscript/lib/arm/libm.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/armeabi-v7a/libm.so
 prebuilts/sdk/renderscript/lib/arm/libcompiler_rt.a   build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/armeabi-v7a/libcompiler_rt.a
 prebuilts/sdk/renderscript/lib/arm/libRSSupport.so    build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/armeabi-v7a/libRSSupport.so
 prebuilts/sdk/renderscript/lib/arm/librsjni.so        build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/armeabi-v7a/librsjni.so
+prebuilts/sdk/renderscript/lib/arm/libclcore.bc       build-tools/${PLATFORM_NAME}/renderscript/lib/bc/armeabi-v7a/libclcore.bc
 
 prebuilts/sdk/renderscript/lib/mips/libc.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/mips/libc.so
 prebuilts/sdk/renderscript/lib/mips/libm.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/mips/libm.so
 prebuilts/sdk/renderscript/lib/mips/libcompiler_rt.a   build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/mips/libcompiler_rt.a
 prebuilts/sdk/renderscript/lib/mips/libRSSupport.so    build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/mips/libRSSupport.so
 prebuilts/sdk/renderscript/lib/mips/librsjni.so        build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/mips/librsjni.so
+prebuilts/sdk/renderscript/lib/mips/libclcore.bc       build-tools/${PLATFORM_NAME}/renderscript/lib/bc/mips/libclcore.bc
 
 prebuilts/sdk/renderscript/lib/x86/libc.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/x86/libc.so
 prebuilts/sdk/renderscript/lib/x86/libm.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/x86/libm.so
 prebuilts/sdk/renderscript/lib/x86/libcompiler_rt.a   build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/x86/libcompiler_rt.a
 prebuilts/sdk/renderscript/lib/x86/libRSSupport.so    build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/x86/libRSSupport.so
 prebuilts/sdk/renderscript/lib/x86/librsjni.so        build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/x86/librsjni.so
+prebuilts/sdk/renderscript/lib/x86/libclcore.bc       build-tools/${PLATFORM_NAME}/renderscript/lib/bc/x86/libclcore.bc
 
 
 
@@ -217,14 +219,47 @@
 # Note: Some samples reference a shared "common" directory. In the future
 # this will be copied in automatically via a templating system. For now,
 # we need to copy it in here as needed.
-developers/samples/android/connectivity        samples/${PLATFORM_NAME}/connectivity
-developers/samples/android/common              samples/${PLATFORM_NAME}/connectivity/sync/BasicSyncAdapter/BasicSyncAdapter/src/main/java/com/example/android/common
-developers/samples/android/content             samples/${PLATFORM_NAME}/content
-developers/samples/android/input               samples/${PLATFORM_NAME}/input
-developers/samples/android/media               samples/${PLATFORM_NAME}/media
-developers/samples/android/security            samples/${PLATFORM_NAME}/security
-developers/samples/android/testing             samples/${PLATFORM_NAME}/testing
-developers/samples/android/ui                  samples/${PLATFORM_NAME}/ui
+developers/build/prebuilts/gradle/BasicAndroidKeyStore/                      samples/${PLATFORM_NAME}/security/BasicAndroidKeyStore
+developers/build/prebuilts/gradle/BasicSyncAdapter/                          samples/${PLATFORM_NAME}/connectivity/BasicSyncAdapter
+developers/build/prebuilts/gradle/NetworkConnect/                            samples/${PLATFORM_NAME}/connectivity/NetworkConnect
+developers/build/prebuilts/gradle/BasicNetworking/                           samples/${PLATFORM_NAME}/connectivity/BasicNetworking
+developers/build/prebuilts/gradle/BluetoothLeGatt/                           samples/${PLATFORM_NAME}/connectivity/BluetoothLeGatt
+developers/build/prebuilts/gradle/AppRestrictions/                           samples/${PLATFORM_NAME}/content/AppRestrictions
+developers/build/prebuilts/gradle/BasicContactables/                         samples/${PLATFORM_NAME}/content/BasicContactables
+developers/build/prebuilts/gradle/StorageClient/                             samples/${PLATFORM_NAME}/content/StorageClient
+developers/build/prebuilts/gradle/StorageProvider/                           samples/${PLATFORM_NAME}/content/StorageProvider
+developers/build/prebuilts/gradle/BasicGestureDetect/                        samples/${PLATFORM_NAME}/input/BasicGestureDetect
+developers/build/prebuilts/gradle/BasicMultitouch/                           samples/${PLATFORM_NAME}/input/BasicMultitouch
+developers/build/prebuilts/gradle/ActivityInstrumentation/                   samples/${PLATFORM_NAME}/testing/ActivityInstrumentation
+developers/build/prebuilts/gradle/MediaRecorder/                             samples/${PLATFORM_NAME}/media/MediaRecorder
+developers/build/prebuilts/gradle/BasicMediaRouter/                          samples/${PLATFORM_NAME}/media/BasicMediaRouter
+developers/build/prebuilts/gradle/BasicMediaDecoder/                         samples/${PLATFORM_NAME}/media/BasicMediaDecoder
+developers/build/prebuilts/gradle/BorderlessButtons/                         samples/${PLATFORM_NAME}/ui/BorderlessButtons
+developers/build/prebuilts/gradle/BasicAccessibility/                        samples/${PLATFORM_NAME}/ui/BasicAccessibility
+developers/build/prebuilts/gradle/CustomChoiceList/                          samples/${PLATFORM_NAME}/ui/CustomChoiceList
+developers/build/prebuilts/gradle/TextSwitcher/                              samples/${PLATFORM_NAME}/ui/TextSwitcher
+developers/build/prebuilts/gradle/HorizontalPaging/                          samples/${PLATFORM_NAME}/ui/HorizontalPaging
+developers/build/prebuilts/gradle/ActionBarCompat-Styled/                    samples/${PLATFORM_NAME}/ui/ActionBarCompat-Styled
+developers/build/prebuilts/gradle/ActionBarCompat-ListPopupMenu/             samples/${PLATFORM_NAME}/ui/ActionBarCompat-ListPopupMenu
+developers/build/prebuilts/gradle/ActionBarCompat-ShareActionProvider/       samples/${PLATFORM_NAME}/ui/ActionBarCompat-ShareActionProvider
+developers/build/prebuilts/gradle/ActionBarCompat-Basic/                     samples/${PLATFORM_NAME}/ui/ActionBarCompat-Basic
+developers/build/prebuilts/gradle/BasicNotifications/                        samples/${PLATFORM_NAME}/ui/BasicNotifications
+developers/build/prebuilts/gradle/CustomNotifications/                       samples/${PLATFORM_NAME}/ui/CustomNotifications
+developers/build/prebuilts/gradle/DoneBar/                                   samples/${PLATFORM_NAME}/ui/DoneBar
+developers/build/prebuilts/gradle/BasicImmersiveMode/                        samples/${PLATFORM_NAME}/ui/BasicImmersiveMode
+developers/build/prebuilts/gradle/AdvancedImmersiveMode/                     samples/${PLATFORM_NAME}/ui/AdvancedImmersiveMode
+developers/build/prebuilts/gradle/ImmersiveMode/                             samples/${PLATFORM_NAME}/ui/ImmersiveMode
+developers/build/prebuilts/gradle/RepeatingAlarm/                            samples/${PLATFORM_NAME}/background/RepeatingAlarm
+developers/build/prebuilts/gradle/TextLinkify/                               samples/${PLATFORM_NAME}/ui/TextLinkify
+developers/build/prebuilts/gradle/BasicRenderScript                          samples/${PLATFORM_NAME}/renderscript/BasicRenderScript
+developers/build/prebuilts/gradle/RenderScriptIntrinsic                      samples/${PLATFORM_NAME}/renderscript/RenderScriptIntrinsic
+developers/build/prebuilts/gradle/SlidingTabsBasic                           samples/${PLATFORM_NAME}/ui/SlidingTabsBasic
+developers/build/prebuilts/gradle/SlidingTabsColors                          samples/${PLATFORM_NAME}/ui/SlidingTabsColors
+developers/build/prebuilts/gradle/CardEmulation                              samples/${PLATFORM_NAME}/connectivity/CardEmulation
+developers/build/prebuilts/gradle/CardReader                                 samples/${PLATFORM_NAME}/connectivity/CardReader
+developers/build/prebuilts/gradle/BatchStepSensor                            samples/${PLATFORM_NAME}/sensors/BatchStepSensor
+
+
 
 # Old sample tree
 development/samples/AccelerometerPlay          samples/${PLATFORM_NAME}/legacy/AccelerometerPlay
diff --git a/build/tools/mk_sdk_repo_xml.sh b/build/tools/mk_sdk_repo_xml.sh
index c807a56..0bb0e51 100755
--- a/build/tools/mk_sdk_repo_xml.sh
+++ b/build/tools/mk_sdk_repo_xml.sh
@@ -139,6 +139,10 @@
 # Starting with XSD repo-7 and addon-5, some revision elements are no longer just
 # integers. Instead they are in major.minor.micro.preview format. This defines
 # which elements. This depends on the XSD root element and the XSD version.
+#
+# Note: addon extra revision can't take a preview number. We don't enforce
+# this in this script. Instead schema validation will fail if the extra
+# source.property declares an RC and it gets inserted in the addon.xml here.
 
 if [[ "$ROOT" == "sdk-repository" && "$XSD_VERSION" -ge 7 ]] ||
    [[ "$ROOT" == "sdk-addon"      && "$XSD_VERSION" -ge 5 ]]; then
@@ -146,6 +150,7 @@
   tool          revision
   build-tool    revision
   platform-tool revision
+  extra         revision
   @             min-tools-rev
   @             min-platform-tools-rev
 )
@@ -177,7 +182,7 @@
 }
 
 # Parses and print a full revision in the form "1.2.3 rc4".
-# Note that the format requires to have a # space before the
+# Note that the format requires to have 1 space before the
 # optional "rc" (e.g. '1 rc4', not '1rc4') and no space after
 # the rc (so not '1 rc 4' either)
 function write_full_revision() {
diff --git a/build/tools/sdk_clean.sh b/build/tools/sdk_clean.sh
index 467d560..a80e6e9 100755
--- a/build/tools/sdk_clean.sh
+++ b/build/tools/sdk_clean.sh
@@ -1,8 +1,6 @@
 #!/bin/bash
 #
-# This script processes a set of files given as arguments as sample code to be  released
-# in the SDK.
-#
+# This script cleans up a set of files given as arguments for release in the SDK
 # Note that these files are modified in-place.
 #
 
@@ -32,7 +30,7 @@
 fi
 
 #
-# Fix up the line endings of all text files
+# Fix up the line endings of all text files. This also removes executable permissions.
 #
 if [ $HOST_OS = windows ] ; then
     ENDING_TYPE=dos
@@ -40,9 +38,8 @@
     ENDING_TYPE=unix
 fi
 find $DIR -name "*.aidl" -o -name "*.css" -o -name "*.html" -o -name "*.java" \
-                     -o -name "*.js" -o -name "*.prop" -o -name "*.py" \
-                     -o -name "*.template" -o -name "*.txt" -o -name "*.windows" \
-                     -o -name "*.xml" \
+                     -o -name "*.js" -o -name "*.prop" -o -name "*.template" \
+                     -o -name "*.txt" -o -name "*.windows" -o -name "*.xml" \
         | xargs $HOST_OUT_EXECUTABLES/line_endings $ENDING_TYPE
 
 
diff --git a/build/windows_sdk_whitelist.mk b/build/windows_sdk_whitelist.mk
index 8d6ac8f..f2f4d8e 100644
--- a/build/windows_sdk_whitelist.mk
+++ b/build/windows_sdk_whitelist.mk
@@ -54,6 +54,7 @@
 	system/core/liblog \
 	system/core/libsparse \
 	system/core/libzipfile \
+	system/core/libutils \
 	system/extras/ext4_utils
 
 # -----
diff --git a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java
index 89679a1..e41a069 100644
--- a/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java
+++ b/cmds/monkey/src/com/android/commands/monkey/MonkeySourceNetworkViews.java
@@ -139,7 +139,8 @@
         int viewId = Integer.parseInt(viewString);
         int connectionId = sUiTestAutomationBridge.getConnectionId();
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
-        return client.findAccessibilityNodeInfoByAccessibilityId(connectionId, windowId, viewId, 0);
+        return client.findAccessibilityNodeInfoByAccessibilityId(connectionId, windowId, viewId,
+                false, 0);
     }
 
     private static AccessibilityNodeInfo getNodeByViewId(String viewId) throws MonkeyViewException {
diff --git a/host/windows/usb/android_winusb.inf b/host/windows/usb/android_winusb.inf
index f26a75c..8dbfe09 100755
--- a/host/windows/usb/android_winusb.inf
+++ b/host/windows/usb/android_winusb.inf
@@ -6,7 +6,7 @@
 Class               = AndroidUsbDeviceClass

 ClassGuid           = {3F966BD9-FA04-4ec5-991C-D326973B5128}

 Provider            = %ProviderName%

-DriverVer           = 08/27/2012,7.0.0000.00001

+DriverVer           = 07/09/2013,8.0.0000.00000

 CatalogFile.NTx86   = androidwinusb86.cat

 CatalogFile.NTamd64 = androidwinusba64.cat

 

@@ -38,8 +38,6 @@
 

 ;Google Nexus 7

 %SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4E40

-%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4E41

-%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4E42

 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4E42&MI_01

 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4E44&MI_01

 

@@ -49,12 +47,8 @@
 

 ;Google Nexus (generic)

 %SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4EE0

-%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE1

-%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE2

 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE2&MI_01

-%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE3

-%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE4&MI_01

-%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE5

+%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE4&MI_02

 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE6&MI_01

 

 

@@ -74,8 +68,6 @@
 

 ;Google Nexus 7

 %SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4E40

-%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4E41

-%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4E42

 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4E42&MI_01

 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4E44&MI_01

 

@@ -85,12 +77,8 @@
 

 ;Google Nexus (generic)

 %SingleBootLoaderInterface% = USB_Install, USB\VID_18D1&PID_4EE0

-%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE1

-%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE2

 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE2&MI_01

-%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE3

-%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE4&MI_01

-%SingleAdbInterface%        = USB_Install, USB\VID_18D1&PID_4EE5

+%CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE4&MI_02

 %CompositeAdbInterface%     = USB_Install, USB\VID_18D1&PID_4EE6&MI_01

 

 [USB_Install]

diff --git a/ide/eclipse/.classpath b/ide/eclipse/.classpath
index bfbd04e..dda0606 100644
--- a/ide/eclipse/.classpath
+++ b/ide/eclipse/.classpath
@@ -16,6 +16,7 @@
 	<classpathentry kind="src" path="packages/apps/Gallery2/src_pd"/>
 	<classpathentry kind="src" path="packages/apps/Gallery2/gallerycommon/src"/>
 	<classpathentry kind="src" path="packages/apps/HTMLViewer/src"/>
+	<classpathentry kind="src" path="packages/apps/InCallUI/src"/>
 	<classpathentry kind="src" path="packages/apps/Launcher2/src"/>
 	<classpathentry kind="src" path="packages/apps/Mms/src"/>
 	<classpathentry kind="src" path="packages/apps/Nfc/src"/>
@@ -38,6 +39,8 @@
 	<classpathentry kind="src" path="packages/screensavers/Basic/src"/>
 	<classpathentry kind="src" path="packages/screensavers/PhotoTable/src"/>
 	<classpathentry kind="src" path="packages/screensavers/WebView/src"/>
+	<classpathentry kind="src" path="packages/services/Telephony/src"/>
+	<classpathentry kind="src" path="packages/services/Telephony/common/src"/>
 	<classpathentry kind="src" path="frameworks/base/cmds/am/src"/>
 	<classpathentry kind="src" path="frameworks/base/cmds/input/src"/>
 	<classpathentry kind="src" path="frameworks/base/cmds/pm/src"/>
@@ -50,6 +53,7 @@
 	<classpathentry kind="src" path="frameworks/base/location/java"/>
 	<classpathentry kind="src" path="frameworks/base/location/lib/java"/>
 	<classpathentry kind="src" path="frameworks/base/media/java"/>
+	<classpathentry kind="src" path="frameworks/base/media/tests/MediaFrameworkTest/src"/>
 	<classpathentry kind="src" path="frameworks/base/media/mca/effect/java"/>
 	<classpathentry kind="src" path="frameworks/base/media/mca/filterfw/java"/>
 	<classpathentry kind="src" path="frameworks/base/media/mca/filterpacks/java"/>
@@ -66,6 +70,7 @@
 	<classpathentry kind="src" path="frameworks/base/test-runner/src"/>
 	<classpathentry kind="src" path="frameworks/base/wifi/java"/>
 	<classpathentry kind="src" path="frameworks/ex/carousel/java"/>
+	<classpathentry kind="src" path="frameworks/ex/camera2/public/src"/>
 	<classpathentry kind="src" path="frameworks/ex/chips/src"/>
 	<classpathentry kind="src" path="frameworks/ex/common/java"/>
 	<classpathentry kind="src" path="frameworks/ex/photoviewer/src"/>
@@ -111,21 +116,25 @@
 	<classpathentry kind="src" path="out/target/common/obj/APPS/SystemUI_intermediates/src/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/android-common-carousel_intermediates/src/renderscript/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/com.android.emailcommon_intermediates/src/src"/>
-	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java"/>
-	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/keystore/java"/>
-	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/location/java"/>
-	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java"/>
-	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java"/>
-	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/wifi/java"/>
+	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java"/>
+	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/keystore/java"/>
+	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/location/java"/>
+	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java"/>
+	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/telephony/java"/>
+	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/wifi/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/NfcLogTags_intermediates/src/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/services_intermediates/src"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/telephony-common_intermediates/src/src/java"/>
 	<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/voip-common_intermediates/src/src/java"/>
 	<classpathentry kind="src" path="out/target/common/R"/>
+	<classpathentry kind="src" path="pdk/apps/TestingCamera2/src"/>
 	<classpathentry kind="src" path="external/apache-http/src"/>
 	<classpathentry kind="src" path="external/bouncycastle/bcprov/src/main/java"/>
 	<classpathentry kind="src" path="external/guava/guava/src"/>
+	<classpathentry kind="src" path="external/hamcrest/src"/>
+	<classpathentry kind="src" path="external/junit/src"/>
 	<classpathentry kind="src" path="external/libphonenumber/java/src"/>
+	<classpathentry kind="src" path="external/mockito/src"/>
 	<classpathentry kind="src" path="external/mp4parser/isoparser/src/main/java"/>
 	<classpathentry kind="src" path="external/nist-sip/java"/>
 	<classpathentry kind="src" path="external/tagsoup/src"/>
diff --git a/ide/eclipse/README.importing-to-eclipse.txt b/ide/eclipse/README.importing-to-eclipse.txt
index dffa0ab..c98bf52 100644
--- a/ide/eclipse/README.importing-to-eclipse.txt
+++ b/ide/eclipse/README.importing-to-eclipse.txt
@@ -1,6 +1,33 @@
+(Java)
+
 To import the formatter, go to the preferences, section Java > Code Style >
 formatter, then click on import and choose
 development/ide/eclipse/android-formatting.xml
 
 To import the import order, to go into Java > Code Style > Organize Import,
 then click on import and choose development/ide/eclipse/android.importorder
+
+(C++)
+
+To import the include paths, go to Project > Properties > C/C++ General >
+Paths and Symbols, then click on "Includes" and then click on "Import Settings".
+Choose development/ide/eclipse/android-include-paths.xml and hit Finish.
+You will need to re-index for the changes to get picked up (right click project
+in Package Explorer, then Index > Rebuild).
+
+To import the symbols, go to Project > Properties > C/C++ General >
+Paths and Symbols, then click on "Symbols" and then click on "Import Settings".
+Choose development/ide/eclipse/android-symbols.xml and hit Finish.
+You will need to re-index for the changes to get picked up (right click project
+in Package Explorer, then Index > Rebuild).
+
+In addition, you will need to add some include files (no way to import this
+from an XML file) by hand. Go to Project > Properties > C/C++ General >
+Paths and Symbols, then click on "Include Files" and click on "Add". Check
+"Add to all configurations" and "Add to all languages". Repeat for these files:
+
+    ${ProjDirPath}/build/core/combo/include/arch/linux-arm/AndroidConfig.h
+
+If you are having trouble seeing the "Include Files" tab, you will need to
+enable it in the global preference panel under "C/C++" /
+"Property Pages Settings".
diff --git a/ide/eclipse/android-include-paths.xml b/ide/eclipse/android-include-paths.xml
index be188bd..4487fa4 100644
--- a/ide/eclipse/android-include-paths.xml
+++ b/ide/eclipse/android-include-paths.xml
@@ -31,6 +31,7 @@
 <includepath>${ProjDirPath}/system/core/include/arch/linux-arm</includepath>
 <includepath>${ProjDirPath}/dalvik/libnativehelper/include</includepath>
 <includepath>${ProjDirPath}/dalvik/libnativehelper/include/nativehelper</includepath>
+<includepath>${ProjDirPath}/system/media/camera/include</includepath>
 
 </language>
 <language name="GNU C++">
@@ -60,6 +61,7 @@
 <includepath>${ProjDirPath}/system/core/include/arch/linux-arm</includepath>
 <includepath>${ProjDirPath}/dalvik/libnativehelper/include</includepath>
 <includepath>${ProjDirPath}/dalvik/libnativehelper/include/nativehelper</includepath>
+<includepath>${ProjDirPath}/system/media/camera/include</includepath>
 
 </language>
 <language name="GNU C">
@@ -89,6 +91,7 @@
 <includepath>${ProjDirPath}/system/core/include/arch/linux-arm</includepath>
 <includepath>${ProjDirPath}/dalvik/libnativehelper/include</includepath>
 <includepath>${ProjDirPath}/dalvik/libnativehelper/include/nativehelper</includepath>
+<includepath>${ProjDirPath}/system/media/camera/include</includepath>
 
 </language>
 </section>
diff --git a/ide/intellij/codestyles/AndroidStyle.xml b/ide/intellij/codestyles/AndroidStyle.xml
index cd6beb4..672c4e5 100644
--- a/ide/intellij/codestyles/AndroidStyle.xml
+++ b/ide/intellij/codestyles/AndroidStyle.xml
@@ -9,40 +9,49 @@
       <option name="SMART_TABS" value="false" />
       <option name="LABEL_INDENT_SIZE" value="0" />
       <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+      <option name="USE_RELATIVE_INDENTS" value="false" />
     </value>
   </option>
-  <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
-  <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
-  <option name="ALIGN_MULTILINE_FOR" value="false" />
-  <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
-  <option name="BLANK_LINES_AROUND_FIELD" value="1" />
-  <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
   <option name="FIELD_NAME_PREFIX" value="m" />
   <option name="STATIC_FIELD_NAME_PREFIX" value="m" />
-  <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
-  <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
+  <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
+  <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
   <option name="IMPORT_LAYOUT_TABLE">
     <value>
-      <package name="com.google" withSubpackages="true" />
+      <package name="com.google" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="com" withSubpackages="true" />
+      <package name="com" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="junit" withSubpackages="true" />
+      <package name="junit" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="net" withSubpackages="true" />
+      <package name="net" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="org" withSubpackages="true" />
+      <package name="org" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="android" withSubpackages="true" />
+      <package name="android" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="java" withSubpackages="true" />
+      <package name="java" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="javax" withSubpackages="true" />
+      <package name="javax" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="" withSubpackages="true" />
+      <package name="" withSubpackages="true" static="false" />
+      <emptyLine />
+      <package name="" withSubpackages="true" static="true" />
     </value>
   </option>
   <option name="RIGHT_MARGIN" value="100" />
+  <option name="JD_P_AT_EMPTY_LINES" value="false" />
+  <option name="JD_DO_NOT_WRAP_ONE_LINE_COMMENTS" value="true" />
+  <option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
+  <option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
+  <option name="JD_KEEP_EMPTY_RETURN" value="false" />
+  <option name="JD_PRESERVE_LINE_FEEDS" value="true" />
+  <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
+  <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+  <option name="BLANK_LINES_AROUND_FIELD" value="1" />
+  <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
+  <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+  <option name="ALIGN_MULTILINE_FOR" value="false" />
   <option name="CALL_PARAMETERS_WRAP" value="1" />
   <option name="METHOD_PARAMETERS_WRAP" value="1" />
   <option name="EXTENDS_LIST_WRAP" value="1" />
@@ -63,9 +72,104 @@
   <option name="DOWHILE_BRACE_FORCE" value="3" />
   <option name="WHILE_BRACE_FORCE" value="3" />
   <option name="FOR_BRACE_FORCE" value="3" />
-  <option name="JD_P_AT_EMPTY_LINES" value="false" />
-  <option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
-  <option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
-  <option name="JD_KEEP_EMPTY_RETURN" value="false" />
+  <ADDITIONAL_INDENT_OPTIONS fileType="css">
+    <option name="INDENT_SIZE" value="4" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="java">
+    <option name="INDENT_SIZE" value="4" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="8" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="js">
+    <option name="INDENT_SIZE" value="4" />
+    <option name="CONTINUATION_INDENT_SIZE" value="4" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="jsp">
+    <option name="INDENT_SIZE" value="4" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="sql">
+    <option name="INDENT_SIZE" value="2" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="xml">
+    <option name="INDENT_SIZE" value="4" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="yml">
+    <option name="INDENT_SIZE" value="2" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <codeStyleSettings language="JavaScript">
+    <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
+    <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+    <option name="BLANK_LINES_AROUND_FIELD" value="1" />
+    <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
+    <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+    <option name="ALIGN_MULTILINE_FOR" value="false" />
+    <option name="CALL_PARAMETERS_WRAP" value="1" />
+    <option name="METHOD_PARAMETERS_WRAP" value="1" />
+    <option name="EXTENDS_LIST_WRAP" value="1" />
+    <option name="THROWS_LIST_WRAP" value="1" />
+    <option name="EXTENDS_KEYWORD_WRAP" value="1" />
+    <option name="THROWS_KEYWORD_WRAP" value="1" />
+    <option name="METHOD_CALL_CHAIN_WRAP" value="1" />
+    <option name="BINARY_OPERATION_WRAP" value="1" />
+    <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
+    <option name="TERNARY_OPERATION_WRAP" value="1" />
+    <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
+    <option name="FOR_STATEMENT_WRAP" value="1" />
+    <option name="ARRAY_INITIALIZER_WRAP" value="1" />
+    <option name="ASSIGNMENT_WRAP" value="1" />
+    <option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
+    <option name="WRAP_COMMENTS" value="true" />
+    <option name="IF_BRACE_FORCE" value="3" />
+    <option name="DOWHILE_BRACE_FORCE" value="3" />
+    <option name="WHILE_BRACE_FORCE" value="3" />
+    <option name="FOR_BRACE_FORCE" value="3" />
+    <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+  </codeStyleSettings>
 </code_scheme>
 
diff --git a/samples/AccelerometerPlay/_index.jd b/samples/AccelerometerPlay/_index.jd
index cdca3a6..488cda7 100644
--- a/samples/AccelerometerPlay/_index.jd
+++ b/samples/AccelerometerPlay/_index.jd
@@ -1,3 +1,4 @@
+page.keywords="Sensor", "Games", "Accelerometer"
 page.tags="Sensor", "Games", "Accelerometer"
 sample.group=Sensors
 @jd:body
diff --git a/samples/ApiDemos/Android.mk b/samples/ApiDemos/Android.mk
index 066c497..ca48f58 100644
--- a/samples/ApiDemos/Android.mk
+++ b/samples/ApiDemos/Android.mk
@@ -12,6 +12,8 @@
 
 LOCAL_JAVA_LIBRARIES := telephony-common mms-common
 
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4
+
 LOCAL_PACKAGE_NAME := ApiDemos
 
 LOCAL_SDK_VERSION := current
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index 34464a0..f202d59 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -32,6 +32,7 @@
     <uses-permission android:name="android.permission.SEND_SMS" />
     <uses-permission android:name="android.permission.RECEIVE_SMS" />
     <uses-permission android:name="android.permission.NFC" />
+    <uses-permission android:name="android.permission.TRANSMIT_IR" />
 
     <!-- For android.media.audiofx.Visualizer -->
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
@@ -643,6 +644,11 @@
             </intent-filter>
         </activity>
 
+        <!-- Stub for memory testing. -->
+
+        <receiver android:name=".app.DoNothing"
+                android:process=":empty" android:exported="true" />
+
         <!-- ============================ -->
         <!--  Accessibility examples      -->
         <!-- ============================ -->
@@ -990,10 +996,36 @@
             </intent-filter>
         </activity>
 
-        <!-- Accessibility Samples -->
-        <activity android:name=".accessibility.AccessibilityNodeProviderActivity"
-                android:label="@string/accessibility_node_provider"
-                android:enabled="@bool/atLeastIceCreamSandwich">
+        <activity android:name=".app.PrintBitmap"
+                android:label="@string/print_bitmap"
+                android:enabled="@bool/atLeastKitKat">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".app.PrintHtmlFromScreen"
+                android:label="@string/print_html_from_screen"
+                android:enabled="@bool/atLeastKitKat">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".app.PrintHtmlOffScreen"
+                android:label="@string/print_html_off_screen"
+                android:enabled="@bool/atLeastKitKat">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".app.PrintCustomContent"
+                android:label="@string/print_custom_content"
+                android:enabled="@bool/atLeastKitKat">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.SAMPLE_CODE" />
@@ -1010,6 +1042,13 @@
         </receiver>
 <!-- END_INCLUDE(app_update_declaration) -->
 
+        <receiver android:name=".app.AppUpdateSspReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.PACKAGE_REPLACED" />
+                <data android:scheme="package" android:ssp="com.example.android.apis" />
+            </intent-filter>
+        </receiver>
+
         <!-- ************************************* -->
         <!--       PREFERENCE PACKAGE SAMPLES      -->
         <!-- ************************************* -->
@@ -1117,6 +1156,16 @@
             </intent-filter>
         </activity>
 
+        <!--
+        <activity android:name=".content.TextUndoActivity" android:label="@string/activity_text_undo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+                <category android:name="android.intent.category.EMBED" />
+            </intent-filter>
+        </activity>
+        -->
+
         <activity android:name=".content.ResourcesLayoutReference"
                 android:label="@string/activity_resources_layout_reference">
             <intent-filter>
@@ -1188,6 +1237,17 @@
                   android:enabled="@bool/atLeastHoneycombMR2" />
 
         <!-- ************************************* -->
+        <!--     HARDWARE PACKAGE SAMPLES          -->
+        <!-- ************************************* -->
+
+        <activity android:name=".hardware.ConsumerIr" android:label="Hardware/Consumer IR">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <!-- ************************************* -->
         <!--     OS PACKAGE SAMPLES                -->
         <!-- ************************************* -->
 
@@ -1242,7 +1302,6 @@
 
         <activity android:name=".animation.AnimationLoading"
                 android:label="Animation/Loading"
-                android:hardwareAccelerated="false"
                 android:enabled="@bool/atLeastHoneycomb">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1252,7 +1311,6 @@
 
         <activity android:name=".animation.AnimationCloning"
                 android:label="Animation/Cloning"
-                android:hardwareAccelerated="false"
                 android:enabled="@bool/atLeastHoneycomb">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1262,7 +1320,6 @@
 
         <activity android:name=".animation.AnimationSeeking"
                 android:label="Animation/Seeking"
-                android:hardwareAccelerated="false"
                 android:enabled="@bool/atLeastHoneycomb">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1272,7 +1329,6 @@
 
         <activity android:name=".animation.AnimatorEvents"
                 android:label="Animation/Events"
-                android:hardwareAccelerated="false"
                 android:enabled="@bool/atLeastHoneycomb">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1282,7 +1338,6 @@
 
         <activity android:name=".animation.BouncingBalls"
                 android:label="Animation/Bouncing Balls"
-                android:hardwareAccelerated="false"
                 android:enabled="@bool/atLeastHoneycomb">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1292,7 +1347,6 @@
 
         <activity android:name=".animation.CustomEvaluator"
                 android:label="Animation/Custom Evaluator"
-                android:hardwareAccelerated="false"
                 android:enabled="@bool/atLeastHoneycomb">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1311,7 +1365,6 @@
 
         <activity android:name=".animation.ReversingAnimation"
                 android:label="Animation/Reversing"
-                android:hardwareAccelerated="false"
                 android:enabled="@bool/atLeastHoneycomb">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1321,7 +1374,6 @@
 
         <activity android:name=".animation.MultiPropertyAnimation"
                 android:label="Animation/Multiple Properties"
-                android:hardwareAccelerated="false"
                 android:enabled="@bool/atLeastHoneycomb">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1348,8 +1400,17 @@
         </activity>
 
         <activity android:name=".animation.LayoutAnimationsByDefault"
-                android:label="Animation/Default Layout Animations"
-                android:enabled="@bool/atLeastHoneycomb">
+                  android:label="Animation/Default Layout Animations"
+                  android:enabled="@bool/atLeastHoneycomb">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".animation.Transitions"
+                  android:label="Animation/Simple Transitions"
+                  android:enabled="@bool/atLeastHoneycomb">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.SAMPLE_CODE" />
@@ -2376,6 +2437,17 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".view.ContentBrowserNavActivity"
+                android:label="Views/System UI Visibility/Content Browser Nav Bar"
+                android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
+                android:uiOptions="splitActionBarWhenNarrow"
+                android:enabled="@bool/atLeastKitKat">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".view.VideoPlayerActivity"
                 android:label="Views/System UI Visibility/Video Player"
                 android:theme="@android:style/Theme.Holo"
@@ -2387,6 +2459,26 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".view.TranslucentBarsActivity"
+                android:label="Views/System UI Visibility/Translucent Bars"
+                android:theme="@android:style/Theme.Holo.NoActionBar.TranslucentDecor"
+                android:enabled="@bool/atLeastKitKat">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.GameActivity"
+                android:label="Views/System UI Visibility/Game"
+                android:theme="@android:style/Theme.Holo.NoActionBar"
+                android:enabled="@bool/atLeastKitKat">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".view.Switches" android:label="Views/Switches">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/samples/ApiDemos/res/layout/accessibility_node_provider.xml b/samples/ApiDemos/res/layout/accessibility_node_provider.xml
deleted file mode 100644
index cc10c9c..0000000
--- a/samples/ApiDemos/res/layout/accessibility_node_provider.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:orientation="vertical">
-
-    <TextView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="50dip"
-        android:text="@string/accessibility_node_provider_instructions">
-    </TextView>
-
-    <view
-        class="com.example.android.apis.accessibility.AccessibilityNodeProviderActivity$VirtualSubtreeRootView"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" >
-    </view>
-
-</LinearLayout>
diff --git a/samples/ApiDemos/res/layout/consumer_ir.xml b/samples/ApiDemos/res/layout/consumer_ir.xml
new file mode 100644
index 0000000..bb60b53
--- /dev/null
+++ b/samples/ApiDemos/res/layout/consumer_ir.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This activity exercises search invocation options -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <Button
+        android:id="@+id/send_button"
+        android:text="@string/ir_send"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+    <Button
+        android:id="@+id/get_freqs_button"
+        android:text="@string/ir_get_freqs"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <ScrollView
+        android:id="@+id/freqs_text_scroll"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" >
+
+        <TextView
+            android:id="@+id/freqs_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingLeft="3dp"
+            android:paddingRight="3dp" />
+
+    </ScrollView>
+
+</LinearLayout>
diff --git a/samples/ApiDemos/res/layout/content_browser_nav.xml b/samples/ApiDemos/res/layout/content_browser_nav.xml
new file mode 100644
index 0000000..e006620
--- /dev/null
+++ b/samples/ApiDemos/res/layout/content_browser_nav.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent" android:layout_height="match_parent"
+    >
+    <view class="com.example.android.apis.view.ContentBrowserNavActivity$Content"
+        android:id="@+id/content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        />
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:fitsSystemWindows="true"
+        android:animateLayoutChanges="true"
+        >
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal"
+            android:textColor="#ff000000"
+            android:background="#c0ffffff"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:gravity="center"
+            android:padding="16dp"
+            android:text="A title goes here"
+            />
+        <SeekBar
+            android:id="@+id/seekbar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom|center_horizontal"
+            android:layout_marginBottom="16dp"
+            />
+    </FrameLayout>
+</FrameLayout>
diff --git a/samples/ApiDemos/res/layout/game.xml b/samples/ApiDemos/res/layout/game.xml
new file mode 100644
index 0000000..809a253
--- /dev/null
+++ b/samples/ApiDemos/res/layout/game.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- BEGIN_INCLUDE(complete) -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent" android:layout_height="match_parent"
+    >
+    <!-- This is the outer area of the entire game screen, extending out under
+         system UI elements. -->
+    <view class="com.example.android.apis.view.GameActivity$Content"
+        android:id="@+id/content"
+        android:src="@drawable/frantic"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="center"
+        />
+    <!-- This is the inner area of the game, not covered by system UI elements.
+        Any UI elements that need to be accessible when the game is paused or other
+        states where the system UI is shown (such as in menus) should go here. -->
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:fitsSystemWindows="true"
+        android:animateLayoutChanges="true"
+        >
+        <Button
+            android:id="@+id/play"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|right"
+            android:textSize="28dp"
+            />
+    </FrameLayout>
+</FrameLayout>
+<!-- END_INCLUDE(complete) -->
diff --git a/samples/ApiDemos/res/layout/intents.xml b/samples/ApiDemos/res/layout/intents.xml
index aed709d..e301b0b 100644
--- a/samples/ApiDemos/res/layout/intents.xml
+++ b/samples/ApiDemos/res/layout/intents.xml
@@ -17,7 +17,8 @@
 <!-- Demonstrates launching various intents.
      See corresponding Java code com.example.android.apis.app.Intents.java. -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="4dip"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:padding="4dip"
     android:gravity="center_horizontal"
     android:layout_width="match_parent" android:layout_height="match_parent">
 
@@ -29,9 +30,22 @@
 
     <Button android:id="@+id/get_music"
         android:layout_width="wrap_content" android:layout_height="wrap_content" 
-        android:text="@string/get_music">
+        android:text="@string/get_music"
+        android:onClick="onGetMusic">
         <requestFocus />
     </Button>
 
+    <Button android:id="@+id/get_image"
+        android:layout_width="wrap_content" android:layout_height="wrap_content"
+        android:text="@string/get_image"
+        android:onClick="onGetImage">
+    </Button>
+
+    <Button android:id="@+id/get_stream"
+        android:layout_width="wrap_content" android:layout_height="wrap_content"
+        android:text="@string/get_stream"
+        android:onClick="onGetStream">
+    </Button>
+
 </LinearLayout>
 
diff --git a/samples/ApiDemos/res/layout/motogp_stat_item.xml b/samples/ApiDemos/res/layout/motogp_stat_item.xml
new file mode 100644
index 0000000..e09fd67
--- /dev/null
+++ b/samples/ApiDemos/res/layout/motogp_stat_item.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="16dip"
+        android:paddingEnd="16dip"
+        android:minHeight="64dip"
+        android:orientation="horizontal">
+
+    <TextView
+        android:id="@+id/year"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_weight="1"
+        android:gravity="start"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textIsSelectable="false">
+    </TextView>
+
+    <TextView
+        android:id="@+id/champion"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:textIsSelectable="false"
+        android:duplicateParentState="true">
+    </TextView>
+
+    <TextView
+        android:id="@+id/constructor"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_weight="1"
+        android:gravity="end"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textIsSelectable="false">
+    </TextView>
+
+</LinearLayout>
diff --git a/samples/ApiDemos/res/layout/print_bitmap.xml b/samples/ApiDemos/res/layout/print_bitmap.xml
new file mode 100644
index 0000000..cce522a
--- /dev/null
+++ b/samples/ApiDemos/res/layout/print_bitmap.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/image"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:src="@raw/android_logo"
+        android:contentDescription="@string/android_logo">
+</ImageView>
diff --git a/samples/ApiDemos/res/layout/print_html_from_screen.xml b/samples/ApiDemos/res/layout/print_html_from_screen.xml
new file mode 100644
index 0000000..535bcb2
--- /dev/null
+++ b/samples/ApiDemos/res/layout/print_html_from_screen.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<WebView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/web_view"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:padding="16dip">
+</WebView>
diff --git a/samples/ApiDemos/res/layout/print_html_off_screen.xml b/samples/ApiDemos/res/layout/print_html_off_screen.xml
new file mode 100644
index 0000000..799b079
--- /dev/null
+++ b/samples/ApiDemos/res/layout/print_html_off_screen.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textIsSelectable="false"
+        android:text="@string/print_html_off_screen_msg">
+</TextView>
diff --git a/samples/ApiDemos/res/layout/system_ui_modes.xml b/samples/ApiDemos/res/layout/system_ui_modes.xml
index aaf6c1a..a4e63e3 100644
--- a/samples/ApiDemos/res/layout/system_ui_modes.xml
+++ b/samples/ApiDemos/res/layout/system_ui_modes.xml
@@ -28,126 +28,159 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:fitsSystemWindows="true">
-        <GridLayout android:layout_width="match_parent"
+        <ScrollView
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginLeft="25dp"
             android:layout_marginRight="25dp"
             android:layout_marginBottom="25dp"
             android:layout_gravity="bottom|center"
-            android:background="#60000000"
-            android:padding="8dp"
-            android:columnCount="2">
+            android:background="#60000000">
+            <GridLayout android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:padding="8dp"
+                android:columnCount="@integer/system_ui_modes_cols">
 
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:textSize="16dp"
-                android:textStyle="bold"
-                android:gravity="left"
-                android:text="Mode:"
-                />
-            <CheckBox
-                android:id="@+id/modeFullscreen"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:text="FULLSCRN"
-                />
-            <CheckBox
-                android:id="@+id/modeLowProfile"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:text="LOW_PROFILE"
-                />
-            <CheckBox
-                android:id="@+id/modeHideNavigation"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:text="HIDE_NAV"
-                />
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:textSize="16dp"
+                    android:textStyle="bold"
+                    android:gravity="left"
+                    android:text="Mode:"
+                    />
+                <CheckBox
+                    android:id="@+id/modeFullscreen"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="FULLSCRN"
+                    />
+                <CheckBox
+                    android:id="@+id/modeLowProfile"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="LOW_PROFILE"
+                    />
+                <CheckBox
+                    android:id="@+id/modeHideNavigation"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="HIDE_NAV"
+                    />
+                <CheckBox
+                    android:id="@+id/modeImmersive"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="IMMERSIVE"
+                    />
+                <CheckBox
+                    android:id="@+id/modeImmersiveSticky"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="IMM_STICKY"
+                    />
 
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:textSize="16dp"
-                android:textStyle="bold"
-                android:gravity="left"
-                android:text="Layout:"
-                />
-            <CheckBox
-                android:id="@+id/layoutFullscreen"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:text="FULLSCRN"
-                />
-            <CheckBox
-                android:id="@+id/layoutStable"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:text="STABLE"
-                />
-            <CheckBox
-                android:id="@+id/layoutHideNavigation"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:text="HIDE_NAV"
-                />
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:textSize="16dp"
+                    android:textStyle="bold"
+                    android:gravity="left"
+                    android:text="Layout:"
+                    />
+                <CheckBox
+                    android:id="@+id/layoutFullscreen"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="FULLSCRN"
+                    />
+                <CheckBox
+                    android:id="@+id/layoutStable"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="STABLE"
+                    />
+                <CheckBox
+                    android:id="@+id/layoutHideNavigation"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="HIDE_NAV"
+                    />
 
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_columnSpan="2"
-                android:textColor="#FFFFFFFF"
-                android:textSize="16dp"
-                android:textStyle="bold"
-                android:gravity="left"
-                android:text="Window:"
-                />
-            <CheckBox
-                android:id="@+id/windowHideActionBar"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:text="No ActionBar"
-                />
-            <CheckBox
-                android:id="@+id/windowFullscreen"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:text="FULLSCRN"
-                />
-            <CheckBox
-                android:id="@+id/windowActionMode"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:text="Action Mode"
-                />
-            <CheckBox
-                android:id="@+id/windowOverscan"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textColor="#FFFFFFFF"
-                android:text="OVERSCAN"
-                />
-            <TextView
-                android:id="@+id/metricsText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_columnSpan="2"
-                android:textColor="#FFFFFFFF"
-                android:textSize="11dp"
-                android:textStyle="bold"
-                android:gravity="center"
-                />
-        </GridLayout>
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_columnSpan="@integer/system_ui_modes_cols"
+                    android:textColor="#FFFFFFFF"
+                    android:textSize="16dp"
+                    android:textStyle="bold"
+                    android:gravity="left"
+                    android:text="Window:"
+                    />
+                <CheckBox
+                    android:id="@+id/windowHideActionBar"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="No ActionBar"
+                    />
+                <CheckBox
+                    android:id="@+id/windowFullscreen"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="FULLSCRN"
+                    />
+                <CheckBox
+                    android:id="@+id/windowActionMode"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="Action Mode"
+                    />
+                <CheckBox
+                    android:id="@+id/windowOverscan"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="OVERSCAN"
+                    />
+                <CheckBox
+                    android:id="@+id/windowTranslucentStatus"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="TRANS_STATUS"
+                    />
+                <CheckBox
+                    android:id="@+id/windowTranslucentNav"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="#FFFFFFFF"
+                    android:text="TRANS_NAV"
+                    />
+
+                <TextView
+                    android:id="@+id/metricsText"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_columnSpan="@integer/system_ui_modes_cols"
+                    android:textColor="#FFFFFFFF"
+                    android:textSize="11dp"
+                    android:textStyle="bold"
+                    android:gravity="center"
+                    />
+            </GridLayout>
+        </ScrollView>
     </FrameLayout>
 </FrameLayout>
diff --git a/samples/ApiDemos/res/layout/text_undo.xml b/samples/ApiDemos/res/layout/text_undo.xml
new file mode 100644
index 0000000..f7d74e8
--- /dev/null
+++ b/samples/ApiDemos/res/layout/text_undo.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Demonstrates saving and restoring activity state.
+     See corresponding Java code com.android.sdk.app.SaveRestoreState.java. -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent" android:layout_height="match_parent">
+    <LinearLayout android:orientation="vertical" android:padding="4dip"
+        android:layout_width="match_parent" android:layout_height="wrap_content">
+
+        <TextView android:id="@+id/msg"
+            android:layout_width="match_parent" android:layout_height="wrap_content"
+            android:layout_weight="0" android:textAppearance="?android:attr/textAppearanceMedium"
+            android:paddingBottom="8dip"
+            android:text="@string/text_undo_msg" />
+
+        <EditText android:id="@+id/text"
+            android:layout_width="match_parent" android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:freezesText="true">
+        </EditText>
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:paddingTop="8dip">
+            <Button
+                android:id="@+id/undo"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/undo"
+                android:layout_gravity="bottom" />
+            <Button
+                android:id="@+id/redo"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/redo"
+                android:layout_gravity="bottom" />
+        </LinearLayout>
+
+    </LinearLayout>
+</ScrollView>
diff --git a/samples/ApiDemos/res/layout/transition.xml b/samples/ApiDemos/res/layout/transition.xml
new file mode 100644
index 0000000..57b91be
--- /dev/null
+++ b/samples/ApiDemos/res/layout/transition.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <RadioGroup
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+        <RadioButton android:id="@+id/scene1"
+                     android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:checked="true"
+                     android:onClick="selectScene"
+                     android:text="Scene 1" />
+
+        <RadioButton android:id="@+id/scene2"
+                     android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:onClick="selectScene"
+                     android:text="Scene 2" />
+
+        <RadioButton android:id="@+id/scene3"
+                     android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:onClick="selectScene"
+                     android:text="Scene 3" />
+
+        <RadioButton android:id="@+id/scene4"
+                     android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:onClick="selectScene"
+                     android:text="Scene 4" />
+
+    </RadioGroup>
+
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/sceneRoot">
+
+        <include layout="@layout/transition_scene1"/>
+
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/ApiDemos/res/layout/transition_scene1.xml b/samples/ApiDemos/res/layout/transition_scene1.xml
new file mode 100644
index 0000000..a98da60
--- /dev/null
+++ b/samples/ApiDemos/res/layout/transition_scene1.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:id="@+id/container">
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="50dip"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentLeft="true"
+            android:background="#f00"
+            android:id="@+id/view1"/>
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="50dip"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentRight="true"
+            android:background="#0f0"
+            android:id="@+id/view2"/>
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="50dip"
+            android:background="#00f"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentLeft="true"
+            android:id="@+id/view3"/>
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="50dip"
+            android:background="#0ff"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:id="@+id/view4"/>
+
+</RelativeLayout>
diff --git a/samples/ApiDemos/res/layout/transition_scene2.xml b/samples/ApiDemos/res/layout/transition_scene2.xml
new file mode 100644
index 0000000..fda2276
--- /dev/null
+++ b/samples/ApiDemos/res/layout/transition_scene2.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/container">
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="100dip"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentRight="true"
+            android:background="#f00"
+            android:id="@+id/view1"/>
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="100dip"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentLeft="true"
+            android:background="#0f0"
+            android:id="@+id/view2"/>
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="100dip"
+            android:background="#00f"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:id="@+id/view3"/>
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="100dip"
+            android:background="#0ff"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentLeft="true"
+            android:id="@+id/view4"/>
+
+</RelativeLayout>
diff --git a/samples/ApiDemos/res/layout/transition_scene3.xml b/samples/ApiDemos/res/layout/transition_scene3.xml
new file mode 100644
index 0000000..39c4da7
--- /dev/null
+++ b/samples/ApiDemos/res/layout/transition_scene3.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:id="@+id/container">
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="50dip"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentLeft="true"
+            android:background="#f00"
+            android:id="@+id/view1"/>
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="50dip"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentRight="true"
+            android:background="#0f0"
+            android:id="@+id/view2"/>
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="50dip"
+            android:background="#00f"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentLeft="true"
+            android:id="@+id/view3"/>
+
+    <View
+            android:layout_width="100dip"
+            android:layout_height="50dip"
+            android:background="#0ff"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:id="@+id/view4"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:orientation="vertical"
+        android:id="@+id/grayscaleContainer">
+
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="10dip"
+                android:background="#000"
+                android:id="@+id/gray1"/>
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="10dip"
+                android:background="#222"
+                android:id="@+id/gray2"/>
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="10dip"
+                android:background="#444"
+                android:id="@+id/gray3"/>
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="10dip"
+                android:background="#666"
+                android:id="@+id/gray4"/>
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="10dip"
+                android:background="#888"
+                android:id="@+id/gray5"/>
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="10dip"
+                android:background="#aaa"
+                android:id="@+id/gray6"/>
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="10dip"
+                android:background="#ccc"
+                android:id="@+id/gray7"/>
+        <View
+                android:layout_width="match_parent"
+                android:layout_height="10dip"
+                android:background="#fff"
+                android:id="@+id/gray8"/>
+
+    </LinearLayout>
+
+</RelativeLayout>
diff --git a/samples/ApiDemos/res/layout/translucent_bars.xml b/samples/ApiDemos/res/layout/translucent_bars.xml
new file mode 100644
index 0000000..c7cbe40
--- /dev/null
+++ b/samples/ApiDemos/res/layout/translucent_bars.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <TextView android:id="@+id/text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:fitsSystemWindows="true"
+            android:textSize="16dp"
+            android:text="@string/alert_dialog_two_buttons2ultra_msg" />
+</ScrollView>
diff --git a/samples/ApiDemos/res/menu/print_custom_content.xml b/samples/ApiDemos/res/menu/print_custom_content.xml
new file mode 100644
index 0000000..ace8039
--- /dev/null
+++ b/samples/ApiDemos/res/menu/print_custom_content.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 Google Inc.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_print"
+        android:title="@string/print"
+        android:showAsAction="never" />
+</menu>
diff --git a/samples/ApiDemos/res/raw/android_logo.png b/samples/ApiDemos/res/raw/android_logo.png
new file mode 100644
index 0000000..f970c26
--- /dev/null
+++ b/samples/ApiDemos/res/raw/android_logo.png
Binary files differ
diff --git a/samples/ApiDemos/res/raw/motogp_stats.html b/samples/ApiDemos/res/raw/motogp_stats.html
new file mode 100644
index 0000000..b55ed9e
--- /dev/null
+++ b/samples/ApiDemos/res/raw/motogp_stats.html
@@ -0,0 +1,333 @@
+<!DOCTYPE html>
+<html>
+<body>
+<table>
+<caption>500cc/MotoGP champions</caption>
+<thead><tr>
+<th scope="col">Season</td>
+<th scope="col">Rider</td>
+<th scope="col">Constructor</td>
+</tr></thead><tbody>
+<tr>
+<td>2012</td>
+<td>Jorge Lorenzo</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2011</td>
+<td>Casey Stoner</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>2010</td>
+<td>Jorge Lorenzo</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2009</td>
+<td>Valentino Rossi</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2008</td>
+<td>Valentino Rossi</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2007</td>
+<td>Casey Stoner</td>
+<td>Ducati</td>
+</tr>
+<tr>
+<td>2006</td>
+<td>Nicky Hayden</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>2005</td>
+<td>Valentino Rossi</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2004</td>
+<td>Valentino Rossi</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>2003</td>
+<td>Valentino Rossi</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>2002</td>
+<td>Valentino Rossi</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>2001</td>
+<td>Valentino Rossi</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>2000</td>
+<td>Kenny Roberts, Jr.</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1999</td>
+<td>Ëlex CrivillŽ</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1998</td>
+<td>Michael Doohan</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1997</td>
+<td>Michael Doohan</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1996</td>
+<td>Michael Doohan</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1995</td>
+<td>Michael Doohan</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1994</td>
+<td>Michael Doohan</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1993</td>
+<td>Kevin Schwantz</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1992</td>
+<td>Wayne Rainey</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1991</td>
+<td>Wayne Rainey</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1990</td>
+<td>Wayne Rainey</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1989</td>
+<td>Eddie Lawson</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1988</td>
+<td>Eddie Lawson</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1987</td>
+<td>Wayne Gardner</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1986</td>
+<td>Eddie Lawson</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1985</td>
+<td>Freddie Spencer</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1984</td>
+<td>Eddie Lawson</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1983</td>
+<td>Freddie Spencer</td>
+<td>Honda</td>
+</tr>
+<tr>
+<td>1982</td>
+<td>Franco Uncini</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1981</td>
+<td>Marco Lucchinelli</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1980</td>
+<td>Kenny Roberts</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1979</td>
+<td>Kenny Roberts</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1978</td>
+<td>Kenny Roberts</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1977</td>
+<td>Barry Sheene</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1976</td>
+<td>Barry Sheene</td>
+<td>Suzuki</td>
+</tr>
+<tr>
+<td>1975</td>
+<td>Giacomo Agostini</td>
+<td>Yamaha</td>
+</tr>
+<tr>
+<td>1974</td>
+<td>Phil Read</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1973</td>
+<td>Phil Read</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1972</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1971</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1970</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1969</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1968</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1967</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1966</td>
+<td>Giacomo Agostini</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1965</td>
+<td>Mike Hailwood</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1964</td>
+<td>Mike Hailwood</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1963</td>
+<td>Mike Hailwood</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1962</td>
+<td>Mike Hailwood</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1961</td>
+<td>Gary Hocking</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1960</td>
+<td>John Surtees</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1959</td>
+<td>John Surtees</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1958</td>
+<td>John Surtees</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1957</td>
+<td>Libero Liberati</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1956</td>
+<td>John Surtees</td>
+<td>MV Agusta</td>
+</tr>
+<tr>
+<td>1955</td>
+<td>Geoff Duke</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1954</td>
+<td>Geoff Duke</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1953</td>
+<td>Geoff Duke</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1952</td>
+<td>Umberto Masetti</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1951</td>
+<td>Geoff Duke</td>
+<td>Norton</td>
+</tr>
+<tr>
+<td>1950</td>
+<td>Umberto Masetti</td>
+<td>Gilera</td>
+</tr>
+<tr>
+<td>1949</td>
+<td>Leslie Graham</td>
+<td>AJS</td>
+</tr>
+</tbody><tfoot></tfoot></table>
+</body>
+</html>
\ No newline at end of file
diff --git a/samples/ApiDemos/res/transition/changebounds.xml b/samples/ApiDemos/res/transition/changebounds.xml
new file mode 100644
index 0000000..a217003
--- /dev/null
+++ b/samples/ApiDemos/res/transition/changebounds.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- BEGIN_INCLUDE(ChangeBounds) -->
+<changeBounds/>
+<!-- END_INCLUDE(ChangeBounds) -->
diff --git a/samples/ApiDemos/res/transition/changebounds_fadein_together.xml b/samples/ApiDemos/res/transition/changebounds_fadein_together.xml
new file mode 100644
index 0000000..3a35653
--- /dev/null
+++ b/samples/ApiDemos/res/transition/changebounds_fadein_together.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+    <changeBounds/>
+    <fade android:fadingMode="fade_in" >
+        <targets>
+            <target android:targetId="@id/grayscaleContainer" />
+        </targets>
+    </fade>
+</transitionSet>
diff --git a/samples/ApiDemos/res/transition/changebounds_fadeout_sequential.xml b/samples/ApiDemos/res/transition/changebounds_fadeout_sequential.xml
new file mode 100644
index 0000000..4734135
--- /dev/null
+++ b/samples/ApiDemos/res/transition/changebounds_fadeout_sequential.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- BEGIN_INCLUDE(TransitionSet) -->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
+     android:transitionOrdering="sequential">
+    <changeBounds/>
+    <fade android:fadingMode="fade_out" >
+        <targets>
+            <target android:targetId="@id/grayscaleContainer" />
+        </targets>
+    </fade>
+</transitionSet>
+<!-- END_INCLUDE(TransitionSet) -->
diff --git a/samples/ApiDemos/res/transition/transitions_mgr.xml b/samples/ApiDemos/res/transition/transitions_mgr.xml
new file mode 100644
index 0000000..bd11906
--- /dev/null
+++ b/samples/ApiDemos/res/transition/transitions_mgr.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- BEGIN_INCLUDE(TransitionManager) -->
+<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
+    <transition android:fromScene="@layout/transition_scene1"
+                android:toScene="@layout/transition_scene2"
+                android:transition="@transition/changebounds"/>
+    <transition android:fromScene="@layout/transition_scene2"
+                android:toScene="@layout/transition_scene1"
+                android:transition="@transition/changebounds"/>
+    <transition android:toScene="@layout/transition_scene3"
+                android:transition="@transition/changebounds_fadein_together"/>
+    <transition android:fromScene="@layout/transition_scene3"
+                android:toScene="@layout/transition_scene1"
+                android:transition="@transition/changebounds_fadeout_sequential"/>
+    <transition android:fromScene="@layout/transition_scene3"
+                android:toScene="@layout/transition_scene2"
+                android:transition="@transition/changebounds_fadeout_sequential"/>
+</transitionManager>
+<!-- END_INCLUDE(TransitionManager) -->
diff --git a/samples/ApiDemos/res/values-land/integers.xml b/samples/ApiDemos/res/values-land/integers.xml
new file mode 100644
index 0000000..d7e7c37
--- /dev/null
+++ b/samples/ApiDemos/res/values-land/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+  <!-- For the System UI Modes API demo, this is the number of columns to use
+       for the mode options.  Changes between portrait and landscape. -->
+  <integer name="system_ui_modes_cols">3</integer>
+</resources>
diff --git a/samples/ApiDemos/res/values-v19/bools.xml b/samples/ApiDemos/res/values-v19/bools.xml
new file mode 100644
index 0000000..136d8fe
--- /dev/null
+++ b/samples/ApiDemos/res/values-v19/bools.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- This resource is true if running under at least KitKat
+         API level.  The default value is false; an alternative value
+         for KitKat is true. -->
+    <bool name="atLeastKitKat">true</bool>
+</resources>
diff --git a/samples/ApiDemos/res/values/arrays.xml b/samples/ApiDemos/res/values/arrays.xml
index b062209..8f987ae 100644
--- a/samples/ApiDemos/res/values/arrays.xml
+++ b/samples/ApiDemos/res/values/arrays.xml
@@ -154,4 +154,209 @@
         <item>No.</item>
         <item>Mmm... cheese.</item>
     </string-array>
+
+    <!-- Used in app/Print/Custom Layout example -->
+    <string-array name="motogp_years">
+        <item>2012</item>
+        <item>2011</item>
+        <item>2010</item>
+        <item>2009</item>
+        <item>2008</item>
+        <item>2007</item>
+        <item>2006</item>
+        <item>2005</item>
+        <item>2004</item>
+        <item>2003</item>
+        <item>2002</item>
+        <item>2001</item>
+        <item>2000</item>
+        <item>1999</item>
+        <item>1998</item>
+        <item>1997</item>
+        <item>1996</item>
+        <item>1995</item>
+        <item>1994</item>
+        <item>1993</item>
+        <item>1992</item>
+        <item>1991</item>
+        <item>1990</item>
+        <item>1989</item>
+        <item>1988</item>
+        <item>1987</item>
+        <item>1986</item>
+        <item>1985</item>
+        <item>1984</item>
+        <item>1983</item>
+        <item>1982</item>
+        <item>1981</item>
+        <item>1980</item>
+        <item>1979</item>
+        <item>1978</item>
+        <item>1977</item>
+        <item>1976</item>
+        <item>1975</item>
+        <item>1974</item>
+        <item>1973</item>
+        <item>1972</item>
+        <item>1971</item>
+        <item>1970</item>
+        <item>1969</item>
+        <item>1968</item>
+        <item>1967</item>
+        <item>1966</item>
+        <item>1965</item>
+        <item>1964</item>
+        <item>1963</item>
+        <item>1962</item>
+        <item>1961</item>
+        <item>1960</item>
+        <item>1959</item>
+        <item>1958</item>
+        <item>1957</item>
+        <item>1956</item>
+        <item>1955</item>
+        <item>1954</item>
+        <item>1953</item>
+        <item>1952</item>
+        <item>1951</item>
+        <item>1950</item>
+        <item>1949</item>
+    </string-array>
+
+    <!-- Used in app/Print/Custom Layout example -->
+    <string-array name="motogp_champions">
+        <item>Jorge Lorenzo</item>
+        <item>Casey Stoner</item>
+        <item>Jorge Lorenzo</item>
+        <item>Valentino Rossi</item>
+        <item>Valentino Rossi</item>
+        <item>Casey Stoner</item>
+        <item>Nicky Hayden</item>
+        <item>Valentino Rossi</item>
+        <item>Valentino Rossi</item>
+        <item>Valentino Rossi</item>
+        <item>Valentino Rossi</item>
+        <item>Valentino Rossi</item>
+        <item>Kenny Roberts, Jr.</item>
+        <item>Àlex Crivillé</item>
+        <item>Michael Doohan</item>
+        <item>Michael Doohan</item>
+        <item>Michael Doohan</item>
+        <item>Michael Doohan</item>
+        <item>Michael Doohan</item>
+        <item>Kevin Schwantz</item>
+        <item>Wayne Rainey</item>
+        <item>Wayne Rainey</item>
+        <item>Wayne Rainey</item>
+        <item>Eddie Lawson</item>
+        <item>Eddie Lawson</item>
+        <item>Wayne Gardner</item>
+        <item>Eddie Lawson</item>
+        <item>Freddie Spencer</item>
+        <item>Eddie Lawson</item>
+        <item>Freddie Spencer</item>
+        <item>Franco Uncini</item>
+        <item>Marco Lucchinelli</item>
+        <item>Kenny Roberts</item>
+        <item>Kenny Roberts</item>
+        <item>Kenny Roberts</item>
+        <item>Barry Sheene</item>
+        <item>Barry Sheene</item>
+        <item>Giacomo Agostini</item>
+        <item>Phil Read</item>
+        <item>Phil Read</item>
+        <item>Giacomo Agostini</item>
+        <item>Giacomo Agostini</item>
+        <item>Giacomo Agostini</item>
+        <item>Giacomo Agostini</item>
+        <item>Giacomo Agostini</item>
+        <item>Giacomo Agostini</item>
+        <item>Giacomo Agostini</item>
+        <item>Mike Hailwood</item>
+        <item>Mike Hailwood</item>
+        <item>Mike Hailwood</item>
+        <item>Mike Hailwood</item>
+        <item>Gary Hocking</item>
+        <item>John Surtees</item>
+        <item>John Surtees</item>
+        <item>John Surtees</item>
+        <item>Libero Liberati</item>
+        <item>John Surtees</item>
+        <item>Geoff Duke</item>
+        <item>Geoff Duke</item>
+        <item>Geoff Duke</item>
+        <item>Umberto Masetti</item>
+        <item>Geoff Duke</item>
+        <item>Umberto Masetti</item>
+        <item>Leslie Graham</item>
+    </string-array>
+
+    <!-- Used in app/Print/Custom Layout example -->
+    <string-array name="motogp_constructors">
+        <item>Yamaha</item>
+        <item>Honda</item>
+        <item>Yamaha</item>
+        <item>Yamaha</item>
+        <item>Yamaha</item>
+        <item>Ducati</item>
+        <item>Honda</item>
+        <item>Yamaha</item>
+        <item>Yamaha</item>
+        <item>Honda</item>
+        <item>Honda</item>
+        <item>Honda</item>
+        <item>Suzuki</item>
+        <item>Honda</item>
+        <item>Honda</item>
+        <item>Honda</item>
+        <item>Honda</item>
+        <item>Honda</item>
+        <item>Honda</item>
+        <item>Suzuki</item>
+        <item>Yamaha</item>
+        <item>Yamaha</item>
+        <item>Yamaha</item>
+        <item>Honda</item>
+        <item>Yamaha</item>
+        <item>Honda</item>
+        <item>Yamaha</item>
+        <item>Honda</item>
+        <item>Yamaha</item>
+        <item>Honda</item>
+        <item>Suzuki</item>
+        <item>Suzuki</item>
+        <item>Yamaha</item>
+        <item>Yamaha</item>
+        <item>Yamaha</item>
+        <item>Suzuki</item>
+        <item>Suzuki</item>
+        <item>Giacomo Agostini</item>
+        <item>Phil Read</item>
+        <item>Phil Read</item>
+        <item>Yamaha</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>MV Agusta</item>
+        <item>Gilera</item>
+        <item>MV Agusta</item>
+        <item>Gilera</item>
+        <item>Gilera</item>
+        <item>Gilera</item>
+        <item>Gilera</item>
+        <item>Norton</item>
+        <item>Gilera</item>
+        <item>AJS</item>
+    </string-array>
+
 </resources>
diff --git a/samples/ApiDemos/res/values/bools.xml b/samples/ApiDemos/res/values/bools.xml
index 366d733..fa3f25f 100644
--- a/samples/ApiDemos/res/values/bools.xml
+++ b/samples/ApiDemos/res/values/bools.xml
@@ -44,4 +44,9 @@
          for JellyBean MR 2 is true. -->
     <bool name="atLeastJellyBeanMR2">false</bool>
 
+    <!-- This resource is true if running under at least KitKat
+         API level.  The default value is false; an alternative value
+         for KitKat is true. -->
+    <bool name="atLeastKitKat">false</bool>
+
 </resources>
diff --git a/samples/ApiDemos/res/values/integers.xml b/samples/ApiDemos/res/values/integers.xml
new file mode 100644
index 0000000..70a6c69
--- /dev/null
+++ b/samples/ApiDemos/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+  <!-- For the System UI Modes API demo, this is the number of columns to use
+       for the mode options.  Changes between portrait and landscape. -->
+  <integer name="system_ui_modes_cols">2</integer>
+</resources>
diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml
index 9329cdd..804087d 100644
--- a/samples/ApiDemos/res/values/strings.xml
+++ b/samples/ApiDemos/res/values/strings.xml
@@ -421,6 +421,12 @@
     <string name="styled_text">Plain, <b>bold</b>, <i>italic</i>, <b><i>bold-italic</i></b></string>
     <string name="styled_text_prog">Assigned programmatically:</string>
 
+    <string name="activity_text_undo">Content/Undo Manager/Text</string>
+    <string name="text_undo_msg">Demonstrates simple use of UndoManager with text editing
+            in a TextView.</string>
+    <string name="undo">Undo</string>
+    <string name="redo">Redo</string>
+
     <string name="activity_resources_layout_reference">Content/Resources/Layout Reference</string>
     <string name="resources_layout_reference_description">Shows how to write layout
         resource references, so that you can define multiple different configurations of
@@ -454,6 +460,9 @@
 
     <string name="activity_install_apk">Content/Packages/Install Apk</string>
 
+    <string name="ir_send">Send IR</string>
+    <string name="ir_get_freqs">Get Carrier Frequencies</string>
+
     <!-- ============================== -->
     <!--  app/intents examples strings     -->
     <!-- ============================== -->
@@ -461,6 +470,8 @@
     <string name="activity_intents">App/Activity/Intents</string>
     <string name="intents">Example of launching various Intents.</string>
     <string name="get_music">Get Music</string>
+    <string name="get_image">Get Image</string>
+    <string name="get_stream">Get Stream</string>
 
     <!-- ============================== -->
     <!--  app/intents activity flags examples strings     -->
@@ -860,6 +871,19 @@
     <string name="btn_toggle_tabs">Toggle tab mode</string>
     <string name="btn_remove_all_tabs">Remove all tabs</string>
 
+    <!-- ================================= -->
+    <!--  app/print print examples strings  -->
+    <!-- ================================= -->
+
+    <string name="print_bitmap">App/Print/Print Bitmap</string>
+    <string name="print_html_from_screen">App/Print/Print HTML from screen</string>
+    <string name="print_html_off_screen">App/Print/Print HTML off screen</string>
+    <string name="print_custom_content">App/Print/Print Custom Layout</string>
+    <string name="print">Print</string>
+    <string name="print_html_off_screen_msg">From the overflow menu you can print some
+        off screen content.</string>
+    <string name="android_logo">Android logo</string>
+
     <!-- ============================ -->
     <!--  graphics examples strings  -->
     <!-- ============================ -->
@@ -1419,10 +1443,6 @@
     <!--  Accessibility examples strings  -->
     <!-- ============================ -->
 
-    <string name="accessibility_node_provider">Accessibility/Accessibility Node Provider</string>
-    <string name="accessibility_node_provider_instructions">Enable TalkBack and Explore-by-touch from accessibility
-        settings. Then touch the colored squares.</string>
-
     <string name="accessibility_service">Accessibility/Accessibility Service</string>
     <string name="accessibility_service_label">ClockBack</string>
     <string name="accessibility_service_instructions">
diff --git a/samples/ApiDemos/src/com/example/android/apis/accessibility/AccessibilityNodeProviderActivity.java b/samples/ApiDemos/src/com/example/android/apis/accessibility/AccessibilityNodeProviderActivity.java
deleted file mode 100644
index 1ca036a..0000000
--- a/samples/ApiDemos/src/com/example/android/apis/accessibility/AccessibilityNodeProviderActivity.java
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.apis.accessibility;
-
-import com.example.android.apis.R;
-
-import android.app.Activity;
-import android.app.Service;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeProvider;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * This sample demonstrates how a View can expose a virtual view sub-tree
- * rooted at it. A virtual sub-tree is composed of imaginary Views
- * that are reported as a part of the view hierarchy for accessibility
- * purposes. This enables custom views that draw complex content to report
- * them selves as a tree of virtual views, thus conveying their logical
- * structure.
- * <p>
- * For example, a View may draw a monthly calendar as a grid of days while
- * each such day may contains some events. From a perspective of the View
- * hierarchy the calendar is composed of a single View but an accessibility
- * service would benefit of traversing the logical structure of the calendar
- * by examining each day and each event on that day.
- * </p>
- */
-public class AccessibilityNodeProviderActivity extends Activity {
-    /** Called when the activity is first created. */
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.accessibility_node_provider);
-    }
-
-   /**
-    * This class presents a View that is composed of three virtual children
-    * each of which is drawn with a different color and represents a region
-    * of the View that has different semantics compared to other such regions.
-    * While the virtual view tree exposed by this class is one level deep
-    * for simplicity, there is no bound on the complexity of that virtual
-    * sub-tree.
-    */
-    public static class VirtualSubtreeRootView extends View {
-
-        /** Paint object for drawing the virtual sub-tree */
-        private final Paint mPaint = new Paint();
-
-        /** Temporary rectangle to minimize object creation. */
-        private final Rect mTempRect = new Rect();
-
-        /** Handle to the system accessibility service. */
-        private final AccessibilityManager mAccessibilityManager;
-
-        /** The virtual children of this View. */
-        private final List<VirtualView> mChildren = new ArrayList<VirtualView>();
-
-        /** The instance of the node provider for the virtual tree - lazily instantiated. */
-        private AccessibilityNodeProvider mAccessibilityNodeProvider;
-
-        /** The last hovered child used for event dispatching. */
-        private VirtualView mLastHoveredChild;
-
-        public VirtualSubtreeRootView(Context context, AttributeSet attrs) {
-            super(context, attrs);
-            mAccessibilityManager = (AccessibilityManager) context.getSystemService(
-                    Service.ACCESSIBILITY_SERVICE);
-            createVirtualChildren();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public AccessibilityNodeProvider getAccessibilityNodeProvider() {
-            // Instantiate the provide only when requested. Since the system
-            // will call this method multiple times it is a good practice to
-            // cache the provider instance.
-            if (mAccessibilityNodeProvider == null) {
-                mAccessibilityNodeProvider = new VirtualDescendantsProvider();
-            }
-            return mAccessibilityNodeProvider;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public boolean dispatchHoverEvent(MotionEvent event) {
-            // This implementation assumes that the virtual children
-            // cannot overlap and are always visible. Do NOT use this
-            // code as a reference of how to implement hover event
-            // dispatch. Instead, refer to ViewGroup#dispatchHoverEvent.
-            boolean handled = false;
-            List<VirtualView> children = mChildren;
-            final int childCount = children.size();
-            for (int i = 0; i < childCount; i++) {
-                VirtualView child = children.get(i);
-                Rect childBounds = child.mBounds;
-                final int childCoordsX = (int) event.getX() + getScrollX();
-                final int childCoordsY = (int) event.getY() + getScrollY();
-                if (!childBounds.contains(childCoordsX, childCoordsY)) {
-                    continue;
-                }
-                final int action = event.getAction();
-                switch (action) {
-                    case MotionEvent.ACTION_HOVER_ENTER: {
-                        mLastHoveredChild = child;
-                        handled |= onHoverVirtualView(child, event);
-                        event.setAction(action);
-                    } break;
-                    case MotionEvent.ACTION_HOVER_MOVE: {
-                        if (child == mLastHoveredChild) {
-                            handled |= onHoverVirtualView(child, event);
-                            event.setAction(action);
-                        } else {
-                            MotionEvent eventNoHistory = event.getHistorySize() > 0
-                                ? MotionEvent.obtainNoHistory(event) : event;
-                            eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
-                            onHoverVirtualView(mLastHoveredChild, eventNoHistory);
-                            eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
-                            onHoverVirtualView(child, eventNoHistory);
-                            mLastHoveredChild = child;
-                            eventNoHistory.setAction(MotionEvent.ACTION_HOVER_MOVE);
-                            handled |= onHoverVirtualView(child, eventNoHistory);
-                            if (eventNoHistory != event) {
-                                eventNoHistory.recycle();
-                            } else {
-                                event.setAction(action);
-                            }
-                        }
-                    } break;
-                    case MotionEvent.ACTION_HOVER_EXIT: {
-                        mLastHoveredChild = null;
-                        handled |= onHoverVirtualView(child, event);
-                        event.setAction(action);
-                    } break;
-                }
-            }
-            if (!handled) {
-                handled |= onHoverEvent(event);
-            }
-            return handled;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-            // The virtual children are ordered horizontally next to
-            // each other and take the entire space of this View.
-            int offsetX = 0;
-            List<VirtualView> children = mChildren;
-            final int childCount = children.size();
-            for (int i = 0; i < childCount; i++) {
-                VirtualView child = children.get(i);
-                Rect childBounds = child.mBounds;
-                childBounds.set(offsetX, 0, offsetX + childBounds.width(), childBounds.height());
-                offsetX += childBounds.width();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            // The virtual children are ordered horizontally next to
-            // each other and take the entire space of this View.
-            int width = 0;
-            int height = 0;
-            List<VirtualView> children = mChildren;
-            final int childCount = children.size();
-            for (int i = 0; i < childCount; i++) {
-                VirtualView child = children.get(i);
-                width += child.mBounds.width();
-                height = Math.max(height, child.mBounds.height());
-            }
-            setMeasuredDimension(width, height);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        protected void onDraw(Canvas canvas) {
-            // Draw the virtual children with the reusable Paint object
-            // and with the bounds and color which are child specific.
-            Rect drawingRect = mTempRect;
-            List<VirtualView> children = mChildren;
-            final int childCount = children.size();
-            for (int i = 0; i < childCount; i++) {
-                VirtualView child = children.get(i);
-                drawingRect.set(child.mBounds);
-                mPaint.setColor(child.mColor);
-                mPaint.setAlpha(child.mAlpha);
-                canvas.drawRect(drawingRect, mPaint);
-            }
-        }
-
-        /**
-         * Creates the virtual children of this View.
-         */
-        private void createVirtualChildren() {
-            // The virtual portion of the tree is one level deep. Note
-            // that implementations can use any way of representing and
-            // drawing virtual view.
-            VirtualView firstChild = new VirtualView(0, new Rect(0, 0, 150, 150), Color.RED,
-                    "Virtual view 1");
-            mChildren.add(firstChild);
-            VirtualView secondChild = new VirtualView(1, new Rect(0, 0, 150, 150), Color.GREEN,
-                    "Virtual view 2");
-            mChildren.add(secondChild);
-            VirtualView thirdChild = new VirtualView(2, new Rect(0, 0, 150, 150), Color.BLUE,
-                    "Virtual view 3");
-            mChildren.add(thirdChild);
-        }
-
-        /**
-         * Set the selected state of a virtual view.
-         *
-         * @param virtualView The virtual view whose selected state to set.
-         * @param selected Whether the virtual view is selected.
-         */
-        private void setVirtualViewSelected(VirtualView virtualView, boolean selected) {
-            virtualView.mAlpha = selected ? VirtualView.ALPHA_SELECTED : VirtualView.ALPHA_NOT_SELECTED;
-        }
-
-        /**
-         * Handle a hover over a virtual view.
-         *
-         * @param virtualView The virtual view over which is hovered.
-         * @param event The event to dispatch.
-         * @return Whether the event was handled.
-         */
-        private boolean onHoverVirtualView(VirtualView virtualView, MotionEvent event) {
-            // The implementation of hover event dispatch can be implemented
-            // in any way that is found suitable. However, each virtual View
-            // should fire a corresponding accessibility event whose source
-            // is that virtual view. Accessibility services get the event source
-            // as the entry point of the APIs for querying the window content.
-            final int action = event.getAction();
-            switch (action) {
-                case MotionEvent.ACTION_HOVER_ENTER: {
-                    sendAccessibilityEventForVirtualView(virtualView,
-                            AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
-                } break;
-                case MotionEvent.ACTION_HOVER_EXIT: {
-                    sendAccessibilityEventForVirtualView(virtualView,
-                            AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
-                } break;
-            }
-            return true;
-        }
-
-        /**
-         * Sends a properly initialized accessibility event for a virtual view..
-         *
-         * @param virtualView The virtual view.
-         * @param eventType The type of the event to send.
-         */
-        private void sendAccessibilityEventForVirtualView(VirtualView virtualView, int eventType) {
-            // If touch exploration, i.e. the user gets feedback while touching
-            // the screen, is enabled we fire accessibility events.
-            if (mAccessibilityManager.isTouchExplorationEnabled()) {
-                AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
-                event.setPackageName(getContext().getPackageName());
-                event.setClassName(virtualView.getClass().getName());
-                event.setSource(VirtualSubtreeRootView.this, virtualView.mId);
-                event.getText().add(virtualView.mText);
-                getParent().requestSendAccessibilityEvent(VirtualSubtreeRootView.this, event);
-            }
-        }
-
-        /**
-         * Finds a virtual view given its id.
-         *
-         * @param id The virtual view id.
-         * @return The found virtual view.
-         */
-        private VirtualView findVirtualViewById(int id) {
-            List<VirtualView> children = mChildren;
-            final int childCount = children.size();
-            for (int i = 0; i < childCount; i++) {
-                VirtualView child = children.get(i);
-                if (child.mId == id) {
-                    return child;
-                }
-            }
-            return null;
-        }
-
-        /**
-         * Represents a virtual View.
-         */
-        private class VirtualView {
-            public static final int ALPHA_SELECTED = 255;
-            public static final int ALPHA_NOT_SELECTED = 127;
-
-            public final int mId;
-            public final int mColor;
-            public final Rect mBounds;
-            public final String mText;
-            public int mAlpha;
-
-            public VirtualView(int id, Rect bounds, int color, String text) {
-                mId = id;
-                mColor = color;
-                mBounds = bounds;
-                mText = text;
-                mAlpha = ALPHA_NOT_SELECTED;
-            }
-        }
-
-        /**
-         * This is the provider that exposes the virtual View tree to accessibility
-         * services. From the perspective of an accessibility service the
-         * {@link AccessibilityNodeInfo}s it receives while exploring the sub-tree
-         * rooted at this View will be the same as the ones it received while
-         * exploring a View containing a sub-tree composed of real Views.
-         */
-        private class VirtualDescendantsProvider extends AccessibilityNodeProvider {
-
-            /**
-             * {@inheritDoc}
-             */
-            @Override
-            public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
-                AccessibilityNodeInfo info = null;
-                if (virtualViewId == View.NO_ID) {
-                    // We are requested to create an AccessibilityNodeInfo describing
-                    // this View, i.e. the root of the virtual sub-tree. Note that the
-                    // host View has an AccessibilityNodeProvider which means that this
-                    // provider is responsible for creating the node info for that root.
-                    info = AccessibilityNodeInfo.obtain(VirtualSubtreeRootView.this);
-                    onInitializeAccessibilityNodeInfo(info);
-                    // Add the virtual children of the root View.
-                    List<VirtualView> children = mChildren;
-                    final int childCount = children.size();
-                    for (int i = 0; i < childCount; i++) {
-                        VirtualView child = children.get(i);
-                        info.addChild(VirtualSubtreeRootView.this, child.mId);
-                    }
-                } else {
-                    // Find the view that corresponds to the given id.
-                    VirtualView virtualView = findVirtualViewById(virtualViewId);
-                    if (virtualView == null) {
-                        return null;
-                    }
-                    // Obtain and initialize an AccessibilityNodeInfo with
-                    // information about the virtual view.
-                    info = AccessibilityNodeInfo.obtain();
-                    info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
-                    info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
-                    info.setPackageName(getContext().getPackageName());
-                    info.setClassName(virtualView.getClass().getName());
-                    info.setSource(VirtualSubtreeRootView.this, virtualViewId);
-                    info.setBoundsInParent(virtualView.mBounds);
-                    info.setParent(VirtualSubtreeRootView.this);
-                    info.setText(virtualView.mText);
-                }
-                return info;
-            }
-
-            /**
-             * {@inheritDoc}
-             */
-            @Override
-            public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String searched,
-                    int virtualViewId) {
-                if (TextUtils.isEmpty(searched)) {
-                    return Collections.emptyList();
-                }
-                String searchedLowerCase = searched.toLowerCase();
-                List<AccessibilityNodeInfo> result = null;
-                if (virtualViewId == View.NO_ID) {
-                    // If the search is from the root, i.e. this View, go over the virtual
-                    // children and look for ones that contain the searched string since
-                    // this View does not contain text itself.
-                    List<VirtualView> children = mChildren;
-                    final int childCount = children.size();
-                    for (int i = 0; i < childCount; i++) {
-                        VirtualView child = children.get(i);
-                        String textToLowerCase = child.mText.toLowerCase();
-                        if (textToLowerCase.contains(searchedLowerCase)) {
-                            if (result == null) {
-                                result = new ArrayList<AccessibilityNodeInfo>();
-                            }
-                            result.add(createAccessibilityNodeInfo(child.mId));
-                        }
-                    }
-                } else {
-                    // If the search is from a virtual view, find the view. Since the tree
-                    // is one level deep we add a node info for the child to the result if
-                    // the child contains the searched text.
-                    VirtualView virtualView = findVirtualViewById(virtualViewId);
-                    if (virtualView != null) {
-                        String textToLowerCase = virtualView.mText.toLowerCase();
-                        if (textToLowerCase.contains(searchedLowerCase)) {
-                            result = new ArrayList<AccessibilityNodeInfo>();
-                            result.add(createAccessibilityNodeInfo(virtualViewId));
-                        }
-                    }
-                }
-                if (result == null) {
-                    return Collections.emptyList();
-                }
-                return result;
-            }
-
-            /**
-             * {@inheritDoc}
-             */
-            @Override
-            public boolean performAction(int virtualViewId, int action, Bundle arguments) {
-                if (virtualViewId == View.NO_ID) {
-                    // Perform the action on the host View.
-                    switch (action) {
-                        case AccessibilityNodeInfo.ACTION_SELECT:
-                            if (!isSelected()) {
-                                setSelected(true);
-                                return isSelected();
-                            }
-                            break;
-                        case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION:
-                            if (isSelected()) {
-                                setSelected(false);
-                                return !isSelected();
-                            }
-                            break;
-                    }
-                } else {
-                    // Find the view that corresponds to the given id.
-                    VirtualView child = findVirtualViewById(virtualViewId);
-                    if (child == null) {
-                        return false;
-                    }
-                    // Perform the action on a virtual view.
-                    switch (action) {
-                        case AccessibilityNodeInfo.ACTION_SELECT:
-                            setVirtualViewSelected(child, true);
-                            invalidate();
-                            return true;
-                        case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION:
-                            setVirtualViewSelected(child, false);
-                            invalidate();
-                            return true;
-                    }
-                }
-                return false;
-            }
-        }
-    }
-}
diff --git a/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html b/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html
index df54e96..1324f86 100644
--- a/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html
+++ b/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html
@@ -21,12 +21,6 @@
     xml files, and adding additional information to AccessibilityEvents using
     AccessibilityRecords.
   </dd>
-  <dt><a href="AccessibilityNodeProviderActivity.html">Accessibility Node Provider</a></dt>
-  <dd>Demonstrates how to develop an accessibility node provider which manages a virtual
-    View tree reported to accessibility services. The virtual subtree is rooted at a View
-    that draws complex content and reports itself as a tree of virtual views, thus conveying
-    its logical structure.
-  </dd>
 </dl>
 
 <dl>
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/Transitions.java b/samples/ApiDemos/src/com/example/android/apis/animation/Transitions.java
new file mode 100644
index 0000000..4878c5f
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/Transitions.java
@@ -0,0 +1,91 @@
+/*
+ * 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.apis.animation;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.transition.Scene;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import com.example.android.apis.R;
+
+/**
+ * This application demonstrates some of the capabilities and uses of the
+ * {@link android.transition transitions} APIs. Scenes and a TransitionManager
+ * are loaded from resource files and transitions are run between those scenes
+ * as well as a dynamically-configured scene.
+ */
+public class Transitions extends Activity {
+
+    Scene mScene1, mScene2, mScene3;
+    ViewGroup mSceneRoot;
+    TransitionManager mTransitionManager;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.transition);
+
+        mSceneRoot = (ViewGroup) findViewById(R.id.sceneRoot);
+
+        TransitionInflater inflater = TransitionInflater.from(this);
+
+        // Note that this is not the only way to create a Scene object, but that
+        // loading them from layout resources cooperates with the
+        // TransitionManager that we are also loading from resources, and which
+        // uses the same layout resource files to determine the scenes to transition
+        // from/to.
+        mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.transition_scene1, this);
+        mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.transition_scene2, this);
+        mScene3 = Scene.getSceneForLayout(mSceneRoot, R.layout.transition_scene3, this);
+        mTransitionManager = inflater.inflateTransitionManager(R.transition.transitions_mgr,
+                mSceneRoot);
+    }
+
+    public void selectScene(View view) {
+        switch (view.getId()) {
+            case R.id.scene1:
+                mTransitionManager.transitionTo(mScene1);
+                break;
+            case R.id.scene2:
+                mTransitionManager.transitionTo(mScene2);
+                break;
+            case R.id.scene3:
+                mTransitionManager.transitionTo(mScene3);
+                break;
+            case R.id.scene4:
+                // scene4 is not an actual 'Scene', but rather a dynamic change in the UI,
+                // transitioned to using beginDelayedTransition() to tell the TransitionManager
+                // to get ready to run a transition at the next frame
+                TransitionManager.beginDelayedTransition(mSceneRoot);
+                setNewSize(R.id.view1, 150, 25);
+                setNewSize(R.id.view2, 150, 25);
+                setNewSize(R.id.view3, 150, 25);
+                setNewSize(R.id.view4, 150, 25);
+                break;
+        }
+    }
+
+    private void setNewSize(int id, int width, int height) {
+        View view = findViewById(id);
+        ViewGroup.LayoutParams params = view.getLayoutParams();
+        params.width = width;
+        params.height = height;
+        view.setLayoutParams(params);
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/AppUpdateSspReceiver.java b/samples/ApiDemos/src/com/example/android/apis/app/AppUpdateSspReceiver.java
new file mode 100644
index 0000000..dfa265c
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/AppUpdateSspReceiver.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.apis.app;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.widget.Toast;
+
+/**
+ * Executed when a new version of the application is is installed.
+ */
+public class AppUpdateSspReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String msg = "Ssp update received: " + intent.getData();
+        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/DoNothing.java b/samples/ApiDemos/src/com/example/android/apis/app/DoNothing.java
new file mode 100644
index 0000000..133a802
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/DoNothing.java
@@ -0,0 +1,27 @@
+/*
+ * 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.apis.app;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class DoNothing extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/Intents.java b/samples/ApiDemos/src/com/example/android/apis/app/Intents.java
index 8f02b83..6207dd8 100644
--- a/samples/ApiDemos/src/com/example/android/apis/app/Intents.java
+++ b/samples/ApiDemos/src/com/example/android/apis/app/Intents.java
@@ -31,17 +31,23 @@
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.intents);
-
-        // Watch for button clicks.
-        Button button = (Button)findViewById(R.id.get_music);
-        button.setOnClickListener(mGetMusicListener);
     }
 
-    private OnClickListener mGetMusicListener = new OnClickListener() {
-        public void onClick(View v) {
-            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
-            intent.setType("audio/*");
-            startActivity(Intent.createChooser(intent, "Select music"));
-        }
-    };
+    public void onGetMusic(View view) {
+        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+        intent.setType("audio/*");
+        startActivity(Intent.createChooser(intent, "Select music"));
+    }
+
+    public void onGetImage(View view) {
+        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+        intent.setType("image/*");
+        startActivity(Intent.createChooser(intent, "Select image"));
+    }
+
+    public void onGetStream(View view) {
+        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+        intent.setType("*/*");
+        startActivity(Intent.createChooser(intent, "Select stream"));
+    }
 }
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/PrintBitmap.java b/samples/ApiDemos/src/com/example/android/apis/app/PrintBitmap.java
new file mode 100644
index 0000000..762478a
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/PrintBitmap.java
@@ -0,0 +1,82 @@
+package com.example.android.apis.app;
+/*
+ * 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.
+ */
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Bundle;
+import android.print.PrintManager;
+import android.support.v4.print.PrintHelper;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.webkit.WebView;
+import android.widget.ImageView;
+
+import com.example.android.apis.R;
+
+/**
+ * This class demonstrates how to implement bitmap printing.
+ * <p>
+ * This activity shows an image and offers a print option in the overflow
+ * menu. When the user chooses to print a helper class from the support
+ * library is used to print the image.
+ * </p>
+ *
+ * @see PrintManager
+ * @see WebView
+ */
+public class PrintBitmap extends Activity {
+
+    private ImageView mImageView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.print_bitmap);
+        mImageView = (ImageView) findViewById(R.id.image);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        getMenuInflater().inflate(R.menu.print_custom_content, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.menu_print) {
+            print();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void print() {
+        // Get the print manager.
+        PrintHelper printHelper = new PrintHelper(this);
+
+        // Set the desired scale mode.
+        printHelper.setScaleMode(PrintHelper.SCALE_MODE_FIT);
+
+        // Get the bitmap for the ImageView's drawable.
+        Bitmap bitmap = ((BitmapDrawable) mImageView.getDrawable()).getBitmap();
+
+        // Print the bitmap.
+        printHelper.printBitmap("Print Bitmap", bitmap);
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/PrintCustomContent.java b/samples/ApiDemos/src/com/example/android/apis/app/PrintCustomContent.java
new file mode 100644
index 0000000..7a7e7ed
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/PrintCustomContent.java
@@ -0,0 +1,562 @@
+/*
+ * 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.apis.app;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.pdf.PdfDocument.Page;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.CancellationSignal.OnCancelListener;
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentInfo;
+import android.print.PrintManager;
+import android.print.pdf.PrintedPdfDocument;
+import android.util.SparseIntArray;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.example.android.apis.R;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class demonstrates how to implement custom printing support.
+ * <p>
+ * This activity shows the list of the MotoGP champions by year and
+ * brand. The print option in the overflow menu allows the user to
+ * print the content. The list list of items is laid out to such that
+ * it fits the options selected by the user from the UI such as page
+ * size. Hence, for different page sizes the printed content will have
+ * different page count.
+ * </p>
+ * <p>
+ * This sample demonstrates how to completely implement a {@link
+ * PrintDocumentAdapter} in which:
+ * <ul>
+ * <li>Layout based on the selected print options is performed.</li>
+ * <li>Layout work is performed only if print options change would change the content.</li>
+ * <li>Layout result is properly reported.</li>
+ * <li>Only requested pages are written.</li>
+ * <li>Write result is properly reported.</li>
+ * <li>Both Layout and write respond to cancellation.</li>
+ * <li>Layout and render of views is demonstrated.</li>
+ * </ul>
+ * </p>
+ *
+ * @see PrintManager
+ * @see PrintDocumentAdapter
+ */
+public class PrintCustomContent extends ListActivity {
+
+    private static final int MILS_IN_INCH = 1000;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setListAdapter(new MotoGpStatAdapter(loadMotoGpStats(),
+                getLayoutInflater()));
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        getMenuInflater().inflate(R.menu.print_custom_content, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.menu_print) {
+            print();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void print() {
+        PrintManager printManager = (PrintManager) getSystemService(
+                Context.PRINT_SERVICE);
+
+        printManager.print("MotoGP stats",
+            new PrintDocumentAdapter() {
+                private int mRenderPageWidth;
+                private int mRenderPageHeight;
+
+                private PrintAttributes mPrintAttributes;
+                private PrintDocumentInfo mDocumentInfo;
+                private Context mPrintContext;
+
+                @Override
+                public void onLayout(final PrintAttributes oldAttributes,
+                        final PrintAttributes newAttributes,
+                        final CancellationSignal cancellationSignal,
+                        final LayoutResultCallback callback,
+                        final Bundle metadata) {
+
+                    // If we are already cancelled, don't do any work.
+                    if (cancellationSignal.isCanceled()) {
+                        callback.onLayoutCancelled();
+                        return;
+                    }
+
+                    // Now we determined if the print attributes changed in a way that
+                    // would change the layout and if so we will do a layout pass.
+                    boolean layoutNeeded = false;
+
+                    final int density = Math.max(newAttributes.getResolution().getHorizontalDpi(),
+                            newAttributes.getResolution().getVerticalDpi());
+
+                    // Note that we are using the PrintedPdfDocument class which creates
+                    // a PDF generating canvas whose size is in points (1/72") not screen
+                    // pixels. Hence, this canvas is pretty small compared to the screen.
+                    // The recommended way is to layout the content in the desired size,
+                    // in this case as large as the printer can do, and set a translation
+                    // to the PDF canvas to shrink in. Note that PDF is a vector format
+                    // and you will not lose data during the transformation.
+
+                    // The content width is equal to the page width minus the margins times
+                    // the horizontal printer density. This way we get the maximal number
+                    // of pixels the printer can put horizontally.
+                    final int marginLeft = (int) (density * (float) newAttributes.getMinMargins()
+                            .getLeftMils() / MILS_IN_INCH);
+                    final int marginRight = (int) (density * (float) newAttributes.getMinMargins()
+                            .getRightMils() / MILS_IN_INCH);
+                    final int contentWidth = (int) (density * (float) newAttributes.getMediaSize()
+                            .getWidthMils() / MILS_IN_INCH) - marginLeft - marginRight;
+                    if (mRenderPageWidth != contentWidth) {
+                        mRenderPageWidth = contentWidth;
+                        layoutNeeded = true;
+                    }
+
+                    // The content height is equal to the page height minus the margins times
+                    // the vertical printer resolution. This way we get the maximal number
+                    // of pixels the printer can put vertically.
+                    final int marginTop = (int) (density * (float) newAttributes.getMinMargins()
+                            .getTopMils() / MILS_IN_INCH);
+                    final int marginBottom = (int) (density * (float) newAttributes.getMinMargins()
+                            .getBottomMils() / MILS_IN_INCH);
+                    final int contentHeight = (int) (density * (float) newAttributes.getMediaSize()
+                            .getHeightMils() / MILS_IN_INCH) - marginTop - marginBottom;
+                    if (mRenderPageHeight != contentHeight) {
+                        mRenderPageHeight = contentHeight;
+                        layoutNeeded = true;
+                    }
+
+                    // Create a context for resources at printer density. We will
+                    // be inflating views to render them and would like them to use
+                    // resources for a density the printer supports.
+                    if (mPrintContext == null || mPrintContext.getResources()
+                            .getConfiguration().densityDpi != density) {
+                        Configuration configuration = new Configuration();
+                        configuration.densityDpi = density;
+                        mPrintContext = createConfigurationContext(
+                                configuration);
+                        mPrintContext.setTheme(android.R.style.Theme_Holo_Light);
+                    }
+
+                    // If no layout is needed that we did a layout at least once and
+                    // the document info is not null, also the second argument is false
+                    // to notify the system that the content did not change. This is
+                    // important as if the system has some pages and the content didn't
+                    // change the system will ask, the application to write them again.
+                    if (!layoutNeeded) {
+                        callback.onLayoutFinished(mDocumentInfo, false);
+                        return;
+                    }
+
+                    // For demonstration purposes we will do the layout off the main
+                    // thread but for small content sizes like this one it is OK to do
+                    // that on the main thread.
+
+                    // Store the data as we will layout off the main thread.
+                    final List<MotoGpStatItem> items = ((MotoGpStatAdapter)
+                                    getListAdapter()).cloneItems();
+
+                    new AsyncTask<Void, Void, PrintDocumentInfo>() {
+                        @Override
+                        protected void onPreExecute() {
+                            // First register for cancellation requests.
+                            cancellationSignal.setOnCancelListener(new OnCancelListener() {
+                                @Override
+                                public void onCancel() {
+                                    cancel(true);
+                                }
+                            });
+                            // Stash the attributes as we will need them for rendering.
+                            mPrintAttributes = newAttributes;
+                        }
+
+                        @Override
+                        protected PrintDocumentInfo doInBackground(Void... params) {
+                            try {
+                                // Create an adapter with the stats and an inflater
+                                // to load resources for the printer density.
+                                MotoGpStatAdapter adapter = new MotoGpStatAdapter(items,
+                                        (LayoutInflater) mPrintContext.getSystemService(
+                                                Context.LAYOUT_INFLATER_SERVICE));
+
+                                int currentPage = 0;
+                                int pageContentHeight = 0;
+                                int viewType = -1;
+                                View view = null;
+                                LinearLayout dummyParent = new LinearLayout(mPrintContext);
+                                dummyParent.setOrientation(LinearLayout.VERTICAL);
+
+                                final int itemCount = adapter.getCount();
+                                for (int i = 0; i < itemCount; i++) {
+                                    // Be nice and respond to cancellation.
+                                    if (isCancelled()) {
+                                        return null;
+                                    }
+
+                                    // Get the next view.
+                                    final int nextViewType = adapter.getItemViewType(i);
+                                    if (viewType == nextViewType) {
+                                        view = adapter.getView(i, view, dummyParent); 
+                                    } else {
+                                        view = adapter.getView(i, null, dummyParent);
+                                    }
+                                    viewType = nextViewType;
+
+                                    // Measure the next view
+                                    measureView(view);
+
+                                    // Add the height but if the view crosses the page
+                                    // boundary we will put it to the next page.
+                                    pageContentHeight += view.getMeasuredHeight();
+                                    if (pageContentHeight > mRenderPageHeight) {
+                                        pageContentHeight = view.getMeasuredHeight();
+                                        currentPage++;
+                                    }
+                                }
+
+                                // Create a document info describing the result.
+                                PrintDocumentInfo info = new PrintDocumentInfo
+                                        .Builder("MotoGP_stats.pdf")
+                                    .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+                                    .setPageCount(currentPage + 1)
+                                    .build();
+
+                                // We completed the layout as a result of print attributes
+                                // change. Hence, if we are here the content changed for
+                                // sure which is why we pass true as the second argument.
+                                callback.onLayoutFinished(info, true);
+                                return info;
+                            } catch (Exception e) {
+                                // An unexpected error, report that we failed and
+                                // one may pass in a human readable localized text
+                                // for what the error is if known.
+                                callback.onLayoutFailed(null);
+                                throw new RuntimeException(e);
+                            }
+                        }
+
+                        @Override
+                        protected void onPostExecute(PrintDocumentInfo result) {
+                            // Update the cached info to send it over if the next
+                            // layout pass does not result in a content change.
+                            mDocumentInfo = result;
+                        }
+
+                        @Override
+                        protected void onCancelled(PrintDocumentInfo result) {
+                            // Task was cancelled, report that.
+                            callback.onLayoutCancelled();
+                        }
+                    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+                }
+
+                @Override
+                public void onWrite(final PageRange[] pages,
+                        final ParcelFileDescriptor destination,
+                        final CancellationSignal cancellationSignal,
+                        final WriteResultCallback callback) {
+
+                    // If we are already cancelled, don't do any work.
+                    if (cancellationSignal.isCanceled()) {
+                        callback.onWriteCancelled();
+                        return;
+                    }
+
+                    // Store the data as we will layout off the main thread.
+                    final List<MotoGpStatItem> items = ((MotoGpStatAdapter)
+                                    getListAdapter()).cloneItems();
+
+                    new AsyncTask<Void, Void, Void>() {
+                        private final SparseIntArray mWrittenPages = new SparseIntArray();
+                        private final PrintedPdfDocument mPdfDocument = new PrintedPdfDocument(
+                                PrintCustomContent.this, mPrintAttributes);
+
+                        @Override
+                        protected void onPreExecute() {
+                            // First register for cancellation requests.
+                            cancellationSignal.setOnCancelListener(new OnCancelListener() {
+                                @Override
+                                public void onCancel() {
+                                    cancel(true);
+                                }
+                            });
+                        }
+
+                        @Override
+                        protected Void doInBackground(Void... params) {
+                            // Go over all the pages and write only the requested ones.
+                            // Create an adapter with the stats and an inflater
+                            // to load resources for the printer density.
+                            MotoGpStatAdapter adapter = new MotoGpStatAdapter(items,
+                                    (LayoutInflater) mPrintContext.getSystemService(
+                                            Context.LAYOUT_INFLATER_SERVICE));
+
+                            int currentPage = -1;
+                            int pageContentHeight = 0;
+                            int viewType = -1;
+                            View view = null;
+                            Page page = null;
+                            LinearLayout dummyParent = new LinearLayout(mPrintContext);
+                            dummyParent.setOrientation(LinearLayout.VERTICAL);
+
+                            // The content is laid out and rendered in screen pixels with
+                            // the width and height of the paper size times the print
+                            // density but the PDF canvas size is in points which are 1/72",
+                            // so we will scale down the content.
+                            final float scale =  Math.min(
+                                    (float) mPdfDocument.getPageContentRect().width()
+                                            / mRenderPageWidth,
+                                    (float) mPdfDocument.getPageContentRect().height()
+                                            / mRenderPageHeight);
+
+                            final int itemCount = adapter.getCount();
+                            for (int i = 0; i < itemCount; i++) {
+                                // Be nice and respond to cancellation.
+                                if (isCancelled()) {
+                                    return null;
+                                }
+
+                                // Get the next view.
+                                final int nextViewType = adapter.getItemViewType(i);
+                                if (viewType == nextViewType) {
+                                    view = adapter.getView(i, view, dummyParent);
+                                } else {
+                                    view = adapter.getView(i, null, dummyParent);
+                                }
+                                viewType = nextViewType;
+
+                                // Measure the next view
+                                measureView(view);
+
+                                // Add the height but if the view crosses the page
+                                // boundary we will put it to the next one.
+                                pageContentHeight += view.getMeasuredHeight();
+                                if (currentPage < 0 || pageContentHeight > mRenderPageHeight) {
+                                    pageContentHeight = view.getMeasuredHeight();
+                                    currentPage++;
+                                    // Done with the current page - finish it.
+                                    if (page != null) {
+                                        mPdfDocument.finishPage(page);
+                                    }
+                                    // If the page is requested, render it.
+                                    if (containsPage(pages, currentPage)) {
+                                        page = mPdfDocument.startPage(currentPage);
+                                        page.getCanvas().scale(scale, scale);
+                                        // Keep track which pages are written.
+                                        mWrittenPages.append(mWrittenPages.size(), currentPage);
+                                    } else {
+                                        page = null;
+                                    }
+                                }
+
+                                // If the current view is on a requested page, render it.
+                                if (page != null) {
+                                    // Layout an render the content.
+                                    view.layout(0, 0, view.getMeasuredWidth(),
+                                            view.getMeasuredHeight());
+                                    view.draw(page.getCanvas());
+                                    // Move the canvas for the next view.
+                                    page.getCanvas().translate(0, view.getHeight());
+                                }
+                            }
+
+                            // Done with the last page.
+                            if (page != null) {
+                                mPdfDocument.finishPage(page);
+                            }
+
+                            // Write the data and return success or failure.
+                            try {
+                                mPdfDocument.writeTo(new FileOutputStream(
+                                        destination.getFileDescriptor()));
+                                // Compute which page ranges were written based on
+                                // the bookkeeping we maintained.
+                                PageRange[] pageRanges = computeWrittenPageRanges(mWrittenPages);
+                                callback.onWriteFinished(pageRanges);
+                            } catch (IOException ioe) {
+                                callback.onWriteFailed(null);
+                            } finally {
+                                mPdfDocument.close();
+                            }
+
+                            return null;
+                        }
+
+                        @Override
+                        protected void onCancelled(Void result) {
+                            // Task was cancelled, report that.
+                            callback.onWriteCancelled();
+                            mPdfDocument.close();
+                        }
+                    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+                }
+
+                private void measureView(View view) {
+                    final int widthMeasureSpec = ViewGroup.getChildMeasureSpec(
+                            MeasureSpec.makeMeasureSpec(mRenderPageWidth,
+                            MeasureSpec.EXACTLY), 0, view.getLayoutParams().width);
+                    final int heightMeasureSpec = ViewGroup.getChildMeasureSpec(
+                            MeasureSpec.makeMeasureSpec(mRenderPageHeight,
+                            MeasureSpec.EXACTLY), 0, view.getLayoutParams().height);
+                    view.measure(widthMeasureSpec, heightMeasureSpec);
+                }
+
+                private PageRange[] computeWrittenPageRanges(SparseIntArray writtenPages) {
+                    List<PageRange> pageRanges = new ArrayList<PageRange>();
+
+                    int start = -1;
+                    int end = -1;
+                    final int writtenPageCount = writtenPages.size();
+                    for (int i = 0; i < writtenPageCount; i++) {
+                        if (start < 0) {
+                            start = writtenPages.valueAt(i);
+                        }
+                        int oldEnd = end = start;
+                        while (i < writtenPageCount && (end - oldEnd) <= 1) {
+                            oldEnd = end;
+                            end = writtenPages.valueAt(i);
+                            i++;
+                        }
+                        PageRange pageRange = new PageRange(start, end);
+                        pageRanges.add(pageRange);
+                        start = end = -1;
+                    }
+
+                    PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
+                    pageRanges.toArray(pageRangesArray);
+                    return pageRangesArray;
+                }
+
+                private boolean containsPage(PageRange[] pageRanges, int page) {
+                    final int pageRangeCount = pageRanges.length;
+                    for (int i = 0; i < pageRangeCount; i++) {
+                        if (pageRanges[i].getStart() <= page
+                                && pageRanges[i].getEnd() >= page) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+        }, null);
+    }
+
+    private List<MotoGpStatItem> loadMotoGpStats() {
+        String[] years = getResources().getStringArray(R.array.motogp_years);
+        String[] champions = getResources().getStringArray(R.array.motogp_champions);
+        String[] constructors = getResources().getStringArray(R.array.motogp_constructors);
+
+        List<MotoGpStatItem> items = new ArrayList<MotoGpStatItem>();
+
+        final int itemCount = years.length;
+        for (int i = 0; i < itemCount; i++) {
+            MotoGpStatItem item = new MotoGpStatItem();
+            item.year = years[i];
+            item.champion = champions[i];
+            item.constructor = constructors[i];
+            items.add(item);
+        }
+
+        return items;
+    }
+
+    private static final class MotoGpStatItem {
+        String year;
+        String champion;
+        String constructor;
+    }
+
+    private class MotoGpStatAdapter extends BaseAdapter {
+        private final List<MotoGpStatItem> mItems;
+        private final LayoutInflater mInflater;
+
+        public MotoGpStatAdapter(List<MotoGpStatItem> items, LayoutInflater inflater) {
+            mItems = items;
+            mInflater = inflater;
+        }
+
+        public List<MotoGpStatItem> cloneItems() {
+            return new ArrayList<MotoGpStatItem>(mItems);
+        }
+
+        @Override
+        public int getCount() {
+            return mItems.size();
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return mItems.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = mInflater.inflate(R.layout.motogp_stat_item, parent, false);
+            }
+
+            MotoGpStatItem item = (MotoGpStatItem) getItem(position);
+
+            TextView yearView = (TextView) convertView.findViewById(R.id.year);
+            yearView.setText(item.year);
+
+            TextView championView = (TextView) convertView.findViewById(R.id.champion);
+            championView.setText(item.champion);
+
+            TextView constructorView = (TextView) convertView.findViewById(R.id.constructor);
+            constructorView.setText(item.constructor);
+
+            return convertView;
+        }
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlFromScreen.java b/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlFromScreen.java
new file mode 100644
index 0000000..55c98ff
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlFromScreen.java
@@ -0,0 +1,93 @@
+/*
+ * 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.apis.app;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.print.PrintManager;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import com.example.android.apis.R;
+
+/**
+ * This class demonstrates how to implement HTML content printing
+ * from a {@link WebView} which is shown on the screen.
+ * <p>
+ * This activity shows a simple HTML content in a {@link WebView}
+ * and allows the user to print that content via an action in the
+ * action bar. The shown {@link WebView} is doing the printing.
+ * </p>
+ *
+ * @see PrintManager
+ * @see WebView
+ */
+public class PrintHtmlFromScreen extends Activity {
+
+    private WebView mWebView;
+
+    private boolean mDataLoaded;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.print_html_from_screen);
+        mWebView = (WebView) findViewById(R.id.web_view);
+
+        // Important: Only enable the print option after the page is loaded.
+        mWebView.setWebViewClient(new WebViewClient() {
+            @Override
+            public void onPageFinished(WebView view, String url) {
+                // Data loaded, so now we want to show the print option.
+                mDataLoaded = true;
+                invalidateOptionsMenu();
+            }
+        });
+
+        // Load an HTML page.
+        mWebView.loadUrl("file:///android_res/raw/motogp_stats.html");
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        if (mDataLoaded) {
+            getMenuInflater().inflate(R.menu.print_custom_content, menu);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.menu_print) {
+            print();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void print() {
+        // Get the print manager.
+        PrintManager printManager = (PrintManager) getSystemService(
+                Context.PRINT_SERVICE);
+        // Pass in the ViewView's document adapter.
+        printManager.print("MotoGP stats", mWebView.createPrintDocumentAdapter(), null);
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlOffScreen.java b/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlOffScreen.java
new file mode 100644
index 0000000..9c239b8
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/app/PrintHtmlOffScreen.java
@@ -0,0 +1,132 @@
+/*
+ * 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.apis.app;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintManager;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import com.example.android.apis.R;
+
+/**
+ * This class demonstrates how to implement HTML content printing
+ * from a {@link WebView} which is not shown on the screen.
+ * <p>
+ * This activity shows a text prompt and when the user chooses the
+ * print option from the overflow menu an HTML page with content that
+ * is not on the screen is printed via an off-screen {@link WebView}.
+ * </p>
+ *
+ * @see PrintManager
+ * @see WebView
+ */
+public class PrintHtmlOffScreen extends Activity {
+
+    private WebView mWebView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.print_html_off_screen);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        getMenuInflater().inflate(R.menu.print_custom_content, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.menu_print) {
+            print();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void print() {
+        // Create a WebView and hold on to it as the printing will start when
+        // load completes and we do not want the WbeView to be garbage collected.
+        mWebView = new WebView(this);
+
+        // Important: Only after the page is loaded we will do the print.
+        mWebView.setWebViewClient(new WebViewClient() {
+            @Override
+            public void onPageFinished(WebView view, String url) {
+              doPrint();
+            }
+        });
+
+        // Load an HTML page.
+        mWebView.loadUrl("file:///android_res/raw/motogp_stats.html");
+    }
+
+    private void doPrint() {
+        // Get the print manager.
+        PrintManager printManager = (PrintManager) getSystemService(
+                Context.PRINT_SERVICE);
+
+        // Create a wrapper PrintDocumentAdapter to clean up when done.
+        PrintDocumentAdapter adapter = new PrintDocumentAdapter() {
+            private final PrintDocumentAdapter mWrappedInstance =
+                    mWebView.createPrintDocumentAdapter();
+
+            @Override
+            public void onStart() {
+                mWrappedInstance.onStart();
+            }
+
+            @Override
+            public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+                    CancellationSignal cancellationSignal, LayoutResultCallback callback,
+                    Bundle extras) {
+                mWrappedInstance.onLayout(oldAttributes, newAttributes, cancellationSignal,
+                        callback, extras);
+            }
+
+            @Override
+            public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
+                    CancellationSignal cancellationSignal, WriteResultCallback callback) {
+                mWrappedInstance.onWrite(pages, destination, cancellationSignal, callback);
+            }
+
+            @Override
+            public void onFinish() {
+                mWrappedInstance.onFinish();
+                // Intercept the finish call to know when printing is done
+                // and destroy the WebView as it is expensive to keep around.
+                mWebView.destroy();
+                mWebView = null;
+            }
+        };
+
+        // Pass in the ViewView's document adapter.
+        printManager.print("MotoGP stats", adapter, null);
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/content/TextUndoActivity.java b/samples/ApiDemos/src/com/example/android/apis/content/TextUndoActivity.java
new file mode 100644
index 0000000..6b9dc8e
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/content/TextUndoActivity.java
@@ -0,0 +1,73 @@
+/*
+ * 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.apis.content;
+
+import android.app.Activity;
+//import android.content.UndoManager;
+import android.os.Parcelable;
+import android.view.View;
+import android.widget.Button;
+import com.example.android.apis.R;
+
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Simple example of using an UndoManager for editing text in a TextView.
+ */
+public class TextUndoActivity extends Activity {
+    //UndoManager mUndoManager;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        /*
+        mUndoManager = new UndoManager();
+        if (savedInstanceState != null) {
+            Parcelable p = savedInstanceState.getParcelable("undo");
+            if (p != null) {
+                mUndoManager.restoreInstanceState(p);
+            }
+        }
+        */
+
+        setContentView(R.layout.text_undo);
+
+        /*
+        ((TextView)findViewById(R.id.text)).setUndoManager(mUndoManager, "text");
+        ((Button)findViewById(R.id.undo)).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mUndoManager.undo(null, 1);
+            }
+        });
+        ((Button)findViewById(R.id.redo)).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mUndoManager.redo(null, 1);
+            }
+        });
+        */
+     }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        //outState.putParcelable("undo", mUndoManager.saveInstanceState());
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java b/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java
index c3c8a6c..a863014 100644
--- a/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java
+++ b/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java
@@ -26,6 +26,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.util.AttributeSet;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
@@ -87,9 +88,6 @@
     /** Is fading mode enabled? */
     boolean mFading;
 
-    /** The index of the current color to use. */
-    int mColorIndex;
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -104,10 +102,10 @@
         // the contents of the bitmap.
         if (savedInstanceState != null) {
             mFading = savedInstanceState.getBoolean("fading", true);
-            mColorIndex = savedInstanceState.getInt("color", 0);
+            mView.mColorIndex = savedInstanceState.getInt("color", 0);
         } else {
             mFading = true;
-            mColorIndex = 0;
+            mView.mColorIndex = 0;
         }
     }
 
@@ -161,7 +159,7 @@
         // Save away the fading state to restore if needed later.  Note that
         // we do not currently save the contents of the display.
         outState.putBoolean("fading", mFading);
-        outState.putInt("color", mColorIndex);
+        outState.putInt("color", mView.mColorIndex);
     }
 
     @Override
@@ -225,9 +223,9 @@
      *
      * It handles all of the input events and drawing functions.
      */
-    class PaintView extends View {
+    public static class PaintView extends View {
         private static final int FADE_ALPHA = 0x06;
-        private static final int MAX_FADE_STEPS = 256 / FADE_ALPHA + 4;
+        private static final int MAX_FADE_STEPS = 256 / (FADE_ALPHA/2) + 4;
         private static final int TRACKBALL_SCALE = 10;
 
         private static final int SPLAT_VECTORS = 40;
@@ -235,21 +233,31 @@
         private final Random mRandom = new Random();
         private Bitmap mBitmap;
         private Canvas mCanvas;
-        private final Paint mPaint;
-        private final Paint mFadePaint;
+        private final Paint mPaint = new Paint();
+        private final Paint mFadePaint = new Paint();
         private float mCurX;
         private float mCurY;
         private int mOldButtonState;
         private int mFadeSteps = MAX_FADE_STEPS;
 
+        /** The index of the current color to use. */
+        int mColorIndex;
+
         public PaintView(Context c) {
             super(c);
+            init();
+        }
+
+        public PaintView(Context c, AttributeSet attrs) {
+            super(c, attrs);
+            init();
+        }
+
+        private void init() {
             setFocusable(true);
 
-            mPaint = new Paint();
             mPaint.setAntiAlias(true);
 
-            mFadePaint = new Paint();
             mFadePaint.setColor(BACKGROUND_COLOR);
             mFadePaint.setAlpha(FADE_ALPHA);
         }
@@ -273,6 +281,31 @@
             }
         }
 
+        public void text(String text) {
+            if (mBitmap != null) {
+                final int width = mBitmap.getWidth();
+                final int height = mBitmap.getHeight();
+                mPaint.setColor(COLORS[mColorIndex]);
+                mPaint.setAlpha(255);
+                int size = height;
+                mPaint.setTextSize(size);
+                Rect bounds = new Rect();
+                mPaint.getTextBounds(text, 0, text.length(), bounds);
+                int twidth = bounds.width();
+                twidth += (twidth/4);
+                if (twidth > width) {
+                    size = (size*width)/twidth;
+                    mPaint.setTextSize(size);
+                    mPaint.getTextBounds(text, 0, text.length(), bounds);
+                }
+                Paint.FontMetrics fm = mPaint.getFontMetrics();
+                mCanvas.drawText(text, (width-bounds.width())/2,
+                        ((height-size)/2) - fm.ascent, mPaint);
+                mFadeSteps = 0;
+                invalidate();
+            }
+        }
+
         @Override
         protected void onSizeChanged(int w, int h, int oldw, int oldh) {
             int curW = mBitmap != null ? mBitmap.getWidth() : 0;
diff --git a/samples/ApiDemos/src/com/example/android/apis/hardware/ConsumerIr.java b/samples/ApiDemos/src/com/example/android/apis/hardware/ConsumerIr.java
new file mode 100644
index 0000000..c0ae960
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/hardware/ConsumerIr.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 20013The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hardware;
+
+// Need the following import to get access to the app resources, since this
+// class is in a sub-package.
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.hardware.ConsumerIrManager;
+import android.view.View;
+import android.widget.TextView;
+import android.util.Log;
+
+import com.example.android.apis.R;
+
+/**
+ * App that transmit an IR code
+ *
+ * <p>This demonstrates the {@link android.hardware.ConsumerIrManager android.hardware.ConsumerIrManager} class.
+ *
+ * <h4>Demo</h4>
+ * Hardware / Consumer IR
+ *
+ * <h4>Source files</h4>
+ * <table class="LinkTable">
+ *         <tr>
+ *             <td>src/com.example.android.apis/hardware/ConsumerIr.java</td>
+ *             <td>Consumer IR demo</td>
+ *         </tr>
+ *         <tr>
+ *             <td>res/any/layout/consumer_ir.xml</td>
+ *             <td>Defines contents of the screen</td>
+ *         </tr>
+ * </table>
+ */
+public class ConsumerIr extends Activity {
+    private static final String TAG = "ConsumerIrTest";
+    TextView mFreqsText;
+    ConsumerIrManager mCIR;
+
+    /**
+     * Initialization of the Activity after it is first created.  Must at least
+     * call {@link android.app.Activity#setContentView setContentView()} to
+     * describe what is to be displayed in the screen.
+     */
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        // Be sure to call the super class.
+        super.onCreate(savedInstanceState);
+
+        // Get a reference to the ConsumerIrManager
+        mCIR = (ConsumerIrManager)getSystemService(Context.CONSUMER_IR_SERVICE);
+
+        // See assets/res/any/layout/consumer_ir.xml for this
+        // view layout definition, which is being set here as
+        // the content of our screen.
+        setContentView(R.layout.consumer_ir);
+
+        // Set the OnClickListener for the button so we see when it's pressed.
+        findViewById(R.id.send_button).setOnClickListener(mSendClickListener);
+        findViewById(R.id.get_freqs_button).setOnClickListener(mGetFreqsClickListener);
+        mFreqsText = (TextView) findViewById(R.id.freqs_text);
+    }
+
+    View.OnClickListener mSendClickListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            if (!mCIR.hasIrEmitter()) {
+                Log.e(TAG, "No IR Emitter found\n");
+                return;
+            }
+
+            // A pattern of alternating series of carrier on and off periods measured in
+            // microseconds.
+            int[] pattern = {1901, 4453, 625, 1614, 625, 1588, 625, 1614, 625, 442, 625, 442, 625,
+                468, 625, 442, 625, 494, 572, 1614, 625, 1588, 625, 1614, 625, 494, 572, 442, 651,
+                442, 625, 442, 625, 442, 625, 1614, 625, 1588, 651, 1588, 625, 442, 625, 494, 598,
+                442, 625, 442, 625, 520, 572, 442, 625, 442, 625, 442, 651, 1588, 625, 1614, 625,
+                1588, 625, 1614, 625, 1588, 625, 48958};
+
+            // transmit the pattern at 38.4KHz
+            mCIR.transmit(38400, pattern);
+        }
+    };
+
+    View.OnClickListener mGetFreqsClickListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            StringBuilder b = new StringBuilder();
+
+            if (!mCIR.hasIrEmitter()) {
+                mFreqsText.setText("No IR Emitter found!");
+                Log.e(TAG, "No IR Emitter found!\n");
+                return;
+            }
+
+            // Get the available carrier frequency ranges
+            ConsumerIrManager.CarrierFrequencyRange[] freqs = mCIR.getCarrierFrequencies();
+            b.append("IR Carrier Frequencies:\n");
+            for (ConsumerIrManager.CarrierFrequencyRange range : freqs) {
+                b.append(String.format("    %d - %d\n", range.getMinFrequency(),
+                            range.getMaxFrequency()));
+            }
+            mFreqsText.setText(b.toString());
+        }
+    };
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserNavActivity.java b/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserNavActivity.java
new file mode 100644
index 0000000..2c5f7bf
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserNavActivity.java
@@ -0,0 +1,266 @@
+/*
+ * 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.apis.view;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.Activity;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ScrollView;
+import android.widget.SearchView;
+import android.widget.SeekBar;
+import android.widget.ShareActionProvider;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.SearchView.OnQueryTextListener;
+
+import com.example.android.apis.R;
+
+/**
+ * This activity demonstrates how to use system UI flags to implement
+ * a content browser style of UI (such as a book reader) that hides the
+ * nav bar as well as the status bar.
+ */
+public class ContentBrowserNavActivity extends Activity
+        implements OnQueryTextListener, ActionBar.TabListener {
+
+    /**
+     * Implementation of a view for displaying immersive content, using system UI
+     * flags to transition in and out of modes where the user is focused on that
+     * content.
+     */
+//BEGIN_INCLUDE(content)
+    public static class Content extends ScrollView
+            implements View.OnSystemUiVisibilityChangeListener, View.OnClickListener {
+        TextView mText;
+        TextView mTitleView;
+        SeekBar mSeekView;
+        boolean mNavVisible;
+        int mBaseSystemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+        int mLastSystemUiVis;
+
+        Runnable mNavHider = new Runnable() {
+            @Override public void run() {
+                setNavVisibility(false);
+            }
+        };
+
+        public Content(Context context, AttributeSet attrs) {
+            super(context, attrs);
+    
+            mText = new TextView(context);
+            mText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
+            mText.setText(context.getString(R.string.alert_dialog_two_buttons2ultra_msg));
+            mText.setClickable(false);
+            mText.setOnClickListener(this);
+            mText.setTextIsSelectable(true);
+            addView(mText, new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+            setOnSystemUiVisibilityChangeListener(this);
+        }
+
+        public void init(TextView title, SeekBar seek) {
+            // This called by the containing activity to supply the surrounding
+            // state of the content browser that it will interact with.
+            mTitleView = title;
+            mSeekView = seek;
+            setNavVisibility(true);
+        }
+
+        @Override public void onSystemUiVisibilityChange(int visibility) {
+            // Detect when we go out of low-profile mode, to also go out
+            // of full screen.  We only do this when the low profile mode
+            // is changing from its last state, and turning off.
+            int diff = mLastSystemUiVis ^ visibility;
+            mLastSystemUiVis = visibility;
+            if ((diff&SYSTEM_UI_FLAG_LOW_PROFILE) != 0
+                    && (visibility&SYSTEM_UI_FLAG_LOW_PROFILE) == 0) {
+                setNavVisibility(true);
+            }
+        }
+
+        @Override protected void onWindowVisibilityChanged(int visibility) {
+            super.onWindowVisibilityChanged(visibility);
+
+            // When we become visible, we show our navigation elements briefly
+            // before hiding them.
+            setNavVisibility(true);
+            getHandler().postDelayed(mNavHider, 2000);
+        }
+
+        @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+            super.onScrollChanged(l, t, oldl, oldt);
+
+            // When the user scrolls, we hide navigation elements.
+            setNavVisibility(false);
+        }
+
+        @Override public void onClick(View v) {
+            // When the user clicks, we toggle the visibility of navigation elements.
+            int curVis = getSystemUiVisibility();
+            setNavVisibility((curVis&SYSTEM_UI_FLAG_LOW_PROFILE) != 0);
+        }
+
+        void setBaseSystemUiVisibility(int visibility) {
+            mBaseSystemUiVisibility = visibility;
+        }
+
+        void setNavVisibility(boolean visible) {
+            int newVis = mBaseSystemUiVisibility;
+            if (!visible) {
+                newVis |= SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_FULLSCREEN
+                        | SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_IMMERSIVE;
+            }
+            final boolean changed = newVis == getSystemUiVisibility();
+
+            // Unschedule any pending event to hide navigation if we are
+            // changing the visibility, or making the UI visible.
+            if (changed || visible) {
+                Handler h = getHandler();
+                if (h != null) {
+                    h.removeCallbacks(mNavHider);
+                }
+            }
+
+            // Set the new desired visibility.
+            setSystemUiVisibility(newVis);
+            mTitleView.setVisibility(visible ? VISIBLE : INVISIBLE);
+            mSeekView.setVisibility(visible ? VISIBLE : INVISIBLE);
+        }
+    }
+//END_INCLUDE(content)
+
+    Content mContent;
+
+    public ContentBrowserNavActivity() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
+
+        setContentView(R.layout.content_browser_nav);
+        mContent = (Content)findViewById(R.id.content);
+        mContent.init((TextView)findViewById(R.id.title),
+                (SeekBar)findViewById(R.id.seekbar));
+
+        ActionBar bar = getActionBar();
+        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));
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.content_actions, menu);
+        SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
+        searchView.setOnQueryTextListener(this);
+
+        // Set file with share history to the provider and set the share intent.
+        MenuItem actionItem = menu.findItem(R.id.menu_item_share_action_provider_action_bar);
+        ShareActionProvider actionProvider = (ShareActionProvider) actionItem.getActionProvider();
+        actionProvider.setShareHistoryFileName(ShareActionProvider.DEFAULT_SHARE_HISTORY_FILE_NAME);
+        // Note that you can set/change the intent any time,
+        // say when the user has selected an image.
+        Intent shareIntent = new Intent(Intent.ACTION_SEND);
+        shareIntent.setType("image/*");
+        Uri uri = Uri.fromFile(getFileStreamPath("shared.png"));
+        shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
+        actionProvider.setShareIntent(shareIntent);
+        return true;
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    /**
+     * This method is declared in the menu.
+     */
+    public void onSort(MenuItem item) {
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.show_tabs:
+                getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+                item.setChecked(true);
+                return true;
+            case R.id.hide_tabs:
+                getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+                item.setChecked(true);
+                return true;
+            case R.id.stable_layout:
+                item.setChecked(!item.isChecked());
+                mContent.setBaseSystemUiVisibility(item.isChecked()
+                        ? View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                        : View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+                return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onQueryTextChange(String newText) {
+        return true;
+    }
+
+    @Override
+    public boolean onQueryTextSubmit(String query) {
+        Toast.makeText(this, "Searching for: " + query + "...", Toast.LENGTH_SHORT).show();
+        return true;
+    }
+
+    @Override
+    public void onTabSelected(Tab tab, FragmentTransaction ft) {
+    }
+
+    @Override
+    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
+    }
+
+    @Override
+    public void onTabReselected(Tab tab, FragmentTransaction ft) {
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/GameActivity.java b/samples/ApiDemos/src/com/example/android/apis/view/GameActivity.java
new file mode 100644
index 0000000..a025427
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/GameActivity.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.apis.view;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.Activity;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.SearchView;
+import android.widget.SeekBar;
+import android.widget.ShareActionProvider;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.SearchView.OnQueryTextListener;
+
+import com.example.android.apis.R;
+import com.example.android.apis.graphics.TouchPaint;
+
+/**
+ * This activity demonstrates how to use the system UI flags to
+ * implement an immersive game.
+ */
+public class GameActivity extends Activity {
+
+    /**
+     * Implementation of a view for the game, filling the entire screen.
+     */
+//BEGIN_INCLUDE(content)
+    public static class Content extends TouchPaint.PaintView implements
+            View.OnSystemUiVisibilityChangeListener, View.OnClickListener {
+        Activity mActivity;
+        Button mPlayButton;
+        boolean mPaused;
+        int mLastSystemUiVis;
+        boolean mUpdateSystemUi;
+
+        Runnable mFader = new Runnable() {
+            @Override public void run() {
+                fade();
+                if (mUpdateSystemUi) {
+                    updateNavVisibility();
+                }
+                if (!mPaused) {
+                    getHandler().postDelayed(mFader, 1000/30);
+                }
+            }
+        };
+
+        public Content(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            setOnSystemUiVisibilityChangeListener(this);
+        }
+
+        public void init(Activity activity, Button playButton) {
+            // This called by the containing activity to supply the surrounding
+            // state of the game that it will interact with.
+            mActivity = activity;
+            mPlayButton = playButton;
+            mPlayButton.setOnClickListener(this);
+            setGamePaused(true);
+        }
+
+        @Override public void onSystemUiVisibilityChange(int visibility) {
+            // Detect when we go out of nav-hidden mode, to reset back to having
+            // it hidden; our game wants those elements to stay hidden as long
+            // as it is being played and stay shown when paused.
+            int diff = mLastSystemUiVis ^ visibility;
+            mLastSystemUiVis = visibility;
+            if (!mPaused && (diff&SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+                    && (visibility&SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
+                // We are running and the system UI navigation has become
+                // shown...  we want it to remain hidden, so update our system
+                // UI state at the next game loop.
+                mUpdateSystemUi = true;
+            }
+        }
+
+        @Override protected void onWindowVisibilityChanged(int visibility) {
+            super.onWindowVisibilityChanged(visibility);
+
+            // When we become visible or invisible, play is paused.
+            setGamePaused(true);
+        }
+
+        @Override
+        public void onWindowFocusChanged(boolean hasWindowFocus) {
+            super.onWindowFocusChanged(hasWindowFocus);
+
+            // When we become visible or invisible, play is paused.
+            // Optional: pause game when window loses focus.  This will cause it to
+            // pause, for example, when the notification shade is pulled down.
+            if (!hasWindowFocus) {
+                //setGamePaused(true);
+            }
+        }
+
+        @Override public void onClick(View v) {
+            if (v == mPlayButton) {
+                // Clicking on the play/pause button toggles its state.
+                setGamePaused(!mPaused);
+            }
+        }
+
+        void setGamePaused(boolean paused) {
+            mPaused = paused;
+            mPlayButton.setText(paused ? R.string.play : R.string.pause);
+            setKeepScreenOn(!paused);
+            updateNavVisibility();
+            Handler h = getHandler();
+            if (h != null) {
+                getHandler().removeCallbacks(mFader);
+                if (!paused) {
+                    mFader.run();
+                    text("Draw!");
+                }
+            }
+        }
+
+        void updateNavVisibility() {
+            int newVis = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | SYSTEM_UI_FLAG_LAYOUT_STABLE;
+            if (!mPaused) {
+                newVis |= SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_FULLSCREEN
+                        | SYSTEM_UI_FLAG_HIDE_NAVIGATION  | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+            }
+
+            // Set the new desired visibility.
+            setSystemUiVisibility(newVis);
+            mUpdateSystemUi = false;
+        }
+    }
+//END_INCLUDE(content)
+
+    Content mContent;
+
+    public GameActivity() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.game);
+        mContent = (Content)findViewById(R.id.content);
+        mContent.init(this, (Button)findViewById(R.id.play));
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+
+        // Pause game when its activity is paused.
+        mContent.setGamePaused(true);
+    }
+}
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/SystemUIModes.java b/samples/ApiDemos/src/com/example/android/apis/view/SystemUIModes.java
index 730534a..8197e05 100644
--- a/samples/ApiDemos/src/com/example/android/apis/view/SystemUIModes.java
+++ b/samples/ApiDemos/src/com/example/android/apis/view/SystemUIModes.java
@@ -136,6 +136,30 @@
         win.setAttributes(winParams);
     }
 
+    private void setTranslucentStatus(boolean on) {
+        Window win = getWindow();
+        WindowManager.LayoutParams winParams = win.getAttributes();
+        final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+        if (on) {
+            winParams.flags |=  bits;
+        } else {
+            winParams.flags &= ~bits;
+        }
+        win.setAttributes(winParams);
+    }
+
+    private void setTranslucentNavigation(boolean on) {
+        Window win = getWindow();
+        WindowManager.LayoutParams winParams = win.getAttributes();
+        final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+        if (on) {
+            winParams.flags |=  bits;
+        } else {
+            winParams.flags &= ~bits;
+        }
+        win.setAttributes(winParams);
+    }
+
     private String getDisplaySize() {
         DisplayMetrics dm = getResources().getDisplayMetrics();
         return String.format("DisplayMetrics = (%d x %d)", dm.widthPixels, dm.heightPixels);
@@ -151,9 +175,10 @@
 
     static int TOAST_LENGTH = 500;
     IV mImage;
-    CheckBox[] mCheckControls = new CheckBox[6];
+    CheckBox[] mCheckControls = new CheckBox[8];
     int[] mCheckFlags = new int[] { View.SYSTEM_UI_FLAG_LOW_PROFILE,
             View.SYSTEM_UI_FLAG_FULLSCREEN, View.SYSTEM_UI_FLAG_HIDE_NAVIGATION,
+            View.SYSTEM_UI_FLAG_IMMERSIVE, View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY,
             View.SYSTEM_UI_FLAG_LAYOUT_STABLE, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,
             View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
     };
@@ -179,9 +204,11 @@
         mCheckControls[0] = (CheckBox) findViewById(R.id.modeLowProfile);
         mCheckControls[1] = (CheckBox) findViewById(R.id.modeFullscreen);
         mCheckControls[2] = (CheckBox) findViewById(R.id.modeHideNavigation);
-        mCheckControls[3] = (CheckBox) findViewById(R.id.layoutStable);
-        mCheckControls[4] = (CheckBox) findViewById(R.id.layoutFullscreen);
-        mCheckControls[5] = (CheckBox) findViewById(R.id.layoutHideNavigation);
+        mCheckControls[3] = (CheckBox) findViewById(R.id.modeImmersive);
+        mCheckControls[4] = (CheckBox) findViewById(R.id.modeImmersiveSticky);
+        mCheckControls[5] = (CheckBox) findViewById(R.id.layoutStable);
+        mCheckControls[6] = (CheckBox) findViewById(R.id.layoutFullscreen);
+        mCheckControls[7] = (CheckBox) findViewById(R.id.layoutHideNavigation);
         for (int i=0; i<mCheckControls.length; i++) {
             mCheckControls[i].setOnCheckedChangeListener(checkChangeListener);
         }
@@ -201,6 +228,22 @@
                     }
                 }
         );
+        ((CheckBox) findViewById(R.id.windowTranslucentStatus)).setOnCheckedChangeListener(
+                new CompoundButton.OnCheckedChangeListener() {
+                    @Override
+                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                        setTranslucentStatus(isChecked);
+                    }
+                }
+        );
+        ((CheckBox) findViewById(R.id.windowTranslucentNav)).setOnCheckedChangeListener(
+                new CompoundButton.OnCheckedChangeListener() {
+                    @Override
+                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                        setTranslucentNavigation(isChecked);
+                    }
+                }
+        );
         ((CheckBox) findViewById(R.id.windowHideActionBar)).setOnCheckedChangeListener(
                 new CompoundButton.OnCheckedChangeListener() {
                     @Override
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/TranslucentBarsActivity.java b/samples/ApiDemos/src/com/example/android/apis/view/TranslucentBarsActivity.java
new file mode 100644
index 0000000..98c11d1
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/TranslucentBarsActivity.java
@@ -0,0 +1,36 @@
+/*
+ * 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.apis.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+import com.example.android.apis.R;
+
+/**
+ * This activity demonstrates a simple implementation of displaying
+ * content with translucent system UI bars.
+ */
+public class TranslucentBarsActivity extends Activity {
+    public TranslucentBarsActivity() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.translucent_bars);
+    }
+}
diff --git a/samples/HelloActivity/src/com/example/android/helloactivity/HelloActivity.java b/samples/HelloActivity/src/com/example/android/helloactivity/HelloActivity.java
index f983d7a..f4babe7 100644
--- a/samples/HelloActivity/src/com/example/android/helloactivity/HelloActivity.java
+++ b/samples/HelloActivity/src/com/example/android/helloactivity/HelloActivity.java
@@ -37,17 +37,6 @@
         // in res/layout/hello_activity.xml
         View view = getLayoutInflater().inflate(R.layout.hello_activity, null);
         setContentView(view);
-
-        WindowManager.LayoutParams params = getWindow().getAttributes();
-        params.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-        getWindow().setAttributes(params);
-        view.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
-            @Override public void onSystemUiVisibilityChange(int visibility) {
-                WindowManager.LayoutParams params = getWindow().getAttributes();
-                params.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-                getWindow().setAttributes(params);
-            }
-        });
     }
 }
 
diff --git a/samples/RenderScript/Levels/src/com/android/rs/levels/LevelsRSActivity.java b/samples/RenderScript/Levels/src/com/android/rs/levels/LevelsRSActivity.java
index d63ee44..49076a5 100644
--- a/samples/RenderScript/Levels/src/com/android/rs/levels/LevelsRSActivity.java
+++ b/samples/RenderScript/Levels/src/com/android/rs/levels/LevelsRSActivity.java
@@ -22,6 +22,7 @@
 import android.graphics.Canvas;
 import android.os.Bundle;
 import android.graphics.SurfaceTexture;
+import android.view.Surface;
 import android.renderscript.Allocation;
 import android.renderscript.Matrix3f;
 import android.renderscript.RenderScript;
@@ -211,18 +212,22 @@
 
     @Override
     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
-        mOutPixelsAllocation.setSurfaceTexture(surface);
+        if (surface != null) {
+            mOutPixelsAllocation.setSurface(new Surface(surface));
+        }
         filter();
     }
 
     @Override
     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
-        mOutPixelsAllocation.setSurfaceTexture(surface);
+        if (surface != null) {
+            mOutPixelsAllocation.setSurface(new Surface(surface));
+        }
     }
 
     @Override
     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
-        mOutPixelsAllocation.setSurfaceTexture(null);
+        mOutPixelsAllocation.setSurface(null);
         return true;
     }
 
diff --git a/samples/Support4Demos/AndroidManifest.xml b/samples/Support4Demos/AndroidManifest.xml
index cc98540..46a4831 100644
--- a/samples/Support4Demos/AndroidManifest.xml
+++ b/samples/Support4Demos/AndroidManifest.xml
@@ -25,7 +25,7 @@
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
 
-    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17" />
+    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="19" />
 
     <!-- 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
@@ -321,6 +321,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".widget.ExploreByTouchHelperActivity"
+                  android:label="@string/explore_by_touch_helper_support">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <provider android:authorities="com.example.supportv4.content.sharingsupportprovider"
                   android:name=".content.SharingSupportProvider" />
 
diff --git a/samples/Support4Demos/res/drawable-hdpi/ic_drawer.png b/samples/Support4Demos/res/drawable-hdpi/ic_drawer_am.png
similarity index 100%
rename from samples/Support4Demos/res/drawable-hdpi/ic_drawer.png
rename to samples/Support4Demos/res/drawable-hdpi/ic_drawer_am.png
Binary files differ
diff --git a/samples/Support4Demos/res/drawable-mdpi/ic_drawer.png b/samples/Support4Demos/res/drawable-mdpi/ic_drawer_am.png
similarity index 100%
rename from samples/Support4Demos/res/drawable-mdpi/ic_drawer.png
rename to samples/Support4Demos/res/drawable-mdpi/ic_drawer_am.png
Binary files differ
diff --git a/samples/Support4Demos/res/drawable-xhdpi/ic_drawer.png b/samples/Support4Demos/res/drawable-xhdpi/ic_drawer_am.png
similarity index 100%
rename from samples/Support4Demos/res/drawable-xhdpi/ic_drawer.png
rename to samples/Support4Demos/res/drawable-xhdpi/ic_drawer_am.png
Binary files differ
diff --git a/samples/Support4Demos/res/drawable/ic_drawer.xml b/samples/Support4Demos/res/drawable/ic_drawer.xml
new file mode 100644
index 0000000..919540f
--- /dev/null
+++ b/samples/Support4Demos/res/drawable/ic_drawer.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_drawer_am"
+        android:autoMirrored="true">
+</bitmap>
+
diff --git a/samples/Support4Demos/res/layout/explore_by_touch_helper.xml b/samples/Support4Demos/res/layout/explore_by_touch_helper.xml
new file mode 100644
index 0000000..0b367a4
--- /dev/null
+++ b/samples/Support4Demos/res/layout/explore_by_touch_helper.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <view
+        class="com.example.android.supportv4.widget.ExploreByTouchHelperActivity$CustomView"
+        android:id="@+id/custom_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/Support4Demos/res/values/strings.xml b/samples/Support4Demos/res/values/strings.xml
index 9949ee0..ce41aaf 100644
--- a/samples/Support4Demos/res/values/strings.xml
+++ b/samples/Support4Demos/res/values/strings.xml
@@ -167,6 +167,13 @@
 
     <string name="sliding_pane_layout_summary">This activity illustrates the use of sliding panes. The content pane may be slid to one side on narrow devices to reveal the left pane used to select content. Sliding panes can be used to fit a UI intended for wider screens in a smaller space. Tapping the Action Bar\'s Up button at the left side of the bar will navigate up in the hierarchy, represented by the left pane. If you rotate the device to landscape mode, on most devices you will see that both panes fit together side by side with no sliding necessary.</string>
 
+    <!-- ExploreByTouchHelper -->
+
+    <string name="explore_by_touch_helper_support">Widget/Explore by Touch helper</string>
+    <string name="sample_item_a">Sample item A</string>
+    <string name="sample_item_b">Sample item B</string>
+
     <!-- ContentLoadingProgressBar -->
     <string name="content_loading_progress_bar">Widget/Content Loading Progress Bar</string>
+
 </resources>
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/ExploreByTouchHelperActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/ExploreByTouchHelperActivity.java
new file mode 100644
index 0000000..946de01
--- /dev/null
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/ExploreByTouchHelperActivity.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv4.widget;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.Paint.Style;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
+import android.support.v4.widget.ExploreByTouchHelper;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import com.example.android.supportv4.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This example shows how to use the {@link ExploreByTouchHelper} class in the
+ * Android support library to add accessibility support to a custom view that
+ * represents multiple logical items.
+ * <p>
+ * The {@link ExploreByTouchHelper} class wraps
+ * {@link AccessibilityNodeProviderCompat} and simplifies exposing information
+ * about a custom view's logical structure to accessibility services.
+ * <p>
+ * The custom view in this example is responsible for:
+ * <ul>
+ * <li>Creating a helper class that extends {@link ExploreByTouchHelper}
+ * <li>Setting the helper as the accessibility delegate using
+ * {@link ViewCompat#setAccessibilityDelegate}
+ * <li>Dispatching hover events to the helper in {@link View#dispatchHoverEvent}
+ * </ul>
+ * <p>
+ * The helper class implementation in this example is responsible for:
+ * <ul>
+ * <li>Mapping hover event coordinates to logical items
+ * <li>Exposing information about logical items to accessibility services
+ * <li>Handling accessibility actions
+ * <ul>
+ */
+public class ExploreByTouchHelperActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.explore_by_touch_helper);
+
+        final CustomView customView = (CustomView) findViewById(R.id.custom_view);
+
+        // Adds an item at the top-left quarter of the custom view.
+        customView.addItem(getString(R.string.sample_item_a), 0, 0, 0.5f, 0.5f);
+
+        // Adds an item at the bottom-right quarter of the custom view.
+        customView.addItem(getString(R.string.sample_item_b), 0.5f, 0.5f, 1, 1);
+    }
+
+    /**
+     * Simple custom view that draws rectangular items to the screen. Each item
+     * has a checked state that may be toggled by tapping on the item.
+     */
+    public static class CustomView extends View {
+        private static final int NO_ITEM = -1;
+
+        private final Paint mPaint = new Paint();
+        private final Rect mTempBounds = new Rect();
+        private final List<CustomItem> mItems = new ArrayList<CustomItem>();
+        private CustomViewTouchHelper mTouchHelper;
+
+        public CustomView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+
+            // Set up accessibility helper class.
+            mTouchHelper = new CustomViewTouchHelper(this);
+            ViewCompat.setAccessibilityDelegate(this, mTouchHelper);
+        }
+
+        @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+        @Override
+        public boolean dispatchHoverEvent(MotionEvent event) {
+            // Always attempt to dispatch hover events to accessibility first.
+            if (mTouchHelper.dispatchHoverEvent(event)) {
+                return true;
+            }
+
+            return super.dispatchHoverEvent(event);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    return true;
+                case MotionEvent.ACTION_UP:
+                    final int itemIndex = getItemIndexUnder(event.getX(), event.getY());
+                    if (itemIndex >= 0) {
+                        onItemClicked(itemIndex);
+                    }
+                    return true;
+            }
+
+            return super.onTouchEvent(event);
+        }
+
+        /**
+         * Adds an item to the custom view. The item is positioned relative to
+         * the custom view bounds and its descriptions is drawn at its center.
+         *
+         * @param description The item's description.
+         * @param top Top coordinate as a fraction of the parent height, range
+         *            is [0,1].
+         * @param left Left coordinate as a fraction of the parent width, range
+         *            is [0,1].
+         * @param bottom Bottom coordinate as a fraction of the parent height,
+         *            range is [0,1].
+         * @param right Right coordinate as a fraction of the parent width,
+         *            range is [0,1].
+         */
+        public void addItem(String description, float top, float left, float bottom, float right) {
+            final CustomItem item = new CustomItem();
+            item.bounds = new RectF(top, left, bottom, right);
+            item.description = description;
+            item.checked = false;
+            mItems.add(item);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            final Paint paint = mPaint;
+            final Rect bounds = mTempBounds;
+            final int height = getHeight();
+            final int width = getWidth();
+
+            for (CustomItem item : mItems) {
+                paint.setColor(item.checked ? Color.RED : Color.BLUE);
+                paint.setStyle(Style.FILL);
+                scaleRectF(item.bounds, bounds, width, height);
+                canvas.drawRect(bounds, paint);
+                paint.setColor(Color.WHITE);
+                paint.setTextAlign(Align.CENTER);
+                canvas.drawText(item.description, bounds.centerX(), bounds.centerY(), paint);
+            }
+        }
+
+        protected boolean onItemClicked(int index) {
+            final CustomItem item = getItem(index);
+            if (item == null) {
+                return false;
+            }
+
+            item.checked = !item.checked;
+            invalidate();
+
+            // Since the item's checked state is exposed to accessibility
+            // services through its AccessibilityNodeInfo, we need to invalidate
+            // the item's virtual view. At some point in the future, the
+            // framework will obtain an updated version of the virtual view.
+            mTouchHelper.invalidateVirtualView(index);
+
+            // We also need to let the framework know what type of event
+            // happened. Accessibility services may use this event to provide
+            // appropriate feedback to the user.
+            mTouchHelper.sendEventForVirtualView(index, AccessibilityEvent.TYPE_VIEW_CLICKED);
+
+            return true;
+        }
+
+        protected int getItemIndexUnder(float x, float y) {
+            final float scaledX = (x / getWidth());
+            final float scaledY = (y / getHeight());
+            final int n = mItems.size();
+
+            for (int i = 0; i < n; i++) {
+                final CustomItem item = mItems.get(i);
+                if (item.bounds.contains(scaledX, scaledY)) {
+                    return i;
+                }
+            }
+
+            return NO_ITEM;
+        }
+
+        protected CustomItem getItem(int index) {
+            if ((index < 0) || (index >= mItems.size())) {
+                return null;
+            }
+
+            return mItems.get(index);
+        }
+
+        protected static void scaleRectF(RectF in, Rect out, int width, int height) {
+            out.top = (int) (in.top * height);
+            out.bottom = (int) (in.bottom * height);
+            out.left = (int) (in.left * width);
+            out.right = (int) (in.right * width);
+        }
+
+        private class CustomViewTouchHelper extends ExploreByTouchHelper {
+            private final Rect mTempRect = new Rect();
+
+            public CustomViewTouchHelper(View forView) {
+                super(forView);
+            }
+
+            @Override
+            protected int getVirtualViewAt(float x, float y) {
+                // We also perform hit detection in onTouchEvent(), and we can
+                // reuse that logic here. This will ensure consistency whether
+                // accessibility is on or off.
+                final int index = getItemIndexUnder(x, y);
+                if (index == NO_ITEM) {
+                    return ExploreByTouchHelper.INVALID_ID;
+                }
+
+                return index;
+            }
+
+            @Override
+            protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+                // Since every item should be visible, and since we're mapping
+                // directly from item index to virtual view id, we can just add
+                // every available index in the item list.
+                final int n = mItems.size();
+                for (int i = 0; i < n; i++) {
+                    virtualViewIds.add(i);
+                }
+            }
+
+            @Override
+            protected void onPopulateEventForVirtualView(
+                    int virtualViewId, AccessibilityEvent event) {
+                final CustomItem item = getItem(virtualViewId);
+                if (item == null) {
+                    throw new IllegalArgumentException("Invalid virtual view id");
+                }
+
+                // The event must be populated with text, either using
+                // getText().add() or setContentDescription(). Since the item's
+                // description is displayed visually, we'll add it to the event
+                // text. If it was only used for accessibility, we would use
+                // setContentDescription().
+                event.getText().add(item.description);
+            }
+
+            @Override
+            protected void onPopulateNodeForVirtualView(
+                    int virtualViewId, AccessibilityNodeInfoCompat node) {
+                final CustomItem item = getItem(virtualViewId);
+                if (item == null) {
+                    throw new IllegalArgumentException("Invalid virtual view id");
+                }
+
+                // Node and event text and content descriptions are usually
+                // identical, so we'll use the exact same string as before.
+                node.setText(item.description);
+
+                // Reported bounds should be consistent with those used to draw
+                // the item in onDraw(). They should also be consistent with the
+                // hit detection performed in getVirtualViewAt() and
+                // onTouchEvent().
+                final Rect bounds = mTempRect;
+                final int height = getHeight();
+                final int width = getWidth();
+                scaleRectF(item.bounds, bounds, width, height);
+                node.setBoundsInParent(bounds);
+
+                // Since the user can tap an item, add the CLICK action. We'll
+                // need to handle this later in onPerformActionForVirtualView.
+                node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
+
+                // This item has a checked state.
+                node.setCheckable(true);
+                node.setChecked(item.checked);
+            }
+
+            @Override
+            protected boolean onPerformActionForVirtualView(
+                    int virtualViewId, int action, Bundle arguments) {
+                switch (action) {
+                    case AccessibilityNodeInfoCompat.ACTION_CLICK:
+                        // Click handling should be consistent with
+                        // onTouchEvent(). This ensures that the view works the
+                        // same whether accessibility is turned on or off.
+                        return onItemClicked(virtualViewId);
+                }
+
+                return false;
+            }
+
+        }
+
+        public static class CustomItem {
+            private String description;
+            private RectF bounds;
+            private boolean checked;
+        }
+    }
+}
diff --git a/samples/Vault/Android.mk b/samples/Vault/Android.mk
new file mode 100644
index 0000000..b4de298
--- /dev/null
+++ b/samples/Vault/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_PACKAGE_NAME := Vault
+
+include $(BUILD_PACKAGE)
diff --git a/samples/Vault/AndroidManifest.xml b/samples/Vault/AndroidManifest.xml
new file mode 100644
index 0000000..ded0515
--- /dev/null
+++ b/samples/Vault/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.vault">
+
+    <application
+        android:label="@string/app_label"
+        android:icon="@drawable/ic_lock_lock">
+        <provider
+            android:name=".VaultProvider"
+            android:authorities="com.example.android.vault.provider"
+            android:exported="true"
+            android:grantUriPermissions="true"
+            android:permission="android.permission.MANAGE_DOCUMENTS"
+            android:enabled="@bool/isAtLeastKitKat">
+            <intent-filter>
+                <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
+            </intent-filter>
+        </provider>
+    </application>
+
+</manifest>
diff --git a/samples/Vault/res/drawable-xhdpi/ic_lock_lock.png b/samples/Vault/res/drawable-xhdpi/ic_lock_lock.png
new file mode 100644
index 0000000..086a0ca
--- /dev/null
+++ b/samples/Vault/res/drawable-xhdpi/ic_lock_lock.png
Binary files differ
diff --git a/samples/Vault/res/values-v19/bool.xml b/samples/Vault/res/values-v19/bool.xml
new file mode 100644
index 0000000..dfa24e9
--- /dev/null
+++ b/samples/Vault/res/values-v19/bool.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <bool name="isAtLeastKitKat">true</bool>
+</resources>
diff --git a/samples/Vault/res/values/bool.xml b/samples/Vault/res/values/bool.xml
new file mode 100644
index 0000000..ed391d9
--- /dev/null
+++ b/samples/Vault/res/values/bool.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <bool name="isAtLeastKitKat">false</bool>
+</resources>
diff --git a/samples/Vault/res/values/strings.xml b/samples/Vault/res/values/strings.xml
new file mode 100644
index 0000000..e050d25
--- /dev/null
+++ b/samples/Vault/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="app_label">Vault</string>
+    <string name="info_software">Software-backed</string>
+    <string name="info_software_detail">Encryption key is software-backed, which is less secure.</string>
+</resources>
diff --git a/samples/Vault/src/com/example/android/vault/EncryptedDocument.java b/samples/Vault/src/com/example/android/vault/EncryptedDocument.java
new file mode 100644
index 0000000..59a22ba
--- /dev/null
+++ b/samples/Vault/src/com/example/android/vault/EncryptedDocument.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.vault;
+
+import static com.example.android.vault.VaultProvider.TAG;
+
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.net.ProtocolException;
+import java.nio.charset.StandardCharsets;
+import java.security.DigestException;
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Represents a single encrypted document stored on disk. Handles encryption,
+ * decryption, and authentication of the document when requested.
+ * <p>
+ * Encrypted documents are stored on disk as a magic number, followed by an
+ * encrypted metadata section, followed by an encrypted content section. The
+ * content section always starts at a specific offset {@link #CONTENT_OFFSET} to
+ * allow metadata updates without rewriting the entire file.
+ * <p>
+ * Each section is encrypted using AES-128 with a random IV, and authenticated
+ * with SHA-256. Data encrypted and authenticated like this can be safely stored
+ * on untrusted storage devices, as long as the keys are stored securely.
+ * <p>
+ * Not inherently thread safe.
+ */
+public class EncryptedDocument {
+
+    /**
+     * Magic number to identify file; "AVLT".
+     */
+    private static final int MAGIC_NUMBER = 0x41564c54;
+
+    /**
+     * Offset in file at which content section starts. Magic and metadata
+     * section must fully fit before this offset.
+     */
+    private static final int CONTENT_OFFSET = 4096;
+
+    private static final boolean DEBUG_METADATA = true;
+
+    /** Key length for AES-128 */
+    public static final int DATA_KEY_LENGTH = 16;
+    /** Key length for SHA-256 */
+    public static final int MAC_KEY_LENGTH = 32;
+
+    private final SecureRandom mRandom;
+    private final Cipher mCipher;
+    private final Mac mMac;
+
+    private final long mDocId;
+    private final File mFile;
+    private final SecretKey mDataKey;
+    private final SecretKey mMacKey;
+
+    /**
+     * Create an encrypted document.
+     *
+     * @param docId the expected {@link Document#COLUMN_DOCUMENT_ID} to be
+     *            validated when reading metadata.
+     * @param file location on disk where the encrypted document is stored. May
+     *            not exist yet.
+     */
+    public EncryptedDocument(long docId, File file, SecretKey dataKey, SecretKey macKey)
+            throws GeneralSecurityException {
+        mRandom = new SecureRandom();
+        mCipher = Cipher.getInstance("AES/CTR/NoPadding");
+        mMac = Mac.getInstance("HmacSHA256");
+
+        if (dataKey.getEncoded().length != DATA_KEY_LENGTH) {
+            throw new IllegalArgumentException("Expected data key length " + DATA_KEY_LENGTH);
+        }
+        if (macKey.getEncoded().length != MAC_KEY_LENGTH) {
+            throw new IllegalArgumentException("Expected MAC key length " + MAC_KEY_LENGTH);
+        }
+
+        mDocId = docId;
+        mFile = file;
+        mDataKey = dataKey;
+        mMacKey = macKey;
+    }
+
+    public File getFile() {
+        return mFile;
+    }
+
+    @Override
+    public String toString() {
+        return mFile.getName();
+    }
+
+    /**
+     * Decrypt and return parsed metadata section from this document.
+     *
+     * @throws DigestException if metadata fails MAC check, or if
+     *             {@link Document#COLUMN_DOCUMENT_ID} recorded in metadata is
+     *             unexpected.
+     */
+    public JSONObject readMetadata() throws IOException, GeneralSecurityException {
+        final RandomAccessFile f = new RandomAccessFile(mFile, "r");
+        try {
+            assertMagic(f);
+
+            // Only interested in metadata section
+            final ByteArrayOutputStream metaOut = new ByteArrayOutputStream();
+            readSection(f, metaOut);
+
+            final String rawMeta = metaOut.toString(StandardCharsets.UTF_8.name());
+            if (DEBUG_METADATA) {
+                Log.d(TAG, "Found metadata for " + mDocId + ": " + rawMeta);
+            }
+
+            final JSONObject meta = new JSONObject(rawMeta);
+
+            // Validate that metadata belongs to requested file
+            if (meta.getLong(Document.COLUMN_DOCUMENT_ID) != mDocId) {
+                throw new DigestException("Unexpected document ID");
+            }
+
+            return meta;
+
+        } catch (JSONException e) {
+            throw new IOException(e);
+        } finally {
+            f.close();
+        }
+    }
+
+    /**
+     * Decrypt and read content section of this document, writing it into the
+     * given pipe.
+     * <p>
+     * Pipe is left open, so caller is responsible for calling
+     * {@link ParcelFileDescriptor#close()} or
+     * {@link ParcelFileDescriptor#closeWithError(String)}.
+     *
+     * @param contentOut write end of a pipe.
+     * @throws DigestException if content fails MAC check. Some or all content
+     *             may have already been written to the pipe when the MAC is
+     *             validated.
+     */
+    public void readContent(ParcelFileDescriptor contentOut)
+            throws IOException, GeneralSecurityException {
+        final RandomAccessFile f = new RandomAccessFile(mFile, "r");
+        try {
+            assertMagic(f);
+
+            if (f.length() <= CONTENT_OFFSET) {
+                throw new IOException("Document has no content");
+            }
+
+            // Skip over metadata section
+            f.seek(CONTENT_OFFSET);
+            readSection(f, new FileOutputStream(contentOut.getFileDescriptor()));
+
+        } finally {
+            f.close();
+        }
+    }
+
+    /**
+     * Encrypt and write both the metadata and content sections of this
+     * document, reading the content from the given pipe. Internally uses
+     * {@link ParcelFileDescriptor#checkError()} to verify that content arrives
+     * without errors. Writes to temporary file to keep atomic view of contents,
+     * swapping into place only when write is successful.
+     * <p>
+     * Pipe is left open, so caller is responsible for calling
+     * {@link ParcelFileDescriptor#close()} or
+     * {@link ParcelFileDescriptor#closeWithError(String)}.
+     *
+     * @param contentIn read end of a pipe.
+     */
+    public void writeMetadataAndContent(JSONObject meta, ParcelFileDescriptor contentIn)
+            throws IOException, GeneralSecurityException {
+        // Write into temporary file to provide an atomic view of existing
+        // contents during write, and also to recover from failed writes.
+        final String tempName = mFile.getName() + ".tmp_" + Thread.currentThread().getId();
+        final File tempFile = new File(mFile.getParentFile(), tempName);
+
+        RandomAccessFile f = new RandomAccessFile(tempFile, "rw");
+        try {
+            // Truncate any existing data
+            f.setLength(0);
+
+            // Write content first to detect size
+            if (contentIn != null) {
+                f.seek(CONTENT_OFFSET);
+                final int plainLength = writeSection(
+                        f, new FileInputStream(contentIn.getFileDescriptor()));
+                meta.put(Document.COLUMN_SIZE, plainLength);
+
+                // Verify that remote side of pipe finished okay; if they
+                // crashed or indicated an error then this throws and we
+                // leave the original file intact and clean up temp below.
+                contentIn.checkError();
+            }
+
+            meta.put(Document.COLUMN_DOCUMENT_ID, mDocId);
+            meta.put(Document.COLUMN_LAST_MODIFIED, System.currentTimeMillis());
+
+            // Rewind and write metadata section
+            f.seek(0);
+            f.writeInt(MAGIC_NUMBER);
+
+            final ByteArrayInputStream metaIn = new ByteArrayInputStream(
+                    meta.toString().getBytes(StandardCharsets.UTF_8));
+            writeSection(f, metaIn);
+
+            if (f.getFilePointer() > CONTENT_OFFSET) {
+                throw new IOException("Metadata section was too large");
+            }
+
+            // Everything written fine, atomically swap new data into place.
+            // fsync() before close would be overkill, since rename() is an
+            // atomic barrier.
+            f.close();
+            tempFile.renameTo(mFile);
+
+        } catch (JSONException e) {
+            throw new IOException(e);
+        } finally {
+            // Regardless of what happens, always try cleaning up.
+            f.close();
+            tempFile.delete();
+        }
+    }
+
+    /**
+     * Read and decrypt the section starting at the current file offset.
+     * Validates MAC of decrypted data, throwing if mismatch. When finished,
+     * file offset is at the end of the entire section.
+     */
+    private void readSection(RandomAccessFile f, OutputStream out)
+            throws IOException, GeneralSecurityException {
+        final long start = f.getFilePointer();
+
+        final Section section = new Section();
+        section.read(f);
+
+        final IvParameterSpec ivSpec = new IvParameterSpec(section.iv);
+        mCipher.init(Cipher.DECRYPT_MODE, mDataKey, ivSpec);
+        mMac.init(mMacKey);
+
+        byte[] inbuf = new byte[8192];
+        byte[] outbuf;
+        int n;
+        while ((n = f.read(inbuf, 0, (int) Math.min(section.length, inbuf.length))) != -1) {
+            section.length -= n;
+            mMac.update(inbuf, 0, n);
+            outbuf = mCipher.update(inbuf, 0, n);
+            if (outbuf != null) {
+                out.write(outbuf);
+            }
+            if (section.length == 0) break;
+        }
+
+        section.assertMac(mMac.doFinal());
+
+        outbuf = mCipher.doFinal();
+        if (outbuf != null) {
+            out.write(outbuf);
+        }
+    }
+
+    /**
+     * Encrypt and write the given stream as a full section. Writes section
+     * header and encrypted data starting at the current file offset. When
+     * finished, file offset is at the end of the entire section.
+     */
+    private int writeSection(RandomAccessFile f, InputStream in)
+            throws IOException, GeneralSecurityException {
+        final long start = f.getFilePointer();
+
+        // Write header; we'll come back later to finalize details
+        final Section section = new Section();
+        section.write(f);
+
+        final long dataStart = f.getFilePointer();
+
+        mRandom.nextBytes(section.iv);
+
+        final IvParameterSpec ivSpec = new IvParameterSpec(section.iv);
+        mCipher.init(Cipher.ENCRYPT_MODE, mDataKey, ivSpec);
+        mMac.init(mMacKey);
+
+        int plainLength = 0;
+        byte[] inbuf = new byte[8192];
+        byte[] outbuf;
+        int n;
+        while ((n = in.read(inbuf)) != -1) {
+            plainLength += n;
+            outbuf = mCipher.update(inbuf, 0, n);
+            if (outbuf != null) {
+                mMac.update(outbuf);
+                f.write(outbuf);
+            }
+        }
+
+        outbuf = mCipher.doFinal();
+        if (outbuf != null) {
+            mMac.update(outbuf);
+            f.write(outbuf);
+        }
+
+        section.setMac(mMac.doFinal());
+
+        final long dataEnd = f.getFilePointer();
+        section.length = dataEnd - dataStart;
+
+        // Rewind and update header
+        f.seek(start);
+        section.write(f);
+        f.seek(dataEnd);
+
+        return plainLength;
+    }
+
+    /**
+     * Header of a single file section.
+     */
+    private static class Section {
+        long length;
+        final byte[] iv = new byte[DATA_KEY_LENGTH];
+        final byte[] mac = new byte[MAC_KEY_LENGTH];
+
+        public void read(RandomAccessFile f) throws IOException {
+            length = f.readLong();
+            f.readFully(iv);
+            f.readFully(mac);
+        }
+
+        public void write(RandomAccessFile f) throws IOException {
+            f.writeLong(length);
+            f.write(iv);
+            f.write(mac);
+        }
+
+        public void setMac(byte[] mac) {
+            if (mac.length != this.mac.length) {
+                throw new IllegalArgumentException("Unexpected MAC length");
+            }
+            System.arraycopy(mac, 0, this.mac, 0, this.mac.length);
+        }
+
+        public void assertMac(byte[] mac) throws DigestException {
+            if (mac.length != this.mac.length) {
+                throw new IllegalArgumentException("Unexpected MAC length");
+            }
+            byte result = 0;
+            for (int i = 0; i < mac.length; i++) {
+                result |= mac[i] ^ this.mac[i];
+            }
+            if (result != 0) {
+                throw new DigestException();
+            }
+        }
+    }
+
+    private static void assertMagic(RandomAccessFile f) throws IOException {
+        final int magic = f.readInt();
+        if (magic != MAGIC_NUMBER) {
+            throw new ProtocolException("Bad magic number: " + Integer.toHexString(magic));
+        }
+    }
+}
diff --git a/samples/Vault/src/com/example/android/vault/SecretKeyWrapper.java b/samples/Vault/src/com/example/android/vault/SecretKeyWrapper.java
new file mode 100644
index 0000000..cb8efde
--- /dev/null
+++ b/samples/Vault/src/com/example/android/vault/SecretKeyWrapper.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.vault;
+
+import android.content.Context;
+import android.security.KeyPairGeneratorSpec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Wraps {@link SecretKey} instances using a public/private key pair stored in
+ * the platform {@link KeyStore}. This allows us to protect symmetric keys with
+ * hardware-backed crypto, if provided by the device.
+ * <p>
+ * See <a href="http://en.wikipedia.org/wiki/Key_Wrap">key wrapping</a> for more
+ * details.
+ * <p>
+ * Not inherently thread safe.
+ */
+public class SecretKeyWrapper {
+    private final Cipher mCipher;
+    private final KeyPair mPair;
+
+    /**
+     * Create a wrapper using the public/private key pair with the given alias.
+     * If no pair with that alias exists, it will be generated.
+     */
+    public SecretKeyWrapper(Context context, String alias)
+            throws GeneralSecurityException, IOException {
+        mCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+
+        final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+        keyStore.load(null);
+
+        if (!keyStore.containsAlias(alias)) {
+            generateKeyPair(context, alias);
+        }
+
+        // Even if we just generated the key, always read it back to ensure we
+        // can read it successfully.
+        final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(
+                alias, null);
+        mPair = new KeyPair(entry.getCertificate().getPublicKey(), entry.getPrivateKey());
+    }
+
+    private static void generateKeyPair(Context context, String alias)
+            throws GeneralSecurityException {
+        final Calendar start = new GregorianCalendar();
+        final Calendar end = new GregorianCalendar();
+        end.add(Calendar.YEAR, 100);
+
+        final KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
+                .setAlias(alias)
+                .setSubject(new X500Principal("CN=" + alias))
+                .setSerialNumber(BigInteger.ONE)
+                .setStartDate(start.getTime())
+                .setEndDate(end.getTime())
+                .build();
+
+        final KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
+        gen.initialize(spec);
+        gen.generateKeyPair();
+    }
+
+    /**
+     * Wrap a {@link SecretKey} using the public key assigned to this wrapper.
+     * Use {@link #unwrap(byte[])} to later recover the original
+     * {@link SecretKey}.
+     *
+     * @return a wrapped version of the given {@link SecretKey} that can be
+     *         safely stored on untrusted storage.
+     */
+    public byte[] wrap(SecretKey key) throws GeneralSecurityException {
+        mCipher.init(Cipher.WRAP_MODE, mPair.getPublic());
+        return mCipher.wrap(key);
+    }
+
+    /**
+     * Unwrap a {@link SecretKey} using the private key assigned to this
+     * wrapper.
+     *
+     * @param blob a wrapped {@link SecretKey} as previously returned by
+     *            {@link #wrap(SecretKey)}.
+     */
+    public SecretKey unwrap(byte[] blob) throws GeneralSecurityException {
+        mCipher.init(Cipher.UNWRAP_MODE, mPair.getPrivate());
+        return (SecretKey) mCipher.unwrap(blob, "AES", Cipher.SECRET_KEY);
+    }
+}
diff --git a/samples/Vault/src/com/example/android/vault/Utils.java b/samples/Vault/src/com/example/android/vault/Utils.java
new file mode 100644
index 0000000..d4694b1
--- /dev/null
+++ b/samples/Vault/src/com/example/android/vault/Utils.java
@@ -0,0 +1,72 @@
+/*
+ * 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.vault;
+
+import android.os.ParcelFileDescriptor;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class Utils {
+    public static void closeQuietly(Closeable closable) {
+        if (closable != null) {
+            try {
+                closable.close();
+            } catch (IOException ignored) {
+            }
+        }
+    }
+
+    public static void closeWithErrorQuietly(ParcelFileDescriptor pfd, String msg) {
+        if (pfd != null) {
+            try {
+                pfd.closeWithError(msg);
+            } catch (IOException ignored) {
+            }
+        }
+    }
+
+    public static void writeFully(File file, byte[] data) throws IOException {
+        final OutputStream out = new FileOutputStream(file);
+        try {
+            out.write(data);
+        } finally {
+            out.close();
+        }
+    }
+
+    public static byte[] readFully(File file) throws IOException {
+        final InputStream in = new FileInputStream(file);
+        try {
+            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+            byte[] buffer = new byte[1024];
+            int count;
+            while ((count = in.read(buffer)) != -1) {
+                bytes.write(buffer, 0, count);
+            }
+            return bytes.toByteArray();
+        } finally {
+            in.close();
+        }
+    }
+}
diff --git a/samples/Vault/src/com/example/android/vault/VaultProvider.java b/samples/Vault/src/com/example/android/vault/VaultProvider.java
new file mode 100644
index 0000000..02e3211
--- /dev/null
+++ b/samples/Vault/src/com/example/android/vault/VaultProvider.java
@@ -0,0 +1,563 @@
+/*
+ * 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.vault;
+
+import static com.example.android.vault.EncryptedDocument.DATA_KEY_LENGTH;
+import static com.example.android.vault.EncryptedDocument.MAC_KEY_LENGTH;
+import static com.example.android.vault.Utils.closeQuietly;
+import static com.example.android.vault.Utils.closeWithErrorQuietly;
+import static com.example.android.vault.Utils.readFully;
+import static com.example.android.vault.Utils.writeFully;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsProvider;
+import android.security.KeyChain;
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Provider that encrypts both metadata and contents of documents stored inside.
+ * Each document is stored as described by {@link EncryptedDocument} with
+ * separate metadata and content sections. Directories are just
+ * {@link EncryptedDocument} instances without a content section, and a list of
+ * child documents included in the metadata section.
+ * <p>
+ * All content is encrypted/decrypted on demand through pipes, using
+ * {@link ParcelFileDescriptor#createReliablePipe()} to detect and recover from
+ * remote crashes and errors.
+ * <p>
+ * Our symmetric encryption key is stored on disk only after using
+ * {@link SecretKeyWrapper} to "wrap" it using another public/private key pair
+ * stored in the platform {@link KeyStore}. This allows us to protect our
+ * symmetric key with hardware-backed keys, if supported. Devices without
+ * hardware support still encrypt their keys while at rest, and the platform
+ * always requires a user to present a PIN, password, or pattern to unlock the
+ * KeyStore before use.
+ */
+public class VaultProvider extends DocumentsProvider {
+    public static final String TAG = "Vault";
+
+    static final String AUTHORITY = "com.example.android.vault.provider";
+
+    static final String DEFAULT_ROOT_ID = "vault";
+    static final String DEFAULT_DOCUMENT_ID = "0";
+
+    /** JSON key storing array of all children documents in a directory. */
+    private static final String KEY_CHILDREN = "vault:children";
+
+    /** Key pointing to next available document ID. */
+    private static final String PREF_NEXT_ID = "next_id";
+
+    /** Blob used to derive {@link #mDataKey} from our secret key. */
+    private static final byte[] BLOB_DATA = "DATA".getBytes(StandardCharsets.UTF_8);
+    /** Blob used to derive {@link #mMacKey} from our secret key. */
+    private static final byte[] BLOB_MAC = "MAC".getBytes(StandardCharsets.UTF_8);
+
+    private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
+            Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE,
+            Root.COLUMN_DOCUMENT_ID, Root.COLUMN_AVAILABLE_BYTES, Root.COLUMN_SUMMARY
+    };
+
+    private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
+            Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME,
+            Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
+    };
+
+    private static String[] resolveRootProjection(String[] projection) {
+        return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
+    }
+
+    private static String[] resolveDocumentProjection(String[] projection) {
+        return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
+    }
+
+    private final Object mIdLock = new Object();
+
+    /**
+     * Flag indicating that the {@link SecretKeyWrapper} public/private key is
+     * hardware-backed. A software keystore is more vulnerable to offline
+     * attacks if the device is compromised.
+     */
+    private boolean mHardwareBacked;
+
+    /** File where wrapped symmetric key is stored. */
+    private File mKeyFile;
+    /** Directory where all encrypted documents are stored. */
+    private File mDocumentsDir;
+
+    private SecretKey mDataKey;
+    private SecretKey mMacKey;
+
+    @Override
+    public boolean onCreate() {
+        mHardwareBacked = KeyChain.isBoundKeyAlgorithm("RSA");
+
+        mKeyFile = new File(getContext().getFilesDir(), "vault.key");
+        mDocumentsDir = new File(getContext().getFilesDir(), "documents");
+        mDocumentsDir.mkdirs();
+
+        try {
+            // Load secret key and ensure our root document is ready.
+            loadOrGenerateKeys(getContext(), mKeyFile);
+            initDocument(Long.parseLong(DEFAULT_DOCUMENT_ID), Document.MIME_TYPE_DIR, null);
+
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        } catch (GeneralSecurityException e) {
+            throw new IllegalStateException(e);
+        }
+
+        return true;
+    }
+
+    /**
+     * Used for testing.
+     */
+    void wipeAllContents() throws IOException, GeneralSecurityException {
+        for (File f : mDocumentsDir.listFiles()) {
+            f.delete();
+        }
+
+        initDocument(Long.parseLong(DEFAULT_DOCUMENT_ID), Document.MIME_TYPE_DIR, null);
+    }
+
+    /**
+     * Load our symmetric secret key and use it to derive two different data and
+     * MAC keys. The symmetric secret key is stored securely on disk by wrapping
+     * it with a public/private key pair, possibly backed by hardware.
+     */
+    private void loadOrGenerateKeys(Context context, File keyFile)
+            throws GeneralSecurityException, IOException {
+        final SecretKeyWrapper wrapper = new SecretKeyWrapper(context, TAG);
+
+        // Generate secret key if none exists
+        if (!keyFile.exists()) {
+            final byte[] raw = new byte[DATA_KEY_LENGTH];
+            new SecureRandom().nextBytes(raw);
+
+            final SecretKey key = new SecretKeySpec(raw, "AES");
+            final byte[] wrapped = wrapper.wrap(key);
+
+            writeFully(keyFile, wrapped);
+        }
+
+        // Even if we just generated the key, always read it back to ensure we
+        // can read it successfully.
+        final byte[] wrapped = readFully(keyFile);
+        final SecretKey key = wrapper.unwrap(wrapped);
+
+        final Mac mac = Mac.getInstance("HmacSHA256");
+        mac.init(key);
+
+        // Derive two different keys for encryption and authentication.
+        final byte[] rawDataKey = new byte[DATA_KEY_LENGTH];
+        final byte[] rawMacKey = new byte[MAC_KEY_LENGTH];
+
+        System.arraycopy(mac.doFinal(BLOB_DATA), 0, rawDataKey, 0, rawDataKey.length);
+        System.arraycopy(mac.doFinal(BLOB_MAC), 0, rawMacKey, 0, rawMacKey.length);
+
+        mDataKey = new SecretKeySpec(rawDataKey, "AES");
+        mMacKey = new SecretKeySpec(rawMacKey, "HmacSHA256");
+    }
+
+    @Override
+    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
+        final RowBuilder row = result.newRow();
+        row.add(Root.COLUMN_ROOT_ID, DEFAULT_ROOT_ID);
+        row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY);
+        row.add(Root.COLUMN_TITLE, getContext().getString(R.string.app_label));
+        row.add(Root.COLUMN_DOCUMENT_ID, DEFAULT_DOCUMENT_ID);
+        row.add(Root.COLUMN_ICON, R.drawable.ic_lock_lock);
+
+        // Notify user in storage UI when key isn't hardware-backed
+        if (!mHardwareBacked) {
+            row.add(Root.COLUMN_SUMMARY, getContext().getString(R.string.info_software));
+        }
+
+        return result;
+    }
+
+    private EncryptedDocument getDocument(long docId) throws GeneralSecurityException {
+        final File file = new File(mDocumentsDir, String.valueOf(docId));
+        return new EncryptedDocument(docId, file, mDataKey, mMacKey);
+    }
+
+    /**
+     * Include metadata for a document in the given result cursor.
+     */
+    private void includeDocument(MatrixCursor result, long docId)
+            throws IOException, GeneralSecurityException {
+        final EncryptedDocument doc = getDocument(docId);
+        if (!doc.getFile().exists()) {
+            throw new FileNotFoundException("Missing document " + docId);
+        }
+
+        final JSONObject meta = doc.readMetadata();
+
+        int flags = 0;
+
+        final String mimeType = meta.optString(Document.COLUMN_MIME_TYPE);
+        if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+            flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
+        } else {
+            flags |= Document.FLAG_SUPPORTS_WRITE;
+        }
+        flags |= Document.FLAG_SUPPORTS_DELETE;
+
+        final RowBuilder row = result.newRow();
+        row.add(Document.COLUMN_DOCUMENT_ID, meta.optLong(Document.COLUMN_DOCUMENT_ID));
+        row.add(Document.COLUMN_DISPLAY_NAME, meta.optString(Document.COLUMN_DISPLAY_NAME));
+        row.add(Document.COLUMN_SIZE, meta.optLong(Document.COLUMN_SIZE));
+        row.add(Document.COLUMN_MIME_TYPE, mimeType);
+        row.add(Document.COLUMN_FLAGS, flags);
+        row.add(Document.COLUMN_LAST_MODIFIED, meta.optLong(Document.COLUMN_LAST_MODIFIED));
+    }
+
+    @Override
+    public String createDocument(String parentDocumentId, String mimeType, String displayName)
+            throws FileNotFoundException {
+        final long parentDocId = Long.parseLong(parentDocumentId);
+
+        // Allocate the next available ID
+        final long childDocId;
+        synchronized (mIdLock) {
+            final SharedPreferences prefs = getContext()
+                    .getSharedPreferences(PREF_NEXT_ID, Context.MODE_PRIVATE);
+            childDocId = prefs.getLong(PREF_NEXT_ID, 1);
+            if (!prefs.edit().putLong(PREF_NEXT_ID, childDocId + 1).commit()) {
+                throw new IllegalStateException("Failed to allocate document ID");
+            }
+        }
+
+        try {
+            initDocument(childDocId, mimeType, displayName);
+
+            // Update parent to reference new child
+            final EncryptedDocument parentDoc = getDocument(parentDocId);
+            final JSONObject parentMeta = parentDoc.readMetadata();
+            parentMeta.accumulate(KEY_CHILDREN, childDocId);
+            parentDoc.writeMetadataAndContent(parentMeta, null);
+
+            return String.valueOf(childDocId);
+
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        } catch (GeneralSecurityException e) {
+            throw new IllegalStateException(e);
+        } catch (JSONException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Create document on disk, writing an initial metadata section. Someone
+     * might come back later to write contents.
+     */
+    private void initDocument(long docId, String mimeType, String displayName)
+            throws IOException, GeneralSecurityException {
+        final EncryptedDocument doc = getDocument(docId);
+        if (doc.getFile().exists()) return;
+
+        try {
+            final JSONObject meta = new JSONObject();
+            meta.put(Document.COLUMN_DOCUMENT_ID, docId);
+            meta.put(Document.COLUMN_MIME_TYPE, mimeType);
+            meta.put(Document.COLUMN_DISPLAY_NAME, displayName);
+            if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+                meta.put(KEY_CHILDREN, new JSONArray());
+            }
+
+            doc.writeMetadataAndContent(meta, null);
+        } catch (JSONException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public void deleteDocument(String documentId) throws FileNotFoundException {
+        final long docId = Long.parseLong(documentId);
+
+        try {
+            // Delete given document, any children documents under it, and any
+            // references to it from parents.
+            deleteDocumentTree(docId);
+            deleteDocumentReferences(docId);
+
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        } catch (GeneralSecurityException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Recursively delete the given document and any children under it.
+     */
+    private void deleteDocumentTree(long docId) throws IOException, GeneralSecurityException {
+        final EncryptedDocument doc = getDocument(docId);
+        final JSONObject meta = doc.readMetadata();
+        try {
+            if (Document.MIME_TYPE_DIR.equals(meta.getString(Document.COLUMN_MIME_TYPE))) {
+                final JSONArray children = meta.getJSONArray(KEY_CHILDREN);
+                for (int i = 0; i < children.length(); i++) {
+                    final long childDocId = children.getLong(i);
+                    deleteDocumentTree(childDocId);
+                }
+            }
+        } catch (JSONException e) {
+            throw new IOException(e);
+        }
+
+        if (!doc.getFile().delete()) {
+            throw new IOException("Failed to delete " + docId);
+        }
+    }
+
+    /**
+     * Remove any references to the given document, usually when included as a
+     * child of another directory.
+     */
+    private void deleteDocumentReferences(long docId) {
+        for (String name : mDocumentsDir.list()) {
+            try {
+                final long parentDocId = Long.parseLong(name);
+                final EncryptedDocument parentDoc = getDocument(parentDocId);
+                final JSONObject meta = parentDoc.readMetadata();
+
+                if (Document.MIME_TYPE_DIR.equals(meta.getString(Document.COLUMN_MIME_TYPE))) {
+                    final JSONArray children = meta.getJSONArray(KEY_CHILDREN);
+                    if (maybeRemove(children, docId)) {
+                        Log.d(TAG, "Removed " + docId + " reference from " + name);
+                        parentDoc.writeMetadataAndContent(meta, null);
+
+                        getContext().getContentResolver().notifyChange(
+                                DocumentsContract.buildChildDocumentsUri(AUTHORITY, name), null,
+                                false);
+                    }
+                }
+            } catch (NumberFormatException ignored) {
+            } catch (IOException e) {
+                Log.w(TAG, "Failed to examine " + name, e);
+            } catch (GeneralSecurityException e) {
+                Log.w(TAG, "Failed to examine " + name, e);
+            } catch (JSONException e) {
+                Log.w(TAG, "Failed to examine " + name, e);
+            }
+        }
+    }
+
+    @Override
+    public Cursor queryDocument(String documentId, String[] projection)
+            throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+        try {
+            includeDocument(result, Long.parseLong(documentId));
+        } catch (GeneralSecurityException e) {
+            throw new IllegalStateException(e);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+        return result;
+    }
+
+    @Override
+    public Cursor queryChildDocuments(
+            String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+        final ExtrasMatrixCursor result = new ExtrasMatrixCursor(
+                resolveDocumentProjection(projection));
+        result.setNotificationUri(getContext().getContentResolver(),
+                DocumentsContract.buildChildDocumentsUri(AUTHORITY, parentDocumentId));
+
+        // Notify user in storage UI when key isn't hardware-backed
+        if (!mHardwareBacked) {
+            result.putString(DocumentsContract.EXTRA_INFO,
+                    getContext().getString(R.string.info_software_detail));
+        }
+
+        try {
+            final EncryptedDocument doc = getDocument(Long.parseLong(parentDocumentId));
+            final JSONObject meta = doc.readMetadata();
+            final JSONArray children = meta.getJSONArray(KEY_CHILDREN);
+            for (int i = 0; i < children.length(); i++) {
+                final long docId = children.getLong(i);
+                includeDocument(result, docId);
+            }
+
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        } catch (GeneralSecurityException e) {
+            throw new IllegalStateException(e);
+        } catch (JSONException e) {
+            throw new IllegalStateException(e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public ParcelFileDescriptor openDocument(
+            String documentId, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        final long docId = Long.parseLong(documentId);
+
+        try {
+            final EncryptedDocument doc = getDocument(docId);
+            if ("r".equals(mode)) {
+                return startRead(doc);
+            } else if ("w".equals(mode) || "wt".equals(mode)) {
+                return startWrite(doc);
+            } else {
+                throw new IllegalArgumentException("Unsupported mode: " + mode);
+            }
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        } catch (GeneralSecurityException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Kick off a thread to handle a read request for the given document.
+     * Internally creates a pipe and returns the read end for returning to a
+     * remote process.
+     */
+    private ParcelFileDescriptor startRead(final EncryptedDocument doc) throws IOException {
+        final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
+        final ParcelFileDescriptor readEnd = pipe[0];
+        final ParcelFileDescriptor writeEnd = pipe[1];
+
+        new Thread() {
+            @Override
+            public void run() {
+                try {
+                    doc.readContent(writeEnd);
+                    Log.d(TAG, "Success reading " + doc);
+                    closeQuietly(writeEnd);
+                } catch (IOException e) {
+                    Log.w(TAG, "Failed reading " + doc, e);
+                    closeWithErrorQuietly(writeEnd, e.toString());
+                } catch (GeneralSecurityException e) {
+                    Log.w(TAG, "Failed reading " + doc, e);
+                    closeWithErrorQuietly(writeEnd, e.toString());
+                }
+            }
+        }.start();
+
+        return readEnd;
+    }
+
+    /**
+     * Kick off a thread to handle a write request for the given document.
+     * Internally creates a pipe and returns the write end for returning to a
+     * remote process.
+     */
+    private ParcelFileDescriptor startWrite(final EncryptedDocument doc) throws IOException {
+        final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
+        final ParcelFileDescriptor readEnd = pipe[0];
+        final ParcelFileDescriptor writeEnd = pipe[1];
+
+        new Thread() {
+            @Override
+            public void run() {
+                try {
+                    final JSONObject meta = doc.readMetadata();
+                    doc.writeMetadataAndContent(meta, readEnd);
+                    Log.d(TAG, "Success writing " + doc);
+                    closeQuietly(readEnd);
+                } catch (IOException e) {
+                    Log.w(TAG, "Failed writing " + doc, e);
+                    closeWithErrorQuietly(readEnd, e.toString());
+                } catch (GeneralSecurityException e) {
+                    Log.w(TAG, "Failed writing " + doc, e);
+                    closeWithErrorQuietly(readEnd, e.toString());
+                }
+            }
+        }.start();
+
+        return writeEnd;
+    }
+
+    /**
+     * Maybe remove the given value from a {@link JSONArray}.
+     *
+     * @return if the array was mutated.
+     */
+    private static boolean maybeRemove(JSONArray array, long value) throws JSONException {
+        boolean mutated = false;
+        int i = 0;
+        while (i < array.length()) {
+            if (value == array.getLong(i)) {
+                array.remove(i);
+                mutated = true;
+            } else {
+                i++;
+            }
+        }
+        return mutated;
+    }
+
+    /**
+     * Simple extension of {@link MatrixCursor} that makes it easy to provide a
+     * {@link Bundle} of extras.
+     */
+    private static class ExtrasMatrixCursor extends MatrixCursor {
+        private Bundle mExtras;
+
+        public ExtrasMatrixCursor(String[] columnNames) {
+            super(columnNames);
+        }
+
+        public void putString(String key, String value) {
+            if (mExtras == null) {
+                mExtras = new Bundle();
+            }
+            mExtras.putString(key, value);
+        }
+
+        @Override
+        public Bundle getExtras() {
+            return mExtras;
+        }
+    }
+}
diff --git a/samples/Vault/tests/Android.mk b/samples/Vault/tests/Android.mk
new file mode 100644
index 0000000..552ace2
--- /dev/null
+++ b/samples/Vault/tests/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := VaultTests
+LOCAL_INSTRUMENTATION_FOR := Vault
+
+include $(BUILD_PACKAGE)
diff --git a/samples/Vault/tests/AndroidManifest.xml b/samples/Vault/tests/AndroidManifest.xml
new file mode 100644
index 0000000..8bdf682
--- /dev/null
+++ b/samples/Vault/tests/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.vault.tests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+            android:name="android.test.InstrumentationTestRunner"
+            android:targetPackage="com.example.android.vault"
+            android:label="Vault tests" />
+
+</manifest>
diff --git a/samples/Vault/tests/src/com/example/android/vault/EncryptedDocumentTest.java b/samples/Vault/tests/src/com/example/android/vault/EncryptedDocumentTest.java
new file mode 100644
index 0000000..54754fb
--- /dev/null
+++ b/samples/Vault/tests/src/com/example/android/vault/EncryptedDocumentTest.java
@@ -0,0 +1,251 @@
+/*
+ * 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.vault;
+
+import android.os.ParcelFileDescriptor;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.charset.StandardCharsets;
+import java.security.DigestException;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Tests for {@link EncryptedDocument}.
+ */
+@MediumTest
+public class EncryptedDocumentTest extends AndroidTestCase {
+
+    private File mFile;
+
+    private SecretKey mDataKey = new SecretKeySpec(new byte[] {
+            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+            0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, "AES");
+
+    private SecretKey mMacKey = new SecretKeySpec(new byte[] {
+            0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+            0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+            0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+            0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, "AES");
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mFile = new File(getContext().getFilesDir(), "meow");
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        for (File f : getContext().getFilesDir().listFiles()) {
+            f.delete();
+        }
+    }
+
+    public void testEmptyFile() throws Exception {
+        mFile.createNewFile();
+        final EncryptedDocument doc = new EncryptedDocument(4, mFile, mDataKey, mMacKey);
+
+        try {
+            doc.readMetadata();
+            fail("expected metadata to throw");
+        } catch (IOException expected) {
+        }
+
+        try {
+            final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
+            doc.readContent(pipe[1]);
+            fail("expected content to throw");
+        } catch (IOException expected) {
+        }
+    }
+
+    public void testNormalMetadataAndContents() throws Exception {
+        final byte[] content = "KITTENS".getBytes(StandardCharsets.UTF_8);
+        testMetadataAndContents(content);
+    }
+
+    public void testGiantMetadataAndContents() throws Exception {
+        // try with content size of prime number >1MB
+        final byte[] content = new byte[1298047];
+        Arrays.fill(content, (byte) 0x42);
+        testMetadataAndContents(content);
+    }
+
+    private void testMetadataAndContents(byte[] content) throws Exception {
+        final EncryptedDocument doc = new EncryptedDocument(4, mFile, mDataKey, mMacKey);
+        final byte[] beforeContent = content;
+
+        final ParcelFileDescriptor[] beforePipe = ParcelFileDescriptor.createReliablePipe();
+        new Thread() {
+            @Override
+            public void run() {
+                final FileOutputStream os = new FileOutputStream(beforePipe[1].getFileDescriptor());
+                try {
+                    os.write(beforeContent);
+                    beforePipe[1].close();
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }.start();
+
+        // fully write metadata and content
+        final JSONObject before = new JSONObject();
+        before.put("meow", "cake");
+        doc.writeMetadataAndContent(before, beforePipe[0]);
+
+        // now go back and verify we can read
+        final JSONObject after = doc.readMetadata();
+        assertEquals("cake", after.getString("meow"));
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final ParcelFileDescriptor[] afterPipe = ParcelFileDescriptor.createReliablePipe();
+        final byte[] afterContent = new byte[beforeContent.length];
+        new Thread() {
+            @Override
+            public void run() {
+                final FileInputStream is = new FileInputStream(afterPipe[0].getFileDescriptor());
+                try {
+                    int i = 0;
+                    while (i < afterContent.length) {
+                        int n = is.read(afterContent, i, afterContent.length - i);
+                        i += n;
+                    }
+                    afterPipe[0].close();
+                    latch.countDown();
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }.start();
+
+        doc.readContent(afterPipe[1]);
+        latch.await(5, TimeUnit.SECONDS);
+
+        MoreAsserts.assertEquals(beforeContent, afterContent);
+    }
+
+    public void testNormalMetadataOnly() throws Exception {
+        final EncryptedDocument doc = new EncryptedDocument(4, mFile, mDataKey, mMacKey);
+
+        // write only metadata
+        final JSONObject before = new JSONObject();
+        before.put("lol", "wut");
+        doc.writeMetadataAndContent(before, null);
+
+        // verify we can read
+        final JSONObject after = doc.readMetadata();
+        assertEquals("wut", after.getString("lol"));
+
+        final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
+        try {
+            doc.readContent(pipe[1]);
+            fail("found document content");
+        } catch (IOException expected) {
+        }
+    }
+
+    public void testCopiedFile() throws Exception {
+        final EncryptedDocument doc1 = new EncryptedDocument(1, mFile, mDataKey, mMacKey);
+        final EncryptedDocument doc4 = new EncryptedDocument(4, mFile, mDataKey, mMacKey);
+
+        // write values for doc1 into file
+        final JSONObject meta1 = new JSONObject();
+        meta1.put("key1", "value1");
+        doc1.writeMetadataAndContent(meta1, null);
+
+        // now try reading as doc4, which should fail
+        try {
+            doc4.readMetadata();
+            fail("somehow read without checking docid");
+        } catch (DigestException expected) {
+        }
+    }
+
+    public void testBitTwiddle() throws Exception {
+        final EncryptedDocument doc = new EncryptedDocument(4, mFile, mDataKey, mMacKey);
+
+        // write some metadata
+        final JSONObject before = new JSONObject();
+        before.put("twiddle", "twiddle");
+        doc.writeMetadataAndContent(before, null);
+
+        final RandomAccessFile f = new RandomAccessFile(mFile, "rw");
+        f.seek(f.length() - 4);
+        f.write(0x00);
+        f.close();
+
+        try {
+            doc.readMetadata();
+            fail("somehow passed hmac");
+        } catch (DigestException expected) {
+        }
+    }
+
+    public void testErrorAbortsWrite() throws Exception {
+        final EncryptedDocument doc = new EncryptedDocument(4, mFile, mDataKey, mMacKey);
+
+        // write initial metadata
+        final JSONObject init = new JSONObject();
+        init.put("color", "red");
+        doc.writeMetadataAndContent(init, null);
+
+        // try writing with a pipe that reports failure
+        final byte[] content = "KITTENS".getBytes(StandardCharsets.UTF_8);
+        final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();
+        new Thread() {
+            @Override
+            public void run() {
+                final FileOutputStream os = new FileOutputStream(pipe[1].getFileDescriptor());
+                try {
+                    os.write(content);
+                    pipe[1].closeWithError("ZOMG");
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }.start();
+
+        final JSONObject second = new JSONObject();
+        second.put("color", "blue");
+        try {
+            doc.writeMetadataAndContent(second, pipe[0]);
+            fail("somehow wrote without error");
+        } catch (IOException ignored) {
+        }
+
+        // verify that original metadata still in place
+        final JSONObject after = doc.readMetadata();
+        assertEquals("red", after.getString("color"));
+    }
+}
diff --git a/samples/Vault/tests/src/com/example/android/vault/VaultProviderTest.java b/samples/Vault/tests/src/com/example/android/vault/VaultProviderTest.java
new file mode 100644
index 0000000..79e5b33
--- /dev/null
+++ b/samples/Vault/tests/src/com/example/android/vault/VaultProviderTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.vault;
+
+import static com.example.android.vault.VaultProvider.AUTHORITY;
+import static com.example.android.vault.VaultProvider.DEFAULT_DOCUMENT_ID;
+
+import android.content.ContentProviderClient;
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.test.AndroidTestCase;
+
+import java.util.HashSet;
+
+/**
+ * Tests for {@link VaultProvider}.
+ */
+public class VaultProviderTest extends AndroidTestCase {
+
+    private static final String MIME_TYPE_DEFAULT = "text/plain";
+
+    private ContentProviderClient mClient;
+    private VaultProvider mProvider;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mClient = getContext().getContentResolver().acquireContentProviderClient(AUTHORITY);
+        mProvider = (VaultProvider) mClient.getLocalContentProvider();
+        mProvider.wipeAllContents();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        mClient.release();
+    }
+
+    public void testDeleteDirectory() throws Exception {
+        Cursor c;
+
+        final String file = mProvider.createDocument(
+                DEFAULT_DOCUMENT_ID, MIME_TYPE_DEFAULT, "file");
+        final String dir = mProvider.createDocument(
+                DEFAULT_DOCUMENT_ID, Document.MIME_TYPE_DIR, "dir");
+
+        final String dirfile = mProvider.createDocument(
+                dir, MIME_TYPE_DEFAULT, "dirfile");
+        final String dirdir = mProvider.createDocument(
+                dir, Document.MIME_TYPE_DIR, "dirdir");
+
+        final String dirdirfile = mProvider.createDocument(
+                dirdir, MIME_TYPE_DEFAULT, "dirdirfile");
+
+        // verify everything is in place
+        c = mProvider.queryChildDocuments(DEFAULT_DOCUMENT_ID, null, null);
+        assertContains(c, "file", "dir");
+        c = mProvider.queryChildDocuments(dir, null, null);
+        assertContains(c, "dirfile", "dirdir");
+
+        // should remove children and parent ref
+        mProvider.deleteDocument(dir);
+
+        c = mProvider.queryChildDocuments(DEFAULT_DOCUMENT_ID, null, null);
+        assertContains(c, "file");
+
+        mProvider.queryDocument(file, null);
+
+        try { mProvider.queryDocument(dir, null); } catch (Exception expected) { }
+        try { mProvider.queryDocument(dirfile, null); } catch (Exception expected) { }
+        try { mProvider.queryDocument(dirdir, null); } catch (Exception expected) { }
+        try { mProvider.queryDocument(dirdirfile, null); } catch (Exception expected) { }
+    }
+
+    private static void assertContains(Cursor c, String... docs) {
+        final HashSet<String> set = new HashSet<String>();
+        while (c.moveToNext()) {
+            set.add(c.getString(c.getColumnIndex(Document.COLUMN_DISPLAY_NAME)));
+        }
+
+        for (String doc : docs) {
+            assertTrue(doc, set.contains(doc));
+        }
+    }
+}
diff --git a/samples/browseable/ActivityInstrumentation/AndroidManifest.xml b/samples/browseable/ActivityInstrumentation/AndroidManifest.xml
new file mode 100644
index 0000000..547d95e
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.activityinstrumentation"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+
+</manifest>
diff --git a/samples/browseable/ActivityInstrumentation/_index.jd b/samples/browseable/ActivityInstrumentation/_index.jd
new file mode 100644
index 0000000..fa62724
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="ActivityInstrumentation"
+sample.group=Testing
+@jd:body
+
+<p>This sample demonstrates how to use an
+{@link android.test.InstrumentationTestCase} to test the internal state of an
+{@link android.app.Activity}.</p>
+<p>To learn more about using Android's custom testing framework, see
+<a href="{@docRoot}training/activity-testing/index.html">Testing Your
+Android Activity</a>.</p>
diff --git a/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/tile.9.png b/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ActivityInstrumentation/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ActivityInstrumentation/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActivityInstrumentation/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ActivityInstrumentation/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActivityInstrumentation/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ActivityInstrumentation/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActivityInstrumentation/res/layout/activity_main.xml b/samples/browseable/ActivityInstrumentation/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/ActivityInstrumentation/res/layout/sample_main.xml b/samples/browseable/ActivityInstrumentation/res/layout/sample_main.xml
new file mode 100644
index 0000000..2b7a4d1
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/layout/sample_main.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2013 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                xmlns:tools="http://schemas.android.com/tools"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:paddingLeft="@dimen/activity_horizontal_margin"
+                android:paddingRight="@dimen/activity_horizontal_margin"
+                android:paddingTop="@dimen/activity_vertical_margin"
+                android:paddingBottom="@dimen/activity_vertical_margin"
+                tools:context=".MainActivity">
+
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/instructions"
+            android:id="@+id/instructions"/>
+
+    <Spinner
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/spinner"
+            android:layout_below="@+id/instructions"
+            android:layout_centerHorizontal="true"/>
+
+</RelativeLayout>
diff --git a/samples/browseable/ActivityInstrumentation/res/values-sw600dp/dimens.xml b/samples/browseable/ActivityInstrumentation/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ActivityInstrumentation/res/values-sw600dp/styles.xml b/samples/browseable/ActivityInstrumentation/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/ActivityInstrumentation/res/values-sw720dp-land/dimens.xml b/samples/browseable/ActivityInstrumentation/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..0dfce6a
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ Copyright 2013 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <!-- Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. -->
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+</resources>
diff --git a/samples/browseable/ActivityInstrumentation/res/values/base-strings.xml b/samples/browseable/ActivityInstrumentation/res/values/base-strings.xml
new file mode 100644
index 0000000..dfe40f4
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">ActivityInstrumentation</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample provides a basic example of using an InstrumentationTest to probe the
+            internal state of an Activity.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/ActivityInstrumentation/res/values/dimens.xml b/samples/browseable/ActivityInstrumentation/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ActivityInstrumentation/res/values/strings.xml b/samples/browseable/ActivityInstrumentation/res/values/strings.xml
new file mode 100644
index 0000000..4ed2243
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2013 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <string name="instructions">The value of the spinner below should be persisted when this activity is destroyed.</string>
+</resources>
diff --git a/samples/browseable/ActivityInstrumentation/res/values/styles.xml b/samples/browseable/ActivityInstrumentation/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.activityinstrumentation/MainActivity.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.activityinstrumentation/MainActivity.java
new file mode 100644
index 0000000..39056ea
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.activityinstrumentation/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.activityinstrumentation;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Basic activity with a spinner. The spinner should persist its position to disk every time a
+ * new selection is made.
+ */
+public class MainActivity extends Activity {
+
+    /** Shared preferences key: Holds spinner position. Must not be negative. */
+    private static final String PREF_SPINNER_POS = "spinner_pos";
+    /** Magic constant to indicate that no value is stored for PREF_SPINNER_POS. */
+    private static final int PREF_SPINNER_VALUE_ISNULL = -1;
+    /** Values for display in spinner. */
+    private static final String[] SPINNER_VALUES = new String[] {
+            "Select Weather...", "Sunny", "Partly Cloudy", "Cloudy", "Rain", "Snow", "Hurricane"};
+
+    // Constants representing each of the options in SPINNER_VALUES. Declared package-private
+    // so that they can be accessed from our test suite.
+    static final int WEATHER_NOSELECTION = 0;
+    static final int WEATHER_SUNNY = 1;
+    static final int WEATHER_PARTLY_CLOUDY = 2;
+    static final int WEATHER_CLOUDY = 3;
+    static final int WEATHER_RAIN = 4;
+    static final int WEATHER_SNOW = 5;
+    static final int WEATHER_HURRICANE = 6;
+
+    /** Handle to default shared preferences for this activity. */
+    private SharedPreferences mPrefs;
+    /** Handle to the spinner in this Activity's layout. */
+    private Spinner mSpinner;
+
+    /**
+     * Setup activity state.
+     *
+     * @param savedInstanceState
+     */
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Inflate UI from res/layout/activity_main.xml
+        setContentView(R.layout.sample_main);
+
+        // Get handle to default shared preferences for this activity
+        mPrefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
+
+        // Populate spinner with sample values from an array
+        mSpinner = (Spinner) findViewById(R.id.spinner);
+        mSpinner.setAdapter(
+                new ArrayAdapter<String>(
+                        this,                                                   // Context
+                        android.R.layout.simple_list_item_1,                    // Layout
+                        new ArrayList<String>(Arrays.asList(SPINNER_VALUES))    // Data source
+                ));
+
+        // Read in a sample value, if it's not set.
+        int selection = mPrefs.getInt(PREF_SPINNER_POS, PREF_SPINNER_VALUE_ISNULL);
+        if (selection != PREF_SPINNER_VALUE_ISNULL) {
+            mSpinner.setSelection(selection);
+        }
+
+        // Callback to persist spinner data whenever a new value is selected. This will be the
+        // focus of our sample unit test.
+        mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+
+            // The methods below commit the ID of the currently selected item in the spinner
+            // to disk, using a SharedPreferences file.
+            //
+            // Note: A common mistake here is to forget to call .commit(). Try removing this
+            // statement and running the tests to watch them fail.
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                mPrefs.edit().putInt(PREF_SPINNER_POS, position).commit();
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+                mPrefs.edit().remove(PREF_SPINNER_POS).commit();
+            }
+        });
+    }
+}
diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/Log.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogNode.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogView.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/AdvancedImmersiveMode/AndroidManifest.xml b/samples/browseable/AdvancedImmersiveMode/AndroidManifest.xml
new file mode 100644
index 0000000..1d01856
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/AndroidManifest.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- the versionCode is an integer representation of this version of your application.  New
+     versions get higher numbers, so the upgrade system can avoid dealing with the ambiguity
+     of "1.9" vs "1.10".  versionName, on the other hand, can be whatever you want, as the code
+     that handles upgrading Android apps between versions on your device just ignores it.-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.advancedimmersivemode"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!-- This sample is to demonstrate features released in API 19.
+         So while it would technically run on an earlier version of Android,
+         there wouldn't be much point) -->
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+    <!-- allowBackup declares if the app can be part of device-wide backups such as "adb backup" -->
+    <!-- theme is a way of applying UI decisions across your entire application.  You can also
+         define it on a per-application basis. -->
+    <application
+        android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <!-- Every activity needs its own Manifest element.  The intent-filter contained in the
+             element declares the intents that can be used to activate this Activity.  For instance,
+             the one below flags this Activity as a "main" entry point of this app, and suitable
+             for creating a shortcut to in the Launcher.  If you wanted your app to have 5
+             different Activities available in the launcher, you could just make 5 activities
+             with that intent filter.  Please don't do that.  Just because it's a good example
+             doesn't mean it's a good idea. -->
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name"
+                  android:uiOptions="splitActionBarWhenNarrow">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/samples/browseable/AdvancedImmersiveMode/_index.jd b/samples/browseable/AdvancedImmersiveMode/_index.jd
new file mode 100644
index 0000000..2b19c9c
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/_index.jd
@@ -0,0 +1,14 @@
+
+
+
+page.tags="AdvancedImmersiveMode"
+sample.group=UI
+@jd:body
+
+<p>Android 4.4 introduces a way for you to provide a more immersive screen
+experience in your app, by letting users show or hide the status bar and
+navigation bar with a swipe.</p>
+<p>This sample demonstrates how this features interacts with some of the other
+UI flags related to full-screen apps. The sample also shows how to implement a
+"sticky" mode, which re-hides the bars a few seconds after the user swipes
+them back in.</p>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/tile.9.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdvancedImmersiveMode/res/layout/activity_main.xml b/samples/browseable/AdvancedImmersiveMode/res/layout/activity_main.xml
new file mode 100755
index 0000000..bc5a575
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:id="@+id/sample_main_layout">
+    <TextView android:id="@+id/sample_output"
+              style="@style/Widget.SampleMessage"
+              android:layout_weight="1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:text="@string/intro_message" />
+    <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:background="@android:color/darker_gray"/>
+    <fragment
+            android:name="com.example.android.common.logger.LogFragment"
+            android:id="@+id/log_fragment"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/menu/main.xml b/samples/browseable/AdvancedImmersiveMode/res/menu/main.xml
new file mode 100644
index 0000000..2c3515d
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/sample_action"
+          android:showAsAction="ifRoom|withText"
+          android:title="@string/sample_action" />
+</menu>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/dimens.xml b/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/styles.xml b/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/base-strings.xml b/samples/browseable/AdvancedImmersiveMode/res/values/base-strings.xml
new file mode 100644
index 0000000..305e12a
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/values/base-strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">AdvancedImmersiveMode</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            \"Immersive Mode\" is a new UI mode which improves \"hide full screen\" and
+            \"hide nav bar\" modes, by letting users swipe the bars in and out.  This sample
+            lets the user experiment with immersive mode by enabling it and seeing how it interacts
+            with some of the other UI flags related to full-screen apps.
+            \n\nThis sample also lets the user choose between normal immersive mode and "sticky"
+            immersive mode, which removes the status bar and nav bar
+            a few seconds after the user has swiped them back in.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/dimens.xml b/samples/browseable/AdvancedImmersiveMode/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml b/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml
new file mode 100644
index 0000000..a65b891
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+        <string name="sample_action">Try these settings!</string>
+</resources>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/styles.xml b/samples/browseable/AdvancedImmersiveMode/res/values/styles.xml
new file mode 100644
index 0000000..d3f82ff
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/values/styles.xml
@@ -0,0 +1,51 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="AppTheme" parent="Theme.Base" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+
+    <style name="Widget.SampleOutput">
+        <item name="android:padding">@dimen/margin_medium</item>
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Log" parent="Widget.SampleOutput">
+        <item name="android:typeface">monospace</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.java
new file mode 100644
index 0000000..fe11ecb
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.java
@@ -0,0 +1,174 @@
+/*
+* Copyright (C) 2012 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.example.android.advancedimmersivemode;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+
+import com.example.android.common.logger.Log;
+
+/**
+ * Demonstrates how to update the app's UI by toggling immersive mode.
+ * Checkboxes are also made available for toggling other UI flags which can
+ * alter the behavior of immersive mode.
+ */
+public class AdvancedImmersiveModeFragment extends Fragment {
+
+    public static final String TAG = "AdvancedImmersiveModeFragment";
+    public CheckBox mHideNavCheckbox;
+    public CheckBox mHideStatusBarCheckBox;
+    public CheckBox mImmersiveModeCheckBox;
+    public CheckBox mImmersiveModeStickyCheckBox;
+    public CheckBox mLowProfileCheckBox;
+
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        final View decorView = getActivity().getWindow().getDecorView();
+        ViewGroup parentView = (ViewGroup) getActivity().getWindow().getDecorView()
+                .findViewById(R.id.sample_main_layout);
+
+        mLowProfileCheckBox = new CheckBox(getActivity());
+        mLowProfileCheckBox.setText("Enable Low Profile mode.");
+        parentView.addView(mLowProfileCheckBox);
+
+        mHideNavCheckbox = new CheckBox(getActivity());
+        mHideNavCheckbox.setChecked(true);
+        mHideNavCheckbox.setText("Hide Navigation bar");
+        parentView.addView(mHideNavCheckbox);
+
+        mHideStatusBarCheckBox = new CheckBox(getActivity());
+        mHideStatusBarCheckBox.setChecked(true);
+        mHideStatusBarCheckBox.setText("Hide Status Bar");
+        parentView.addView(mHideStatusBarCheckBox);
+
+        mImmersiveModeCheckBox = new CheckBox(getActivity());
+        mImmersiveModeCheckBox.setText("Enable Immersive Mode.");
+        parentView.addView(mImmersiveModeCheckBox);
+
+        mImmersiveModeStickyCheckBox = new CheckBox(getActivity());
+        mImmersiveModeStickyCheckBox.setText("Enable Immersive Mode (Sticky)");
+        parentView.addView(mImmersiveModeStickyCheckBox);
+
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.sample_action) {
+            toggleImmersiveMode();
+        }
+        return true;
+    }
+
+    /**
+     * Detects and toggles immersive mode (also known as "hidey bar" mode).
+     */
+    public void toggleImmersiveMode() {
+
+        // BEGIN_INCLUDE (get_current_ui_flags)
+        // The "Decor View" is the parent view of the Activity.  It's also conveniently the easiest
+        // one to find from within a fragment, since there's a handy helper method to pull it, and
+        // we don't have to bother with picking a view somewhere deeper in the hierarchy and calling
+        // "findViewById" on it.
+        View decorView = getActivity().getWindow().getDecorView();
+        int uiOptions = decorView.getSystemUiVisibility();
+        int newUiOptions = uiOptions;
+        // END_INCLUDE (get_current_ui_flags)
+
+        // BEGIN_INCLUDE (toggle_lowprofile_mode)
+        // Low profile mode doesn't resize the screen at all, but it covers the nav & status bar
+        // icons with black so they're less distracting.  Unlike "full screen" and "hide nav bar,"
+        // this mode doesn't interact with immersive mode at all, but it's instructive when running
+        // this sample to observe the differences in behavior.
+        if (mLowProfileCheckBox.isChecked()) {
+            newUiOptions |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
+        } else {
+            newUiOptions &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
+        }
+        // END_INCLUDE (toggle_lowprofile_mode)
+
+        // BEGIN_INCLUDE (toggle_fullscreen_mode)
+        // When enabled, this flag hides non-critical UI, such as the status bar,
+        // which usually shows notification icons, battery life, etc
+        // on phone-sized devices.  The bar reappears when the user swipes it down.  When immersive
+        // mode is also enabled, the app-drawable area expands, and when the status bar is swiped
+        // down, it appears semi-transparently and slides in over the app, instead of pushing it
+        // down.
+        if (mHideStatusBarCheckBox.isChecked()) {
+            newUiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
+        } else {
+            newUiOptions &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
+        }
+        // END_INCLUDE (toggle_fullscreen_mode)
+
+        // BEGIN_INCLUDE (toggle_hidenav_mode)
+        // When enabled, this flag hides the black nav bar along the bottom,
+        // where the home/back buttons are.  The nav bar normally instantly reappears
+        // when the user touches the screen.  When immersive mode is also enabled, the nav bar
+        // stays hidden until the user swipes it back.
+        if (mHideNavCheckbox.isChecked()) {
+            newUiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+        } else {
+            newUiOptions &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+        }
+        // END_INCLUDE (toggle_hidenav_mode)
+
+        // BEGIN_INCLUDE (toggle_immersive_mode)
+        // Immersive mode doesn't do anything without at least one of the previous flags
+        // enabled.  When enabled, it allows the user to swipe the status and/or nav bars
+        // off-screen.  When the user swipes the bars back onto the screen, the flags are cleared
+        // and immersive mode is automatically disabled.
+        if (mImmersiveModeCheckBox.isChecked()) {
+            newUiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE;
+        } else {
+            newUiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE;
+        }
+        // END_INCLUDE (toggle_immersive_mode)
+
+        // BEGIN_INCLUDE (toggle_immersive_mode_sticky)
+        // There's actually two forms of immersive mode, normal and "sticky".  Sticky immersive mode
+        // is different in 2 key ways:
+        //
+        // * Uses semi-transparent bars for the nav and status bars
+        // * This UI flag will *not* be cleared when the user interacts with the UI.
+        //   When the user swipes, the bars will temporarily appear for a few seconds and then
+        //   disappear again.
+        if (mImmersiveModeStickyCheckBox.isChecked()) {
+            newUiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+        } else {
+            newUiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+        }
+        // END_INCLUDE (toggle_immersive_mode_sticky)
+
+        // BEGIN_INCLUDE (set_ui_flags)
+        //Set the new UI flags.
+        decorView.setSystemUiVisibility(newUiOptions);
+        Log.i(TAG, "Current height: " + decorView.getHeight() + ", width: " + decorView.getWidth());
+        // END_INCLUDE (set_ui_flags)
+    }
+}
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.java
new file mode 100644
index 0000000..0ebe878
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.java
@@ -0,0 +1,80 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+
+
+package com.example.android.advancedimmersivemode;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description
+ * and a few action bar buttons.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    public static final String FRAGTAG = "AdvancedImmersiveModeFragment";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        if (getSupportFragmentManager().findFragmentByTag(FRAGTAG) == null ) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            AdvancedImmersiveModeFragment fragment = new AdvancedImmersiveModeFragment();
+            transaction.add(fragment, FRAGTAG);
+            transaction.commit();
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+    public static final String TAG = "SampleActivityBase";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected  void onStart() {
+        super.onStart();
+        initializeLogging();
+    }
+
+    /** Set up targets to receive log data */
+    public void initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/Log.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogNode.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogView.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/AppRestrictions/AndroidManifest.xml b/samples/browseable/AppRestrictions/AndroidManifest.xml
new file mode 100644
index 0000000..b492bbf
--- /dev/null
+++ b/samples/browseable/AppRestrictions/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.apprestrictions"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="18" />
+
+    <application android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher">
+
+        <activity android:name="MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="CustomRestrictionsActivity"
+            android:label="@string/restrictions_activity_label" />
+
+        <receiver android:name="GetRestrictionsReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
+            </intent-filter>
+        </receiver>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/AppRestrictions/_index.jd b/samples/browseable/AppRestrictions/_index.jd
new file mode 100644
index 0000000..83aa08c
--- /dev/null
+++ b/samples/browseable/AppRestrictions/_index.jd
@@ -0,0 +1,17 @@
+
+
+
+page.tags="AppRestrictions"
+sample.group=Content
+@jd:body
+
+<p>
+            
+            This sample demonstrates the use of the App Restriction feature, which is available on
+            Android 4.3 and above tablet device with the multiuser feature.
+
+            When launched under the primary User account, you can toggle between standard app restriction
+            types and custom.  When launched under a restricted profile, this activity displays app
+            restriction settings, if available.
+            
+        </p>
diff --git a/samples/browseable/AppRestrictions/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..f36c473
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/drawable-hdpi/tile.9.png b/samples/browseable/AppRestrictions/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..5ab2e0d
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..7622838
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..7f55fef
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictions/res/layout/activity_main.xml b/samples/browseable/AppRestrictions/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/AppRestrictions/res/layout/main.xml b/samples/browseable/AppRestrictions/res/layout/main.xml
new file mode 100644
index 0000000..55e2c8e
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/layout/main.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+    <LinearLayout android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="20dp">
+
+        <TextView android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_marginBottom="10dp"
+                  android:textSize="18sp"
+                  android:text="@string/sample_app_description"/>
+
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_marginBottom="15dp">
+            <CheckBox android:id="@+id/custom_app_limits"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:onClick="onCustomClicked"/>
+            <TextView android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:textSize="18sp"
+                      android:text="@string/custom_description"
+                      android:onClick="onCustomClicked"
+                      android:layout_weight="1"/>
+        </LinearLayout>
+
+        <!-- Separator -->
+        <View android:layout_height="1dp"
+               android:background="@android:color/white"
+               android:layout_width="match_parent"
+               android:layout_margin="25dp"/>
+
+        <!-- Section to show app restriction settings under a restricted profile. -->
+        <TextView android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:textSize="20sp"
+                  android:text="@string/current_app_limits_label"/>
+        <TextView android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:textSize="18sp"
+                  android:layout_marginBottom="10dp"
+                  android:text="@string/current_app_limits_description"/>
+
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_marginLeft="20dp">
+            <TextView android:layout_width="210dp"
+                      android:layout_height="wrap_content"
+                      android:textSize="18sp"
+                      android:text="@string/boolean_entry_title"/>
+            <Space android:layout_height="1dp"
+                   android:layout_width="15dp"/>
+            <TextView android:id="@+id/boolean_entry_id"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:textSize="18sp"
+                      android:text="@string/boolean_entry_title"/>
+        </LinearLayout>
+
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_marginLeft="20dp">
+            <TextView android:layout_width="210dp"
+                      android:layout_height="wrap_content"
+                      android:textSize="18sp"
+                      android:text="@string/choice_entry_title"/>
+            <Space android:layout_height="1dp"
+                   android:layout_width="15dp"/>
+            <TextView android:id="@+id/choice_entry_id"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:textSize="18sp"
+                      android:text="@string/boolean_entry_title"/>
+        </LinearLayout>
+
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_marginLeft="20dp">
+            <TextView android:layout_width="210dp"
+                      android:layout_height="wrap_content"
+                      android:textSize="18sp"
+                      android:text="@string/multi_entry_title"/>
+            <Space android:layout_height="1dp"
+                   android:layout_width="15dp"/>
+            <TextView android:id="@+id/multi_entry_id"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:textSize="18sp"
+                      android:text="@string/multi_entry_title"/>
+        </LinearLayout>
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml b/samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml b/samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/AppRestrictions/res/values/base-strings.xml b/samples/browseable/AppRestrictions/res/values/base-strings.xml
new file mode 100644
index 0000000..08a4663
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/values/base-strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">AppRestrictions</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates the use of the App Restriction feature, which is available on
+            Android 4.3 and above tablet device with the multiuser feature.
+
+            When launched under the primary User account, you can toggle between standard app restriction
+            types and custom.  When launched under a restricted profile, this activity displays app
+            restriction settings, if available.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/AppRestrictions/res/values/dimens.xml b/samples/browseable/AppRestrictions/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/AppRestrictions/res/values/strings.xml b/samples/browseable/AppRestrictions/res/values/strings.xml
new file mode 100644
index 0000000..534edf0
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/values/strings.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="restrictions_activity_label">Custom app restrictions</string>
+    <string name="boolean_entry_title">Test boolean type</string>
+    <string name="choice_entry_title">Test choice type</string>
+    <string name="multi_entry_title">Test multi-select type</string>
+    <string name="custom_description">If checked, use a custom app restriction Activity.  Otherwise,
+        use standard restriction types.
+    </string>
+    <string name="sample_app_description">Note: This sample app requires the restricted profile
+        feature.\n\n
+        1. If this is the primary user, go to Settings &gt; Users.\n\n
+        2. Create a restricted profile, if one doesn\'t exist already.\n\n
+        3. Open the profile settings, locate the sample app, and tap the app restriction settings
+        icon. Configure app restrictions for the app.\n\n
+        4. In the lock screen, switch to the user\'s restricted profile, launch this sample app,
+        and see the configured app restrictions displayed.\n
+    </string>
+    <string name="settings_button_label">Go to Settings</string>
+    <string name="current_app_limits_label">Current app restriction settings:</string>
+    <string name="na">N/A</string>
+    <string name="current_app_limits_description">Your app can restrict its content based on these
+        settings, which can be configured through the primary user\'s Users Settings.
+    </string>
+
+    <string-array name="multi_entry_entries">
+        <item>Ice Cream</item>
+        <item>Jelly Bean</item>
+        <item>More Jelly Bean</item>
+    </string-array>
+
+    <string-array name="multi_entry_values" translateable="false">
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+    </string-array>
+
+    <string-array name="choice_entry_entries">
+        <item>Ice Cream</item>
+        <item>Jelly Bean</item>
+        <item>More Jelly Bean</item>
+    </string-array>
+
+    <string-array name="choice_entry_values" translateable="false">
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+    </string-array>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/AppRestrictions/res/values/styles.xml b/samples/browseable/AppRestrictions/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/AppRestrictions/res/xml/custom_prefs.xml b/samples/browseable/AppRestrictions/res/xml/custom_prefs.xml
new file mode 100644
index 0000000..5a3cf0d
--- /dev/null
+++ b/samples/browseable/AppRestrictions/res/xml/custom_prefs.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+        android:title="@string/restrictions_activity_label">
+
+    <CheckBoxPreference android:key="pref_boolean"
+        android:title="@string/boolean_entry_title" />
+
+    <ListPreference android:key="pref_choice"
+        android:title="@string/choice_entry_title"
+        android:entries="@array/choice_entry_entries"
+        android:entryValues="@array/choice_entry_values" />
+
+    <MultiSelectListPreference android:key="pref_multi"
+        android:title="@string/multi_entry_title"
+        android:entries="@array/multi_entry_entries"
+        android:entryValues="@array/multi_entry_values" />
+
+</PreferenceScreen>
diff --git a/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsActivity.java b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsActivity.java
new file mode 100644
index 0000000..213b313
--- /dev/null
+++ b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsActivity.java
@@ -0,0 +1,44 @@
+/*
+ * 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.apprestrictions;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * This activity demonstrates how an app can integrate its own custom app restriction settings
+ * with the restricted profile feature.
+ *
+ * This sample app maintains custom app restriction settings in shared preferences.  When
+ * the activity is invoked (from Settings > Users), the stored settings are used to initialize
+ * the custom configuration on the user interface.  Three sample input types are
+ * shown: checkbox, single-choice, and multi-choice.  When the settings are modified by the user,
+ * the corresponding restriction entries are saved, which are retrievable under a restricted
+ * profile.
+ */
+public class CustomRestrictionsActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (savedInstanceState == null) {
+            getFragmentManager().beginTransaction().replace(android.R.id.content,
+                    new CustomRestrictionsFragment()).commit();
+        }
+    }
+}
diff --git a/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.java b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.java
new file mode 100644
index 0000000..b04dfd1
--- /dev/null
+++ b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.java
@@ -0,0 +1,202 @@
+/*
+ * 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.apprestrictions;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.RestrictionEntry;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
+import android.preference.MultiSelectListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This fragment is included in {@code CustomRestrictionsActivity}.  It demonstrates how an app
+ * can integrate its own custom app restriction settings with the restricted profile feature.
+ *
+ * This sample app maintains custom app restriction settings in shared preferences.  Your app
+ * can use other methods to maintain the settings.  When this activity is invoked
+ * (from Settings > Users > Restricted Profile), the shared preferences are used to initialize
+ * the custom configuration on the user interface.
+ *
+ * Three sample input types are shown: checkbox, single-choice, and multi-choice.  When the
+ * settings are modified by the user, the corresponding restriction entries are saved in the
+ * platform.  The saved restriction entries are retrievable when the app is launched under a
+ * restricted profile.
+ */
+public class CustomRestrictionsFragment extends PreferenceFragment
+        implements Preference.OnPreferenceChangeListener {
+
+    // Shared preference key for the boolean restriction.
+    private static final String KEY_BOOLEAN_PREF = "pref_boolean";
+    // Shared preference key for the single-select restriction.
+    private static final String KEY_CHOICE_PREF = "pref_choice";
+    // Shared preference key for the multi-select restriction.
+    private static final String KEY_MULTI_PREF = "pref_multi";
+
+
+    private List<RestrictionEntry> mRestrictions;
+    private Bundle mRestrictionsBundle;
+
+    // Shared preferences for each of the sample input types.
+    private CheckBoxPreference mBooleanPref;
+    private ListPreference mChoicePref;
+    private MultiSelectListPreference mMultiPref;
+
+    // Restriction entries for each of the sample input types.
+    private RestrictionEntry mBooleanEntry;
+    private RestrictionEntry mChoiceEntry;
+    private RestrictionEntry mMultiEntry;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        addPreferencesFromResource(R.xml.custom_prefs);
+
+        // This sample app uses shared preferences to maintain app restriction settings.  Your app
+        // can use other methods to maintain the settings.
+        mBooleanPref = (CheckBoxPreference) findPreference(KEY_BOOLEAN_PREF);
+        mChoicePref = (ListPreference) findPreference(KEY_CHOICE_PREF);
+        mMultiPref = (MultiSelectListPreference) findPreference(KEY_MULTI_PREF);
+
+        mBooleanPref.setOnPreferenceChangeListener(this);
+        mChoicePref.setOnPreferenceChangeListener(this);
+        mMultiPref.setOnPreferenceChangeListener(this);
+
+        setRetainInstance(true);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        final Activity activity = getActivity();
+
+        // BEGIN_INCLUDE (GET_CURRENT_RESTRICTIONS)
+        // Existing app restriction settings, if exist, can be retrieved from the Bundle.
+        mRestrictionsBundle =
+                activity.getIntent().getBundleExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE);
+
+        if (mRestrictionsBundle == null) {
+            mRestrictionsBundle =
+                    ((UserManager) activity.getSystemService(Context.USER_SERVICE))
+                            .getApplicationRestrictions(activity.getPackageName());
+        }
+
+        if (mRestrictionsBundle == null) {
+            mRestrictionsBundle = new Bundle();
+        }
+
+        mRestrictions = activity.getIntent().getParcelableArrayListExtra(
+                Intent.EXTRA_RESTRICTIONS_LIST);
+        // END_INCLUDE (GET_CURRENT_RESTRICTIONS)
+
+        // Transfers the saved values into the preference hierarchy.
+        if (mRestrictions != null) {
+            for (RestrictionEntry entry : mRestrictions) {
+                if (entry.getKey().equals(GetRestrictionsReceiver.KEY_BOOLEAN)) {
+                    mBooleanPref.setChecked(entry.getSelectedState());
+                    mBooleanEntry = entry;
+                } else if (entry.getKey().equals(GetRestrictionsReceiver.KEY_CHOICE)) {
+                    mChoicePref.setValue(entry.getSelectedString());
+                    mChoiceEntry = entry;
+                } else if (entry.getKey().equals(GetRestrictionsReceiver.KEY_MULTI_SELECT)) {
+                    HashSet<String> set = new HashSet<String>();
+                    for (String value : entry.getAllSelectedStrings()) {
+                        set.add(value);
+                    }
+                    mMultiPref.setValues(set);
+                    mMultiEntry = entry;
+                }
+            }
+        } else {
+            mRestrictions = new ArrayList<RestrictionEntry>();
+
+            // Initializes the boolean restriction entry and updates its corresponding shared
+            // preference value.
+            mBooleanEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_BOOLEAN,
+                    mRestrictionsBundle.getBoolean(GetRestrictionsReceiver.KEY_BOOLEAN, false));
+            mBooleanEntry.setType(RestrictionEntry.TYPE_BOOLEAN);
+            mBooleanPref.setChecked(mBooleanEntry.getSelectedState());
+
+            // Initializes the single choice restriction entry and updates its corresponding
+            // shared preference value.
+            mChoiceEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_CHOICE,
+                    mRestrictionsBundle.getString(GetRestrictionsReceiver.KEY_CHOICE));
+            mChoiceEntry.setType(RestrictionEntry.TYPE_CHOICE);
+            mChoicePref.setValue(mChoiceEntry.getSelectedString());
+
+            // Initializes the multi-select restriction entry and updates its corresponding
+            // shared preference value.
+            mMultiEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_MULTI_SELECT,
+                    mRestrictionsBundle.getStringArray(
+                            GetRestrictionsReceiver.KEY_MULTI_SELECT));
+            mMultiEntry.setType(RestrictionEntry.TYPE_MULTI_SELECT);
+            if (mMultiEntry.getAllSelectedStrings() != null) {
+                HashSet<String> set = new HashSet<String>();
+                final String[] values = mRestrictionsBundle.getStringArray(
+                        GetRestrictionsReceiver.KEY_MULTI_SELECT);
+                if (values != null) {
+                    for (String value : values) {
+                        set.add(value);
+                    }
+                }
+                mMultiPref.setValues(set);
+            }
+            mRestrictions.add(mBooleanEntry);
+            mRestrictions.add(mChoiceEntry);
+            mRestrictions.add(mMultiEntry);
+        }
+        // Prepares result to be passed back to the Settings app when the custom restrictions
+        // activity finishes.
+        Intent intent = new Intent(getActivity().getIntent());
+        intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST,
+                new ArrayList<RestrictionEntry>(mRestrictions));
+        getActivity().setResult(Activity.RESULT_OK, intent);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (preference == mBooleanPref) {
+            mBooleanEntry.setSelectedState((Boolean) newValue);
+        } else if (preference == mChoicePref) {
+            mChoiceEntry.setSelectedString((String) newValue);
+        } else if (preference == mMultiPref) {
+            String[] selectedStrings = new String[((Set<String>)newValue).size()];
+            int i = 0;
+            for (String value : (Set<String>) newValue) {
+                selectedStrings[i++] = value;
+            }
+            mMultiEntry.setAllSelectedStrings(selectedStrings);
+        }
+
+        // Saves all the app restriction configuration changes from the custom activity.
+        Intent intent = new Intent(getActivity().getIntent());
+        intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST,
+                new ArrayList<RestrictionEntry>(mRestrictions));
+        getActivity().setResult(Activity.RESULT_OK, intent);
+        return true;
+    }
+}
diff --git a/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.java b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.java
new file mode 100644
index 0000000..bb5a283
--- /dev/null
+++ b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.java
@@ -0,0 +1,162 @@
+/*
+ * 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.apprestrictions;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.RestrictionEntry;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+public class GetRestrictionsReceiver extends BroadcastReceiver {
+    private static final String TAG = GetRestrictionsReceiver.class.getSimpleName();
+
+    // Keys for referencing app restriction settings from the platform.
+    public static final String KEY_BOOLEAN = "boolean_key";
+    public static final String KEY_CHOICE = "choice_key";
+    public static final String KEY_MULTI_SELECT = "multi_key";
+
+    @Override
+    public void onReceive(final Context context, Intent intent) {
+        final PendingResult result = goAsync();
+
+        // If app restriction settings are already created, they will be included in the Bundle
+        // as key/value pairs.
+        final Bundle existingRestrictions =
+                intent.getBundleExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE);
+        Log.i(TAG, "existingRestrictions = " + existingRestrictions);
+
+        new Thread() {
+            public void run() {
+                createRestrictions(context, result, existingRestrictions);
+            }
+        }.start();
+    }
+
+    // Initializes a boolean type restriction entry.
+    public static void populateBooleanEntry(Resources res, RestrictionEntry entry) {
+        entry.setType(RestrictionEntry.TYPE_BOOLEAN);
+        entry.setTitle(res.getString(R.string.boolean_entry_title));
+    }
+
+    // Initializes a single choice type restriction entry.
+    public static void populateChoiceEntry(Resources res, RestrictionEntry reSingleChoice) {
+        String[] choiceEntries = res.getStringArray(R.array.choice_entry_entries);
+        String[] choiceValues = res.getStringArray(R.array.choice_entry_values);
+        if (reSingleChoice.getSelectedString() == null) {
+            reSingleChoice.setSelectedString(choiceValues[0]);
+        }
+        reSingleChoice.setTitle(res.getString(R.string.choice_entry_title));
+        reSingleChoice.setChoiceEntries(choiceEntries);
+        reSingleChoice.setChoiceValues(choiceValues);
+        reSingleChoice.setType(RestrictionEntry.TYPE_CHOICE);
+    }
+
+    // Initializes a multi-select type restriction entry.
+    public static void populateMultiEntry(Resources res, RestrictionEntry reMultiSelect) {
+        String[] multiEntries = res.getStringArray(R.array.multi_entry_entries);
+        String[] multiValues = res.getStringArray(R.array.multi_entry_values);
+        if (reMultiSelect.getAllSelectedStrings() == null) {
+            reMultiSelect.setAllSelectedStrings(new String[0]);
+        }
+        reMultiSelect.setTitle(res.getString(R.string.multi_entry_title));
+        reMultiSelect.setChoiceEntries(multiEntries);
+        reMultiSelect.setChoiceValues(multiValues);
+        reMultiSelect.setType(RestrictionEntry.TYPE_MULTI_SELECT);
+    }
+
+    // Demonstrates the creation of standard app restriction types: boolean, single choice, and
+    // multi-select.
+    private ArrayList<RestrictionEntry> initRestrictions(Context context) {
+        ArrayList<RestrictionEntry> newRestrictions = new ArrayList<RestrictionEntry>();
+        Resources res = context.getResources();
+
+        RestrictionEntry reBoolean = new RestrictionEntry(KEY_BOOLEAN, false);
+        populateBooleanEntry(res, reBoolean);
+        newRestrictions.add(reBoolean);
+
+        RestrictionEntry reSingleChoice = new RestrictionEntry(KEY_CHOICE, (String) null);
+        populateChoiceEntry(res, reSingleChoice);
+        newRestrictions.add(reSingleChoice);
+
+        RestrictionEntry reMultiSelect = new RestrictionEntry(KEY_MULTI_SELECT, (String[]) null);
+        populateMultiEntry(res, reMultiSelect);
+        newRestrictions.add(reMultiSelect);
+
+        return newRestrictions;
+    }
+
+    private void createRestrictions(Context context, PendingResult result,
+                                    Bundle existingRestrictions) {
+        // The incoming restrictions bundle contains key/value pairs representing existing app
+        // restrictions for this package. In order to retain existing app restrictions, you need to
+        // construct new restriction entries and then copy in any existing values for the new keys.
+        ArrayList<RestrictionEntry> newEntries = initRestrictions(context);
+
+        // If app restrictions were not previously configured for the package, create the default
+        // restrictions entries and return them.
+        if (existingRestrictions == null) {
+            Bundle extras = new Bundle();
+            extras.putParcelableArrayList(Intent.EXTRA_RESTRICTIONS_LIST, newEntries);
+            result.setResult(Activity.RESULT_OK, null, extras);
+            result.finish();
+            return;
+        }
+
+        // Retains current restriction settings by transferring existing restriction entries to
+        // new ones.
+        for (RestrictionEntry entry : newEntries) {
+            final String key = entry.getKey();
+            if (KEY_BOOLEAN.equals(key)) {
+                entry.setSelectedState(existingRestrictions.getBoolean(KEY_BOOLEAN));
+            } else if (KEY_CHOICE.equals(key)) {
+                if (existingRestrictions.containsKey(KEY_CHOICE)) {
+                    entry.setSelectedString(existingRestrictions.getString(KEY_CHOICE));
+                }
+            } else if (KEY_MULTI_SELECT.equals(key)) {
+                if (existingRestrictions.containsKey(KEY_MULTI_SELECT)) {
+                    entry.setAllSelectedStrings(existingRestrictions.getStringArray(key));
+                }
+            }
+        }
+
+        final Bundle extras = new Bundle();
+
+        // This path demonstrates the use of a custom app restriction activity instead of standard
+        // types.  When a custom activity is set, the standard types will not be available under
+        // app restriction settings.
+        //
+        // If your app has an existing activity for app restriction configuration, you can set it
+        // up with the intent here.
+        if (PreferenceManager.getDefaultSharedPreferences(context)
+                .getBoolean(MainActivity.CUSTOM_CONFIG_KEY, false)) {
+            final Intent customIntent = new Intent();
+            customIntent.setClass(context, CustomRestrictionsActivity.class);
+            extras.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, customIntent);
+        }
+
+        extras.putParcelableArrayList(Intent.EXTRA_RESTRICTIONS_LIST, newEntries);
+        result.setResult(Activity.RESULT_OK, null, extras);
+        result.finish();
+    }
+}
diff --git a/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.java b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.java
new file mode 100644
index 0000000..57c4439
--- /dev/null
+++ b/samples/browseable/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.java
@@ -0,0 +1,131 @@
+/*
+ * 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.apprestrictions;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.preference.PreferenceManager;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+/**
+ * This is the main user interface of the App Restrictions sample app.  It demonstrates the use
+ * of the App Restriction feature, which is available on Android 4.3 and above tablet devices
+ * with the multiuser feature.
+ *
+ * When launched under the primary User account, you can toggle between standard app restriction
+ * types and custom.  When launched under a restricted profile, this activity displays app
+ * restriction settings, if available.
+ *
+ * Follow these steps to exercise the feature:
+ * 1. If this is the primary user, go to Settings > Users.
+ * 2. Create a restricted profile, if one doesn't exist already.
+ * 3. Open the profile settings, locate the sample app, and tap the app restriction settings
+ *    icon. Configure app restrictions for the app.
+ * 4. In the lock screen, switch to the user's restricted profile, launch this sample app,
+ *    and see the configured app restrictions displayed.
+ */
+public class MainActivity extends Activity {
+    private Bundle mRestrictionsBundle;
+
+    // Checkbox to indicate whether custom or standard app restriction types are selected.
+    private CheckBox mCustomConfig;
+
+    public static final String CUSTOM_CONFIG_KEY = "custom_config";
+
+    private TextView mMultiEntryValue;
+    private TextView mChoiceEntryValue;
+    private TextView mBooleanEntryValue;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Sets up  user interface elements.
+        setContentView(R.layout.main);
+
+        mCustomConfig = (CheckBox) findViewById(R.id.custom_app_limits);
+        final boolean customChecked =
+                PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
+                        CUSTOM_CONFIG_KEY, false);
+        if (customChecked) mCustomConfig.setChecked(true);
+
+        mMultiEntryValue = (TextView) findViewById(R.id.multi_entry_id);
+        mChoiceEntryValue = (TextView) findViewById(R.id.choice_entry_id);
+        mBooleanEntryValue = (TextView) findViewById(R.id.boolean_entry_id);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        // If app restrictions are set for this package, when launched from a restricted profile,
+        // the settings are available in the returned Bundle as key/value pairs.
+        mRestrictionsBundle =
+                ((UserManager) getSystemService(Context.USER_SERVICE))
+                        .getApplicationRestrictions(getPackageName());
+        if (mRestrictionsBundle == null) {
+            mRestrictionsBundle = new Bundle();
+        }
+
+        // Reads and displays values from a boolean type restriction entry, if available.
+        // An app can utilize these settings to restrict its content under a restricted profile.
+        final String booleanRestrictionValue =
+                mRestrictionsBundle.containsKey(GetRestrictionsReceiver.KEY_BOOLEAN) ?
+                        mRestrictionsBundle.getBoolean(GetRestrictionsReceiver.KEY_BOOLEAN) + "":
+                        getString(R.string.na);
+        mBooleanEntryValue.setText(booleanRestrictionValue);
+
+        // Reads and displays values from a single choice restriction entry, if available.
+        final String singleChoiceRestrictionValue =
+                mRestrictionsBundle.containsKey(GetRestrictionsReceiver.KEY_CHOICE) ?
+                        mRestrictionsBundle.getString(GetRestrictionsReceiver.KEY_CHOICE) :
+                        getString(R.string.na);
+        mChoiceEntryValue.setText(singleChoiceRestrictionValue);
+
+        // Reads and displays values from a multi-select restriction entry, if available.
+        final String[] multiSelectValues =
+                mRestrictionsBundle.getStringArray(GetRestrictionsReceiver.KEY_MULTI_SELECT);
+        if (multiSelectValues == null || multiSelectValues.length == 0) {
+            mMultiEntryValue.setText(getString(R.string.na));
+        } else {
+            String tempValue = "";
+            for (String value : multiSelectValues) {
+                tempValue = tempValue + value + " ";
+            }
+            mMultiEntryValue.setText(tempValue);
+        }
+    }
+
+    /**
+     * Saves custom app restriction to the shared preference.
+     *
+     * This flag is used by {@code GetRestrictionsReceiver} to determine if a custom app
+     * restriction activity should be used.
+     *
+     * @param view
+     */
+    public void onCustomClicked(View view) {
+        final SharedPreferences.Editor editor =
+                PreferenceManager.getDefaultSharedPreferences(this).edit();
+        editor.putBoolean(CUSTOM_CONFIG_KEY, mCustomConfig.isChecked()).commit();
+    }
+}
diff --git a/samples/browseable/Basic/AndroidManifest.xml b/samples/browseable/Basic/AndroidManifest.xml
new file mode 100644
index 0000000..332c055
--- /dev/null
+++ b/samples/browseable/Basic/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.actionbarcompat.basic"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!-- ActionBarCompat provides an Action Bar from API v7 onwards -->
+    <uses-sdk
+        android:minSdkVersion="7"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/Theme.AppCompat"
+        android:allowBackup="true">
+
+        <activity android:name=".MainActivity">
+            <!-- Launcher Intent filter -->
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/browseable/Basic/_index.jd b/samples/browseable/Basic/_index.jd
new file mode 100644
index 0000000..72cffd9
--- /dev/null
+++ b/samples/browseable/Basic/_index.jd
@@ -0,0 +1,15 @@
+
+
+
+page.tags="Basic ActionBarCompat"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to create a basic action bar that displays
+action items. The sample shows how to inflate items from a menu resource, and
+how to add items programatically. To reduce clutter, rarely used actions are
+displayed in an action bar overflow.</p>
+<p>The activity in this sample extends from
+{@link android.support.v7.app.ActionBarActivity}, which provides the
+functionality necessary to display a compatible action bar on devices
+running Android 2.1 and higher.</p>
diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_action_location.png b/samples/browseable/Basic/res/drawable-hdpi/ic_action_location.png
new file mode 100644
index 0000000..a42b3ea
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-hdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_action_refresh.png b/samples/browseable/Basic/res/drawable-hdpi/ic_action_refresh.png
new file mode 100644
index 0000000..c9d295d
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-hdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_action_settings.png b/samples/browseable/Basic/res/drawable-hdpi/ic_action_settings.png
new file mode 100644
index 0000000..d3f981d
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-hdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/Basic/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..5bb19fb
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/Basic/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_action_location.png b/samples/browseable/Basic/res/drawable-mdpi/ic_action_location.png
new file mode 100644
index 0000000..eaf9774
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-mdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_action_refresh.png b/samples/browseable/Basic/res/drawable-mdpi/ic_action_refresh.png
new file mode 100644
index 0000000..eef97e9
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-mdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_action_settings.png b/samples/browseable/Basic/res/drawable-mdpi/ic_action_settings.png
new file mode 100644
index 0000000..fc2bf8c
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-mdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/Basic/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..5737b36
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_action_location.png b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_location.png
new file mode 100644
index 0000000..5f11cce
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_action_refresh.png b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_refresh.png
new file mode 100644
index 0000000..1027c9a
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_action_settings.png b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_settings.png
new file mode 100644
index 0000000..1b9acf2
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/Basic/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..31df043
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/Basic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..5087435
--- /dev/null
+++ b/samples/browseable/Basic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/layout/activity_main.xml b/samples/browseable/Basic/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/Basic/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/Basic/res/layout/sample_main.xml b/samples/browseable/Basic/res/layout/sample_main.xml
new file mode 100644
index 0000000..ff589e1
--- /dev/null
+++ b/samples/browseable/Basic/res/layout/sample_main.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="16dp"
+    android:text="@string/intro_message"
+    android:gravity="center" />
\ No newline at end of file
diff --git a/samples/browseable/Basic/res/menu/main.xml b/samples/browseable/Basic/res/menu/main.xml
new file mode 100644
index 0000000..a4dc5d1
--- /dev/null
+++ b/samples/browseable/Basic/res/menu/main.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+    As we're using ActionBarCompat, any action item attributes come from ActionBarCompat's XML
+    namespace instead of the android namespace. Here we've added a new support namespace added to
+    the menu element allowing us to use the 'showAsAction' attribute in a backwards compatible way.
+    Any other action item attributes used should be referenced from this namespace too
+    (actionProviderClass, actionViewClass, actionLayout).
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:support="http://schemas.android.com/apk/res-auto" >
+
+    <!--
+        Here we create an item, setting support:showAsAction to display the item as an action if
+        there's room on the compatible Action Bar.
+    -->
+    <item
+        android:id="@+id/menu_refresh"
+        android:icon="@drawable/ic_action_refresh"
+        android:title="@string/menu_refresh"
+        support:showAsAction="ifRoom"/>
+
+    <!-- Location item is added in onCreateOptionsMenu() -->
+
+    <!--
+        Here we set the settings item to always be in the overflow menu, by setting
+        support:showAsAction to never, so it is never displayed as an action item on the compatible
+        Action Bar.
+    -->
+    <item
+        android:id="@+id/menu_settings"
+        android:icon="@drawable/ic_action_settings"
+        android:title="@string/menu_settings"
+        support:showAsAction="never"/>
+
+</menu>
\ No newline at end of file
diff --git a/samples/browseable/Basic/res/values-sw600dp/dimens.xml b/samples/browseable/Basic/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/Basic/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/Basic/res/values-sw600dp/styles.xml b/samples/browseable/Basic/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/Basic/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/Basic/res/values/base-strings.xml b/samples/browseable/Basic/res/values/base-strings.xml
new file mode 100644
index 0000000..ff084ef
--- /dev/null
+++ b/samples/browseable/Basic/res/values/base-strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">Basic</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample shows you how to use ActionBarCompat to create a basic Activity which
+            displays action items. It covers inflating items from a menu resource, as well as adding
+            an item in code. Items that are not shown as action items on the Action Bar are
+            displayed in the action bar overflow.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/Basic/res/values/dimens.xml b/samples/browseable/Basic/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/Basic/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/Basic/res/values/ids.xml b/samples/browseable/Basic/res/values/ids.xml
new file mode 100644
index 0000000..0269815
--- /dev/null
+++ b/samples/browseable/Basic/res/values/ids.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+
+    <!--
+        Generate an id which can be used when the location menu item is added in MainActivity
+    -->
+    <item name="menu_location" type="id"/>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Basic/res/values/strings.xml b/samples/browseable/Basic/res/values/strings.xml
new file mode 100644
index 0000000..7867410
--- /dev/null
+++ b/samples/browseable/Basic/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+    <string name="menu_refresh">Refresh</string>
+    <string name="menu_location">Location</string>
+    <string name="menu_settings">Settings</string>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/Basic/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/Basic/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/Basic/src/com.example.android.actionbarcompat.basic/MainActivity.java b/samples/browseable/Basic/src/com.example.android.actionbarcompat.basic/MainActivity.java
new file mode 100644
index 0000000..8d3506f
--- /dev/null
+++ b/samples/browseable/Basic/src/com.example.android.actionbarcompat.basic/MainActivity.java
@@ -0,0 +1,87 @@
+/*
+ * 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.actionbarcompat.basic;
+
+import android.os.Bundle;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.app.ActionBarActivity;
+import android.view.Menu;
+import android.view.MenuItem;
+
+/**
+ * This sample shows you how to use ActionBarCompat to create a basic Activity which displays
+ * action items. It covers inflating items from a menu resource, as well as adding an item in code.
+ *
+ * This Activity extends from {@link ActionBarActivity}, which provides all of the function
+ * necessary to display a compatible Action Bar on devices running Android v2.1+.
+ */
+public class MainActivity extends ActionBarActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+    }
+
+    // BEGIN_INCLUDE(create_menu)
+    /**
+     * Use this method to instantiate your menu, and add your items to it. You
+     * should return true if you have added items to it and want the menu to be displayed.
+     */
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate our menu from the resources by using the menu inflater.
+        getMenuInflater().inflate(R.menu.main, menu);
+
+        // It is also possible add items here. Use a generated id from
+        // resources (ids.xml) to ensure that all menu ids are distinct.
+        MenuItem locationItem = menu.add(0, R.id.menu_location, 0, R.string.menu_location);
+        locationItem.setIcon(R.drawable.ic_action_location);
+
+        // Need to use MenuItemCompat methods to call any action item related methods
+        MenuItemCompat.setShowAsAction(locationItem, MenuItem.SHOW_AS_ACTION_IF_ROOM);
+
+        return true;
+    }
+    // END_INCLUDE(create_menu)
+
+    // BEGIN_INCLUDE(menu_item_selected)
+    /**
+     * This method is called when one of the menu items to selected. These items
+     * can be on the Action Bar, the overflow menu, or the standard options menu. You
+     * should return true if you handle the selection.
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.menu_refresh:
+                // Here we might start a background refresh task
+                return true;
+
+            case R.id.menu_location:
+                // Here we might call LocationManager.requestLocationUpdates()
+                return true;
+
+            case R.id.menu_settings:
+                // Here we would open up our settings activity
+                return true;
+        }
+
+        return super.onOptionsItemSelected(item);
+    }
+    // END_INCLUDE(menu_item_selected)
+}
diff --git a/samples/browseable/BasicAccessibility/AndroidManifest.xml b/samples/browseable/BasicAccessibility/AndroidManifest.xml
new file mode 100644
index 0000000..d61d789
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicaccessibility"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="11"
+        android:targetSdkVersion="16" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/BasicAccessibility/_index.jd b/samples/browseable/BasicAccessibility/_index.jd
new file mode 100644
index 0000000..761aa11
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/_index.jd
@@ -0,0 +1,12 @@
+
+
+
+page.tags="BasicAccessibility"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to create applications that are accessible for
+users with visual or physical disabilities.</p>
+<p>To learn how to make the most of the accessibility features built into
+the Android framework, see
+<a href="{@docRoot}training/accessibility/index.html">Implementing Accessibility</a>.</p>
diff --git a/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_discard.png b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_discard.png
new file mode 100644
index 0000000..ece5ad8
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_discard.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_info.png b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_info.png
new file mode 100644
index 0000000..da65dea
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..6c0b5ee
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-hdpi/partly_cloudy.png b/samples/browseable/BasicAccessibility/res/drawable-hdpi/partly_cloudy.png
new file mode 100644
index 0000000..b1b380c
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-hdpi/partly_cloudy.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicAccessibility/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_discard.png b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_discard.png
new file mode 100644
index 0000000..93483b6
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_discard.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_info.png b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_info.png
new file mode 100644
index 0000000..7f7e0a3
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..4ce0b82
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_discard.png b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_discard.png
new file mode 100644
index 0000000..94f7c8c
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_discard.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_info.png b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_info.png
new file mode 100644
index 0000000..4ede9ce
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ded707
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicAccessibility/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..74ae891
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAccessibility/res/layout/activity_main.xml b/samples/browseable/BasicAccessibility/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BasicAccessibility/res/layout/sample_main.xml b/samples/browseable/BasicAccessibility/res/layout/sample_main.xml
new file mode 100644
index 0000000..64f4f38
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/layout/sample_main.xml
@@ -0,0 +1,206 @@
+<!--
+Copyright (C) 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:tools="http://schemas.android.com/tools"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:gravity="center_horizontal">
+    <ScrollView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:fillViewport="false">
+        <RelativeLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:paddingLeft="@dimen/activity_horizontal_margin"
+                android:paddingRight="@dimen/activity_horizontal_margin"
+                android:paddingTop="@dimen/activity_vertical_margin"
+                android:paddingBottom="@dimen/activity_vertical_margin"
+                tools:context=".MainActivity"
+                >
+
+            <!-- Notice the presence of nextFocusDown/nextFocusUp on the elements below. You can
+            also use nextFocusLeft/nextFocusRight. This tells the system in what order elements
+            should be navigated through. If not present, the system will make a guess based on
+            element location in the layout. -->
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="Buttons"
+                    android:id="@+id/buttonsLabel"
+                    android:layout_alignParentTop="true"
+                    android:layout_alignParentLeft="true"
+                    android:nextFocusDown="@+id/composeButton"/>
+
+            <!-- This is a regular, text-based button. No contentDescription is needed, since the
+                 text field sufficiently describes the action performed. -->
+            <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/composeButtonLabel"
+                    android:id="@+id/composeButton"
+                    android:layout_below="@+id/buttonsLabel"
+                    android:layout_alignLeft="@+id/buttonsLabel"
+                    android:nextFocusUp="@+id/buttonsLabel"
+                    android:nextFocusDown="@+id/checkboxesLabel"
+                    />
+
+            <!-- The next two buttons are different types of image-based buttons. -->
+
+            <!-- BEGIN_INCLUDE (image_content_description) -->
+            <!-- Adding a contentDescription is needed for accessibility, since no text is present.
+            Since the contentDescription is read verbatim, you may want to be a bit more
+            descriptive than usual, such as adding "button" to the end of your description, if
+            appropriate. -->
+            <ImageButton
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/discardButton"
+                    android:layout_alignTop="@+id/composeButton"
+                    android:layout_toRightOf="@+id/composeButton"
+                    android:src="@drawable/ic_action_discard"
+                    android:layout_alignBottom="@+id/composeButton"
+                    android:contentDescription="@string/discardButtonDescription"
+                    android:scaleType="fitCenter"
+                    android:nextFocusUp="@+id/buttonsLabel"
+                    android:nextFocusDown="@+id/checkboxesLabel"
+                    />
+            <!-- END_INCLUDE (image_content_description) -->
+
+            <ImageButton
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/infoButton"
+                    android:layout_alignTop="@+id/discardButton"
+                    android:layout_toRightOf="@+id/discardButton"
+                    android:src="@drawable/ic_action_info"
+                    android:layout_alignBottom="@+id/discardButton"
+                    android:layout_alignRight="@+id/hyperspaceCheckbox"
+                    android:scaleType="fitCenter"
+                    android:background="?android:selectableItemBackground"
+                    android:padding="5dp"
+                    android:contentDescription="@string/infoButtonDescription"
+                    android:nextFocusUp="@+id/buttonsLabel"
+                    android:nextFocusDown="@+id/checkboxesLabel"
+            />
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/checkboxesLabel"
+                    android:id="@+id/checkboxesLabel"
+                    android:layout_below="@+id/composeButton"
+                    android:layout_alignLeft="@+id/composeButton"
+                    android:nextFocusUp="@+id/composeButton"
+                    android:nextFocusDown="@+id/jetpackCheckbox"
+                    />
+
+            <!-- Like a text-based button, checkboxes with text will often work correctly as-is.
+                 If your checkboxes do not have a text attribute, you will need to add a
+                 contentDescriptoin. -->
+            <CheckBox
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/jetpackCheckboxLabel"
+                    android:id="@+id/jetpackCheckbox"
+                    android:layout_below="@+id/checkboxesLabel"
+                    android:layout_alignLeft="@+id/checkboxesLabel"
+                    android:checked="false"
+                    android:nextFocusUp="@+id/checkboxesLabel"
+                    android:nextFocusDown="@+id/hyperspaceCheckbox"
+                    />
+
+            <CheckBox
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/hyperspaceCheckboxLabel"
+                    android:id="@+id/hyperspaceCheckbox"
+                    android:layout_below="@+id/jetpackCheckbox"
+                    android:layout_alignLeft="@+id/jetpackCheckbox"
+                    android:checked="false"
+                    android:nextFocusUp="@+id/jetpackCheckbox"
+                    android:nextFocusDown="@+id/imagesAndTextLabel"
+                    />
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/imagesAndTextLabel"
+                    android:id="@+id/imagesAndTextLabel"
+                    android:layout_below="@+id/hyperspaceCheckbox"
+                    android:layout_alignLeft="@+id/hyperspaceCheckbox"
+                    android:nextFocusUp="@+id/hyperspaceCheckbox"
+                    android:nextFocusDown="@+id/partlyCloudImage"
+                    />
+
+            <!-- Images should have a contentDescription if they convey any meaningful
+                 information. Images that are purely decorative may not need a contentDescription,
+                 however. -->
+            <ImageView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/partlyCloudyImage"
+                    android:layout_below="@+id/imagesAndTextLabel"
+                    android:layout_alignLeft="@+id/imagesAndTextLabel"
+                    android:src="@drawable/partly_cloudy"
+                    android:contentDescription="@string/partlyCloudyDescription"
+                    android:layout_alignRight="@+id/discardButton"
+                    android:nextFocusUp="@+id/imagesAndTextLabel"
+                    android:nextFocusDown="@+id/customViewLabel"
+                    />
+
+            <!-- TextViews are typically self describing, so do not need extra modifications. -->
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textAppearance="?android:attr/textAppearanceLarge"
+                    android:text="@string/temperature"
+                    android:textSize="60sp"
+                    android:id="@+id/temperatureText"
+                    android:layout_alignTop="@+id/partlyCloudyImage"
+                    android:layout_toRightOf="@+id/partlyCloudyImage"
+                    android:layout_alignBottom="@+id/partlyCloudyImage"
+                    android:gravity="center_vertical"
+                    android:nextFocusUp="@+id/imagesAndTextLabel"
+                    android:nextFocusDown="@+id/customViewLabel"
+                    />
+
+            <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/customViewLabel"
+                    android:id="@+id/customViewLabel"
+                    android:layout_below="@+id/partlyCloudyImage"
+                    android:layout_alignLeft="@+id/partlyCloudyImage"
+                    android:nextFocusUp="@+id/partlyCloudImage"
+                    android:nextFocusDown="@+id/dialView"
+                    />
+
+            <!-- Custom views require additonal code changes. See DialView.java for more
+                 details. -->
+            <com.example.android.basicaccessibility.DialView
+                    android:layout_width="200dp"
+                    android:layout_height="200dp"
+                    android:id="@+id/dialView"
+                    android:layout_below="@+id/customViewLabel"
+                    android:layout_alignLeft="@+id/partlyCloudyImage"
+                    android:nextFocusUp="@+id/customViewLabel"
+                    />
+
+        </RelativeLayout>
+    </ScrollView>
+</LinearLayout>
diff --git a/samples/browseable/BasicAccessibility/res/values-sw600dp/dimens.xml b/samples/browseable/BasicAccessibility/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicAccessibility/res/values-sw600dp/styles.xml b/samples/browseable/BasicAccessibility/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicAccessibility/res/values-sw720dp-land/dimens.xml b/samples/browseable/BasicAccessibility/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..2c2d431
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,21 @@
+<!--
+Copyright (C) 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+    <!-- Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. -->
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+</resources>
diff --git a/samples/browseable/BasicAccessibility/res/values/base-strings.xml b/samples/browseable/BasicAccessibility/res/values/base-strings.xml
new file mode 100644
index 0000000..20790c7
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/values/base-strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicAccessibility</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates how to create an accessible application, using a mix of different widgets demonstrating different ways of adding accessibility markup to a UI.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicAccessibility/res/values/dimens.xml b/samples/browseable/BasicAccessibility/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicAccessibility/res/values/strings.xml b/samples/browseable/BasicAccessibility/res/values/strings.xml
new file mode 100644
index 0000000..8340682
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/values/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+    <string name="composeButtonPressed">(Compose button pressed.)</string>
+    <string name="discardButtonPressed">(Discard button pressed.)</string>
+    <string name="infoButtonPressed">(Info button pressed.)</string>
+    <string name="composeButtonLabel">Compose</string>
+    <string name="discardButtonDescription">Discard Button</string>
+    <string name="infoButtonDescription">Info Button</string>
+    <string name="partlyCloudyDescription">Partly Cloudy</string>
+    <string name="checkboxesLabel">Checkboxes</string>
+    <string name="jetpackCheckboxLabel">Enable Jetpack</string>
+    <string name="hyperspaceCheckboxLabel">Enable Hyperspace Engines</string>
+    <string name="imagesAndTextLabel">Images &amp; Text</string>
+    <string name="temperature">53 °F</string>
+    <string name="customViewLabel">Custom View</string>
+</resources>
diff --git a/samples/browseable/BasicAccessibility/res/values/styles.xml b/samples/browseable/BasicAccessibility/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.basicaccessibility/DialView.java b/samples/browseable/BasicAccessibility/src/com.example.android.basicaccessibility/DialView.java
new file mode 100644
index 0000000..efdb449
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/src/com.example.android.basicaccessibility/DialView.java
@@ -0,0 +1,237 @@
+/*
+ * 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.basicaccessibility;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
+/**
+ * Custom view to demonstrate accessibility.
+ *
+ * <p>This view does not use any framework widgets, so does not get any accessibility features
+ * automatically. Instead, we use {@link android.view.accessibility.AccessibilityEvent} to provide accessibility hints to
+ * the OS.
+ *
+ * <p>For example, if TalkBack is enabled, users will be able to receive spoken feedback as they
+ * interact with this view.
+ *
+ * <p>More generally, this view renders a multi-position "dial" that can be used to select a value
+ * between 1 and 4. Each time the dial is clicked, the next position will be selected (modulo
+ * the maximum number of positions).
+ */
+public class DialView extends View {
+    private static int SELECTION_COUNT = 4;
+
+    private static float FONT_SIZE = 40f;
+    private float mWidth;
+    private float mHeight;
+    private float mWidthPadded;
+    private float mHeightPadded;
+    private Paint mTextPaint;
+    private Paint mDialPaint;
+    private float mRadius;
+    private int mActiveSelection;
+
+    /**
+     * Constructor that is called when inflating a view from XML. This is called
+     * when a view is being constructed from an XML file, supplying attributes
+     * that were specified in the XML file.
+     *
+     * <p>In our case, this constructor just calls init().
+     *
+     * @param context The Context the view is running in, through which it can
+     *                access the current theme, resources, etc.
+     * @param attrs   The attributes of the XML tag that is inflating the view.
+     * @see #View(android.content.Context, android.util.AttributeSet, int)
+     */
+    public DialView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    /**
+     * Helper method to initialize instance variables. Called by constructor.
+     */
+    private void init() {
+        // Paint styles used for rendering are created here, rather than at render-time. This
+        // is a performance optimization, since onDraw() will get called frequently.
+        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mTextPaint.setColor(Color.BLACK);
+        mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+        mTextPaint.setTextAlign(Paint.Align.CENTER);
+        mTextPaint.setTextSize(FONT_SIZE);
+
+        mDialPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mDialPaint.setColor(Color.GRAY);
+
+        // Initialize current selection. This will store where the dial's "indicator" is pointing.
+        mActiveSelection = 0;
+
+        // Setup onClick listener for this view. Rotates between each of the different selection
+        // states on each click.
+        //
+        // Notice that we call sendAccessibilityEvent here. Some AccessibilityEvents are generated
+        // by the system. However, custom views will typically need to send events manually as the
+        // user interacts with the view. The type of event sent will vary, depending on the nature
+        // of the view and how the user interacts with it.
+        //
+        // In this case, we are sending TYPE_VIEW_SELECTED rather than TYPE_VIEW_CLICKED, because
+        // clicking on this view selects a new value.
+        //
+        // We will give our AccessibilityEvent further information about the state of the view in
+        // onPopulateAccessibilityEvent(), which will be called automatically by the system
+        // for each AccessibilityEvent.
+        setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // Rotate selection to the next valid choice.
+                mActiveSelection = (mActiveSelection + 1) % SELECTION_COUNT;
+                // Send an AccessibilityEvent, since the user has interacted with the view.
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+                // Redraw the entire view. (Inefficient, but this is sufficient for demonstration
+                // purposes.)
+                invalidate();
+            }
+        });
+    }
+
+    /**
+     * This is where a View should populate outgoing accessibility events with its text content.
+     * While this method is free to modify event attributes other than text content, doing so
+     * should normally be performed in
+     * {@link #onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent)}.
+     * <p/>
+     * <p>Note that the behavior of this method will typically vary, depending on the type of
+     * accessibility event is passed into it. The allowed values also very, and are documented
+     * in {@link android.view.accessibility.AccessibilityEvent}.
+     * <p/>
+     * <p>Typically, this is where you'll describe the state of your custom view. You may also
+     * want to provide custom directions when the user has focused your view.
+     *
+     * @param event The accessibility event which to populate.
+     */
+    // BEGIN_INCLUDE (on_populate_accessibility_event)
+    @Override
+    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEvent(event);
+
+        // Detect what type of accessibility event is being passed in.
+        int eventType = event.getEventType();
+
+        // Common case: The user has interacted with our view in some way. State may or may not
+        // have been changed. Read out the current status of the view.
+        //
+        // We also set some other metadata which is not used by TalkBack, but could be used by
+        // other TTS engines.
+        if (eventType == AccessibilityEvent.TYPE_VIEW_SELECTED ||
+                eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
+            event.getText().add("Mode selected: " + Integer.toString(mActiveSelection + 1) + ".");
+            event.setItemCount(SELECTION_COUNT);
+            event.setCurrentItemIndex(mActiveSelection);
+        }
+
+        // When a user first focuses on our view, we'll also read out some simple instructions to
+        // make it clear that this is an interactive element.
+        if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
+            event.getText().add("Tap to change.");
+        }
+    }
+    // END_INCLUDE (on_populate_accessibility_event)
+
+    /**
+     * This is called during layout when the size of this view has changed. If
+     * you were just added to the view hierarchy, you're called with the old
+     * values of 0.
+     *
+     * <p>This is where we determine the drawing bounds for our custom view.
+     *
+     * @param w    Current width of this view.
+     * @param h    Current height of this view.
+     * @param oldw Old width of this view.
+     * @param oldh Old height of this view.
+     */
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        // Account for padding
+        float xPadding = (float) (getPaddingLeft() + getPaddingRight());
+        float yPadding = (float) (getPaddingTop() + getPaddingBottom());
+
+        // Compute available width/height
+        mWidth = w;
+        mHeight = h;
+        mWidthPadded = w - xPadding;
+        mHeightPadded = h - yPadding;
+        mRadius = (float) (Math.min(mWidth, mHeight) / 2 * 0.8);
+    }
+
+    /**
+     * Render view content.
+     *
+     * <p>We render an outer grey circle to serve as our "dial", and then render a smaller black
+     * circle to server as our indicator. The position for the indicator is determined based
+     * on mActiveSelection.
+     *
+     * @param canvas the canvas on which the background will be drawn
+     */
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        // Draw dial
+        canvas.drawCircle(mWidth / 2, mHeight / 2, (float) mRadius, mDialPaint);
+
+        // Draw text labels
+        final float labelRadius = mRadius + 10;
+        for (int i = 0; i < SELECTION_COUNT; i++) {
+            float[] xyData = computeXYForPosition(i, labelRadius);
+            float x = xyData[0];
+            float y = xyData[1];
+            canvas.drawText(Integer.toString(i + 1), x, y, mTextPaint);
+        }
+
+        // Draw indicator mark
+        final float markerRadius = mRadius - 35;
+        float[] xyData = computeXYForPosition(mActiveSelection, markerRadius);
+        float x = xyData[0];
+        float y = xyData[1];
+        canvas.drawCircle(x, y, 20, mTextPaint);
+    }
+
+    /**
+     * Compute the X/Y-coordinates for a label or indicator, given the position number and radius
+     * where the label should be drawn.
+     *
+     * @param pos    Zero based position index
+     * @param radius Radius where label/indicator is to be drawn.
+     * @return 2-element array. Element 0 is X-coordinate, element 1 is Y-coordinate.
+     */
+    private float[] computeXYForPosition(final int pos, final float radius) {
+        float[] result = new float[2];
+        Double startAngle = Math.PI * (9 / 8d);   // Angles are in radiansq
+        Double angle = startAngle + (pos * (Math.PI / 4));
+        result[0] = (float) (radius * Math.cos(angle)) + (mWidth / 2);
+        result[1] = (float) (radius * Math.sin(angle)) + (mHeight / 2);
+        return result;
+    }
+}
diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.basicaccessibility/MainActivity.java b/samples/browseable/BasicAccessibility/src/com.example.android.basicaccessibility/MainActivity.java
new file mode 100644
index 0000000..2777ad7
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/src/com.example.android.basicaccessibility/MainActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicaccessibility;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Basic activity class.
+ *
+ * <p>Responsible for rendering layout, and displaying some toasts to give buttons feedback.
+ * There's nothing terribly interesting in this class. All the interesting stuff is in
+ * res/layout/activity_main.xml and {@link DialView}.
+ */
+public class MainActivity extends Activity {
+
+    /**
+     * Standard onCreate() implementation. Sets R.layout.activity_main as the layout.
+     */
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+    }
+}
diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/Log.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogView.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml b/samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml
new file mode 100644
index 0000000..28d256c
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicandroidkeystore"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="19" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name"
+                  android:uiOptions="splitActionBarWhenNarrow">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/samples/browseable/BasicAndroidKeyStore/_index.jd b/samples/browseable/BasicAndroidKeyStore/_index.jd
new file mode 100644
index 0000000..5b7af60
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/_index.jd
@@ -0,0 +1,15 @@
+
+
+
+page.tags="BasicAndroidKeyStore"
+sample.group=Security
+@jd:body
+
+<p>This sample demonstrates how to use a {java.security.KeyStore} to
+safely create and store encryption keys that only your application can access.
+You can also sign data using those keys.</p>
+<p>To see this in action, run the sample application and click:</p>
+<ul>
+<li><strong>Create</strong> to create a new KeyPair.</li>
+<li><strong>Sign</strong> to sign some data using a KeyPair.</li>
+<li><strong>Verify</strong> to verify the data using the signature provided.</li>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml b/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml
new file mode 100644
index 0000000..bc5a575
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:id="@+id/sample_main_layout">
+    <TextView android:id="@+id/sample_output"
+              style="@style/Widget.SampleMessage"
+              android:layout_weight="1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:text="@string/intro_message" />
+    <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:background="@android:color/darker_gray"/>
+    <fragment
+            android:name="com.example.android.common.logger.LogFragment"
+            android:id="@+id/log_fragment"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/menu/main.xml b/samples/browseable/BasicAndroidKeyStore/res/menu/main.xml
new file mode 100644
index 0000000..74435ca
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/menu/main.xml
@@ -0,0 +1,30 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/btn_create_keys"
+          android:showAsAction="always"
+          android:title="@string/str_create_keys" />
+
+    <item android:id="@+id/btn_sign_data"
+          android:showAsAction="always"
+          android:title="@string/str_sign_data" />
+
+    <item android:id="@+id/btn_verify_data"
+          android:showAsAction="always"
+          android:title="@string/str_verify_data" />
+
+</menu>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/dimens.xml b/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/styles.xml b/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values/base-strings.xml b/samples/browseable/BasicAndroidKeyStore/res/values/base-strings.xml
new file mode 100644
index 0000000..0699a4a
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/values/base-strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicAndroidKeyStore</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+                Welcome to the <b>Basic Android Key Store</b> sample!\n\n
+                This sample demonstrates how to use the Android Key Store to safely create and store
+                encryption keys that only your application can access.  You can also sign data
+                using those keys.\n\n
+                To create a new KeyPair, click \"Create\".\n\n
+                To sign some data using a KeyPair, click \"Sign\".\n\n
+                To verify the data using the signature provided, click \"Verify\".\n\n            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values/dimens.xml b/samples/browseable/BasicAndroidKeyStore/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values/strings.xml b/samples/browseable/BasicAndroidKeyStore/res/values/strings.xml
new file mode 100644
index 0000000..25ad389
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <string name="str_create_keys">Create</string>
+    <string name="str_sign_data">Sign</string>
+    <string name="str_verify_data">Verify</string>
+</resources>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values/styles.xml b/samples/browseable/BasicAndroidKeyStore/res/values/styles.xml
new file mode 100644
index 0000000..d3f82ff
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/values/styles.xml
@@ -0,0 +1,51 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="AppTheme" parent="Theme.Base" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+
+    <style name="Widget.SampleOutput">
+        <item name="android:padding">@dimen/margin_medium</item>
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Log" parent="Widget.SampleOutput">
+        <item name="android:typeface">monospace</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.java
new file mode 100644
index 0000000..12873e8
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.java
@@ -0,0 +1,327 @@
+/*
+* 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.basicandroidkeystore;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.security.KeyPairGeneratorSpec;
+import android.support.v4.app.Fragment;
+import android.util.Base64;
+import android.view.MenuItem;
+
+import com.example.android.common.logger.Log;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.UnrecoverableEntryException;
+import java.security.cert.CertificateException;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import javax.security.auth.x500.X500Principal;
+
+public class BasicAndroidKeyStoreFragment extends Fragment {
+
+    public static final String TAG = "BasicAndroidKeyStoreFragment";
+
+    // BEGIN_INCLUDE(values)
+
+    public static final String SAMPLE_ALIAS = "myKey";
+
+    // Some sample data to sign, and later verify using the generated signature.
+    public static final String SAMPLE_INPUT="Hello, Android!";
+
+    // Just a handy place to store the signature in between signing and verifying.
+    public String mSignatureStr = null;
+
+    // You can store multiple key pairs in the Key Store.  The string used to refer to the Key you
+    // want to store, or later pull, is referred to as an "alias" in this case, because calling it
+    // a key, when you use it to retrieve a key, would just be irritating.
+    private String mAlias = null;
+
+    // END_INCLUDE(values)
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+        setAlias(SAMPLE_ALIAS);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.btn_create_keys:
+                try {
+                    createKeys(getActivity());
+                    Log.d(TAG, "Keys created");
+                    return true;
+                } catch (NoSuchAlgorithmException e) {
+                    Log.w(TAG, "RSA not supported", e);
+                } catch (InvalidAlgorithmParameterException e) {
+                    Log.w(TAG, "No such provider: AndroidKeyStore");
+                } catch (NoSuchProviderException e) {
+                    Log.w(TAG, "Invalid Algorithm Parameter Exception", e);
+                }
+                return true;
+            case R.id.btn_sign_data:
+                try {
+                    mSignatureStr = signData(SAMPLE_INPUT);
+                } catch (KeyStoreException e) {
+                    Log.w(TAG, "KeyStore not Initialized", e);
+                } catch (UnrecoverableEntryException e) {
+                    Log.w(TAG, "KeyPair not recovered", e);
+                } catch (NoSuchAlgorithmException e) {
+                    Log.w(TAG, "RSA not supported", e);
+                } catch (InvalidKeyException e) {
+                    Log.w(TAG, "Invalid Key", e);
+                } catch (SignatureException e) {
+                    Log.w(TAG, "Invalid Signature", e);
+                } catch (IOException e) {
+                    Log.w(TAG, "IO Exception", e);
+                } catch (CertificateException e) {
+                    Log.w(TAG, "Error occurred while loading certificates", e);
+                }
+                Log.d(TAG, "Signature: " + mSignatureStr);
+                return true;
+
+            case R.id.btn_verify_data:
+                boolean verified = false;
+                try {
+                    if (mSignatureStr != null) {
+                        verified = verifyData(SAMPLE_INPUT, mSignatureStr);
+                    }
+                } catch (KeyStoreException e) {
+                    Log.w(TAG, "KeyStore not Initialized", e);
+                } catch (CertificateException e) {
+                    Log.w(TAG, "Error occurred while loading certificates", e);
+                } catch (NoSuchAlgorithmException e) {
+                    Log.w(TAG, "RSA not supported", e);
+                } catch (IOException e) {
+                    Log.w(TAG, "IO Exception", e);
+                } catch (UnrecoverableEntryException e) {
+                    Log.w(TAG, "KeyPair not recovered", e);
+                } catch (InvalidKeyException e) {
+                    Log.w(TAG, "Invalid Key", e);
+                } catch (SignatureException e) {
+                    Log.w(TAG, "Invalid Signature", e);
+                }
+                if (verified) {
+                    Log.d(TAG, "Data Signature Verified");
+                } else {
+                    Log.d(TAG, "Data not verified.");
+                }
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Creates a public and private key and stores it using the Android Key Store, so that only
+     * this application will be able to access the keys.
+     */
+    public void createKeys(Context context) throws NoSuchProviderException,
+            NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+        // BEGIN_INCLUDE(create_valid_dates)
+        // Create a start and end time, for the validity range of the key pair that's about to be
+        // generated.
+        Calendar start = new GregorianCalendar();
+        Calendar end = new GregorianCalendar();
+        end.add(1, Calendar.YEAR);
+        //END_INCLUDE(create_valid_dates)
+
+
+        // BEGIN_INCLUDE(create_spec)
+        // The KeyPairGeneratorSpec object is how parameters for your key pair are passed
+        // to the KeyPairGenerator.  For a fun home game, count how many classes in this sample
+        // start with the phrase "KeyPair".
+        KeyPairGeneratorSpec spec =
+                new KeyPairGeneratorSpec.Builder(context)
+                        // You'll use the alias later to retrieve the key.  It's a key for the key!
+                        .setAlias(mAlias)
+                                // The subject used for the self-signed certificate of the generated pair
+                        .setSubject(new X500Principal("CN=" + mAlias))
+                                // The serial number used for the self-signed certificate of the
+                                // generated pair.
+                        .setSerialNumber(BigInteger.valueOf(1337))
+                                // Date range of validity for the generated pair.
+                        .setStartDate(start.getTime())
+                        .setEndDate(end.getTime())
+                        .build();
+        // END_INCLUDE(create_spec)
+
+        // BEGIN_INCLUDE(create_keypair)
+        // Initialize a KeyPair generator using the the intended algorithm (in this example, RSA
+        // and the KeyStore.  This example uses the AndroidKeyStore.
+        KeyPairGenerator kpGenerator = KeyPairGenerator
+                .getInstance(SecurityConstants.TYPE_RSA,
+                        SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
+        kpGenerator.initialize(spec);
+        KeyPair kp = kpGenerator.generateKeyPair();
+        Log.d(TAG, "Public Key is: " + kp.getPublic().toString());
+        // END_INCLUDE(create_keypair)
+    }
+
+    /**
+     * Signs the data using the key pair stored in the Android Key Store.  This signature can be
+     * used with the data later to verify it was signed by this application.
+     * @return A string encoding of the data signature generated
+     */
+    public String signData(String inputStr) throws KeyStoreException,
+            UnrecoverableEntryException, NoSuchAlgorithmException, InvalidKeyException,
+            SignatureException, IOException, CertificateException {
+        byte[] data = inputStr.getBytes();
+
+        // BEGIN_INCLUDE(sign_load_keystore)
+        KeyStore ks = KeyStore.getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
+
+        // Weird artifact of Java API.  If you don't have an InputStream to load, you still need
+        // to call "load", or it'll crash.
+        ks.load(null);
+
+        // Load the key pair from the Android Key Store
+        KeyStore.Entry entry = ks.getEntry(mAlias, null);
+
+        /* If the entry is null, keys were never stored under this alias.
+         * Debug steps in this situation would be:
+         * -Check the list of aliases by iterating over Keystore.aliases(), be sure the alias
+         *   exists.
+         * -If that's empty, verify they were both stored and pulled from the same keystore
+         *   "AndroidKeyStore"
+         */
+        if (entry == null) {
+            Log.w(TAG, "No key found under alias: " + mAlias);
+            Log.w(TAG, "Exiting signData()...");
+            return null;
+        }
+
+        /* If entry is not a KeyStore.PrivateKeyEntry, it might have gotten stored in a previous
+         * iteration of your application that was using some other mechanism, or been overwritten
+         * by something else using the same keystore with the same alias.
+         * You can determine the type using entry.getClass() and debug from there.
+         */
+        if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
+            Log.w(TAG, "Not an instance of a PrivateKeyEntry");
+            Log.w(TAG, "Exiting signData()...");
+            return null;
+        }
+        // END_INCLUDE(sign_data)
+
+        // BEGIN_INCLUDE(sign_create_signature)
+        // This class doesn't actually represent the signature,
+        // just the engine for creating/verifying signatures, using
+        // the specified algorithm.
+        Signature s = Signature.getInstance(SecurityConstants.SIGNATURE_SHA256withRSA);
+
+        // Initialize Signature using specified private key
+        s.initSign(((KeyStore.PrivateKeyEntry) entry).getPrivateKey());
+
+        // Sign the data, store the result as a Base64 encoded String.
+        s.update(data);
+        byte[] signature = s.sign();
+        String result = Base64.encodeToString(signature, Base64.DEFAULT);
+        // END_INCLUDE(sign_data)
+
+        return result;
+    }
+
+    /**
+     * Given some data and a signature, uses the key pair stored in the Android Key Store to verify
+     * that the data was signed by this application, using that key pair.
+     * @param input The data to be verified.
+     * @param signatureStr The signature provided for the data.
+     * @return A boolean value telling you whether the signature is valid or not.
+     */
+    public boolean verifyData(String input, String signatureStr) throws KeyStoreException,
+            CertificateException, NoSuchAlgorithmException, IOException,
+            UnrecoverableEntryException, InvalidKeyException, SignatureException {
+        byte[] data = input.getBytes();
+        byte[] signature;
+        // BEGIN_INCLUDE(decode_signature)
+
+        // Make sure the signature string exists.  If not, bail out, nothing to do.
+
+        if (signatureStr == null) {
+            Log.w(TAG, "Invalid signature.");
+            Log.w(TAG, "Exiting verifyData()...");
+            return false;
+        }
+
+        try {
+            // The signature is going to be examined as a byte array,
+            // not as a base64 encoded string.
+            signature = Base64.decode(signatureStr, Base64.DEFAULT);
+        } catch (IllegalArgumentException e) {
+            // signatureStr wasn't null, but might not have been encoded properly.
+            // It's not a valid Base64 string.
+            return false;
+        }
+        // END_INCLUDE(decode_signature)
+
+        KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
+
+        // Weird artifact of Java API.  If you don't have an InputStream to load, you still need
+        // to call "load", or it'll crash.
+        ks.load(null);
+
+        // Load the key pair from the Android Key Store
+        KeyStore.Entry entry = ks.getEntry(mAlias, null);
+
+        if (entry == null) {
+            Log.w(TAG, "No key found under alias: " + mAlias);
+            Log.w(TAG, "Exiting verifyData()...");
+            return false;
+        }
+
+        if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
+            Log.w(TAG, "Not an instance of a PrivateKeyEntry");
+            return false;
+        }
+
+        // This class doesn't actually represent the signature,
+        // just the engine for creating/verifying signatures, using
+        // the specified algorithm.
+        Signature s = Signature.getInstance(SecurityConstants.SIGNATURE_SHA256withRSA);
+
+        // BEGIN_INCLUDE(verify_data)
+        // Verify the data.
+        s.initVerify(((KeyStore.PrivateKeyEntry) entry).getCertificate());
+        s.update(data);
+        boolean valid = s.verify(signature);
+        return valid;
+        // END_INCLUDE(verify_data)
+    }
+
+    public void setAlias(String alias) {
+        mAlias = alias;
+    }
+}
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java
new file mode 100644
index 0000000..9f16565
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java
@@ -0,0 +1,78 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+
+
+package com.example.android.basicandroidkeystore;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description
+ * and a few action bar buttons.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    public static final String FRAGTAG = "BasicAndroidKeyStoreFragment";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        BasicAndroidKeyStoreFragment fragment = new BasicAndroidKeyStoreFragment();
+        transaction.add(fragment, FRAGTAG);
+        transaction.commit();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/SecurityConstants.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/SecurityConstants.java
new file mode 100644
index 0000000..ea5ee30
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/SecurityConstants.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicandroidkeystore;
+
+/**
+ * Helper class, contains several constants used when encrypting/decrypting data on Android.
+ * This class should not be considered a complete list of the algorithms, keystore types,
+ * or signature types within the Android Platform, only the more common ones.
+ */
+public class SecurityConstants {
+    public static final String KEYSTORE_PROVIDER_ANDROID_KEYSTORE = "AndroidKeyStore";
+
+    public static final String TYPE_RSA = "RSA";
+    public static final String TYPE_DSA = "DSA";
+    public static final String TYPE_BKS = "BKS";
+
+    public static final String SIGNATURE_SHA256withRSA = "SHA256withRSA";
+    public static final String SIGNATURE_SHA512withRSA = "SHA512withRSA";
+}
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+    public static final String TAG = "SampleActivityBase";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected  void onStart() {
+        super.onStart();
+        initializeLogging();
+    }
+
+    /** Set up targets to receive log data */
+    public void initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/Log.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogNode.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogView.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/BasicContactables/AndroidManifest.xml b/samples/browseable/BasicContactables/AndroidManifest.xml
new file mode 100644
index 0000000..62b9812
--- /dev/null
+++ b/samples/browseable/BasicContactables/AndroidManifest.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basiccontactables"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <!-- BEGIN_INCLUDE(contacts_permission) -->
+    <uses-permission android:name="android.permission.READ_CONTACTS"/>
+    <!-- END_INCLUDE(contacts_permission) -->
+    <uses-sdk
+        android:minSdkVersion="18"
+        android:targetSdkVersion="18" />
+    <permission android:name="android"></permission>
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/Theme.Sample" >
+        <activity
+            android:name="com.example.android.basiccontactables.MainActivity"
+            android:label="@string/app_name"
+            android:launchMode="singleTop">
+            <meta-data
+                android:name="android.app.searchable"
+                android:resource="@xml/searchable" />
+            <intent-filter>
+                <action android:name="android.intent.action.SEARCH" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/samples/browseable/BasicContactables/_index.jd b/samples/browseable/BasicContactables/_index.jd
new file mode 100644
index 0000000..f5bb3fc
--- /dev/null
+++ b/samples/browseable/BasicContactables/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="BasicContactables"
+sample.group=Content
+@jd:body
+
+<p>This sample demonstrates how to use the
+{@link android.provider.ContactsContract.Data} table to search for contacts.</p>
+<p>The sample sends consolidated query strings to the
+{@link android.provider.ContactsContract.Data} table to match both contact
+names and phone numbers. This approach helps to reduce the number of
+queries needed when searching the contacts database.</p>
diff --git a/samples/browseable/BasicContactables/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicContactables/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicContactables/res/drawable-hdpi/ic_search_api_holo_light.png b/samples/browseable/BasicContactables/res/drawable-hdpi/ic_search_api_holo_light.png
new file mode 100644
index 0000000..72e207b
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/drawable-hdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/samples/browseable/BasicContactables/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicContactables/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicContactables/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicContactables/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicContactables/res/drawable-mdpi/ic_search_api_holo_light.png b/samples/browseable/BasicContactables/res/drawable-mdpi/ic_search_api_holo_light.png
new file mode 100644
index 0000000..f2e26f8
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/drawable-mdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_search_api_holo_light.png b/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_search_api_holo_light.png
new file mode 100644
index 0000000..a4cdf1c
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_search_api_holo_light.png
Binary files differ
diff --git a/samples/browseable/BasicContactables/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicContactables/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicContactables/res/layout/activity_main.xml b/samples/browseable/BasicContactables/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BasicContactables/res/layout/sample_main.xml b/samples/browseable/BasicContactables/res/layout/sample_main.xml
new file mode 100755
index 0000000..52dc311
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/layout/sample_main.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView android:id="@+id/sample_output"
+        style="@style/Widget.SampleOutput"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/intro_message" />
+
+</ScrollView>
diff --git a/samples/browseable/BasicContactables/res/menu/main.xml b/samples/browseable/BasicContactables/res/menu/main.xml
new file mode 100644
index 0000000..4a530f1
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/menu/main.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/search"
+          android:title="@string/search_title"
+          android:icon="@drawable/ic_search_api_holo_light"
+          android:showAsAction="collapseActionView|ifRoom"
+          android:actionViewClass="android.widget.SearchView" />
+</menu>
diff --git a/samples/browseable/BasicContactables/res/values-sw600dp/dimens.xml b/samples/browseable/BasicContactables/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicContactables/res/values-sw600dp/styles.xml b/samples/browseable/BasicContactables/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicContactables/res/values/base-strings.xml b/samples/browseable/BasicContactables/res/values/base-strings.xml
new file mode 100644
index 0000000..0fc07ef
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/values/base-strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicContactables</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates how to use the Contactables table to search for contacts.
+            \n\nQuery strings sent to the Contactables table will match both contact names and phone numbers,
+            reducing the number of queries your application needs to use when searching the contacts database!
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicContactables/res/values/dimens.xml b/samples/browseable/BasicContactables/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicContactables/res/values/strings.xml b/samples/browseable/BasicContactables/res/values/strings.xml
new file mode 100755
index 0000000..a499fd2
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="sample_action">Sample action</string>
+    <string name="search_title">Search Contacts</string>
+</resources>
diff --git a/samples/browseable/BasicContactables/res/values/styles.xml b/samples/browseable/BasicContactables/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicContactables/res/xml/searchable.xml b/samples/browseable/BasicContactables/res/xml/searchable.xml
new file mode 100644
index 0000000..32fe1cc
--- /dev/null
+++ b/samples/browseable/BasicContactables/res/xml/searchable.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+  
+<searchable xmlns:android="http://schemas.android.com/apk/res/android"
+        android:label="@string/app_name"
+        android:hint="@string/search_title" />
diff --git a/samples/browseable/BasicContactables/src/com.example.android.basiccontactables/ContactablesLoaderCallbacks.java b/samples/browseable/BasicContactables/src/com.example.android.basiccontactables/ContactablesLoaderCallbacks.java
new file mode 100644
index 0000000..4fc4da7
--- /dev/null
+++ b/samples/browseable/BasicContactables/src/com.example.android.basiccontactables/ContactablesLoaderCallbacks.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.basiccontactables;
+
+import android.app.Activity;
+import android.app.LoaderManager;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Loader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract.CommonDataKinds;
+import android.util.Log;
+import android.widget.TextView;
+
+/**
+ * Helper class to handle all the callbacks that occur when interacting with loaders.  Most of the
+ * interesting code in this sample app will be in this file.
+ */
+public class ContactablesLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> {
+
+    Context mContext;
+
+    public static final String QUERY_KEY = "query";
+
+    public static final String TAG = "ContactablesLoaderCallbacks";
+
+    public ContactablesLoaderCallbacks(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public Loader<Cursor> onCreateLoader(int loaderIndex, Bundle args) {
+        // Where the Contactables table excels is matching text queries,
+        // not just data dumps from Contacts db.  One search term is used to query
+        // display name, email address and phone number.  In this case, the query was extracted
+        // from an incoming intent in the handleIntent() method, via the
+        // intent.getStringExtra() method.
+
+        // BEGIN_INCLUDE(uri_with_query)
+        String query = args.getString(QUERY_KEY);
+        Uri uri = Uri.withAppendedPath(
+                CommonDataKinds.Contactables.CONTENT_FILTER_URI, query);
+        // END_INCLUDE(uri_with_query)
+
+
+        // BEGIN_INCLUDE(cursor_loader)
+        // Easy way to limit the query to contacts with phone numbers.
+        String selection =
+                CommonDataKinds.Contactables.HAS_PHONE_NUMBER + " = " + 1;
+
+        // Sort results such that rows for the same contact stay together.
+        String sortBy = CommonDataKinds.Contactables.LOOKUP_KEY;
+
+        return new CursorLoader(
+                mContext,  // Context
+                uri,       // URI representing the table/resource to be queried
+                null,      // projection - the list of columns to return.  Null means "all"
+                selection, // selection - Which rows to return (condition rows must match)
+                null,      // selection args - can be provided separately and subbed into selection.
+                sortBy);   // string specifying sort order
+        // END_INCLUDE(cursor_loader)
+    }
+
+    @Override
+    public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
+        TextView tv  = (TextView) ((Activity)mContext).findViewById(R.id.sample_output);
+        if(tv == null) {
+            Log.e(TAG, "TextView is null?!");
+        } else if (mContext == null) {
+            Log.e(TAG, "Context is null?");
+        } else {
+            Log.e(TAG, "Nothing is null?!");
+        }
+
+        // Reset text in case of a previous query
+        tv.setText(mContext.getText(R.string.intro_message) + "\n\n");
+
+        if (cursor.getCount() == 0) {
+            return;
+        }
+
+        // Pulling the relevant value from the cursor requires knowing the column index to pull
+        // it from.
+        // BEGIN_INCLUDE(get_columns)
+        int phoneColumnIndex = cursor.getColumnIndex(CommonDataKinds.Phone.NUMBER);
+        int emailColumnIndex = cursor.getColumnIndex(CommonDataKinds.Email.ADDRESS);
+        int nameColumnIndex = cursor.getColumnIndex(CommonDataKinds.Contactables.DISPLAY_NAME);
+        int lookupColumnIndex = cursor.getColumnIndex(CommonDataKinds.Contactables.LOOKUP_KEY);
+        int typeColumnIndex = cursor.getColumnIndex(CommonDataKinds.Contactables.MIMETYPE);
+        // END_INCLUDE(get_columns)
+
+        cursor.moveToFirst();
+        // Lookup key is the easiest way to verify a row of data is for the same
+        // contact as the previous row.
+        String lookupKey = "";
+        do {
+            // BEGIN_INCLUDE(lookup_key)
+            String currentLookupKey = cursor.getString(lookupColumnIndex);
+            if (!lookupKey.equals(currentLookupKey)) {
+                String displayName = cursor.getString(nameColumnIndex);
+                tv.append(displayName + "\n");
+                lookupKey = currentLookupKey;
+            }
+            // END_INCLUDE(lookup_key)
+
+            // BEGIN_INCLUDE(retrieve_data)
+            // The data type can be determined using the mime type column.
+            String mimeType = cursor.getString(typeColumnIndex);
+            if (mimeType.equals(CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
+                tv.append("\tPhone Number: " + cursor.getString(phoneColumnIndex) + "\n");
+            } else if (mimeType.equals(CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
+                tv.append("\tEmail Address: " + cursor.getString(emailColumnIndex) + "\n");
+            }
+            // END_INCLUDE(retrieve_data)
+
+            // Look at DDMS to see all the columns returned by a query to Contactables.
+            // Behold, the firehose!
+            for(String column : cursor.getColumnNames()) {
+                Log.d(TAG, column + column + ": " +
+                        cursor.getString(cursor.getColumnIndex(column)) + "\n");
+            }
+        } while (cursor.moveToNext());
+    }
+
+    @Override
+    public void onLoaderReset(Loader<Cursor> cursorLoader) {
+    }
+}
diff --git a/samples/browseable/BasicContactables/src/com.example.android.basiccontactables/MainActivity.java b/samples/browseable/BasicContactables/src/com.example.android.basiccontactables/MainActivity.java
new file mode 100644
index 0000000..b8b074e
--- /dev/null
+++ b/samples/browseable/BasicContactables/src/com.example.android.basiccontactables/MainActivity.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.basiccontactables;
+
+import android.app.Activity;
+import android.app.SearchManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.Menu;
+import android.widget.SearchView;
+
+/**
+ * Simple one-activity app that takes a search term via the Action Bar
+ * and uses it as a query to search the contacts database via the Contactables
+ * table.
+ */
+public class MainActivity extends Activity {
+
+    public static final int CONTACT_QUERY_LOADER = 0;
+    public static final String QUERY_KEY = "query";
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+
+        if (getIntent() != null) {
+            handleIntent(getIntent());
+        }
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        handleIntent(intent);
+    }
+
+    /**
+     * Assuming this activity was started with a new intent, process the incoming information and
+     * react accordingly.
+     * @param intent
+     */
+    private void handleIntent(Intent intent) {
+        // Special processing of the incoming intent only occurs if the if the action specified
+        // by the intent is ACTION_SEARCH.
+        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+            // SearchManager.QUERY is the key that a SearchManager will use to send a query string
+            // to an Activity.
+            String query = intent.getStringExtra(SearchManager.QUERY);
+
+            // We need to create a bundle containing the query string to send along to the
+            // LoaderManager, which will be handling querying the database and returning results.
+            Bundle bundle = new Bundle();
+            bundle.putString(QUERY_KEY, query);
+
+            ContactablesLoaderCallbacks loaderCallbacks = new ContactablesLoaderCallbacks(this);
+
+            // Start the loader with the new query, and an object that will handle all callbacks.
+            getLoaderManager().restartLoader(CONTACT_QUERY_LOADER, bundle, loaderCallbacks);
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.main, menu);
+
+        // Associate searchable configuration with the SearchView
+        SearchManager searchManager =
+                (SearchManager) getSystemService(Context.SEARCH_SERVICE);
+        SearchView searchView =
+                (SearchView) menu.findItem(R.id.search).getActionView();
+        searchView.setSearchableInfo(
+                searchManager.getSearchableInfo(getComponentName()));
+
+        return true;
+    }
+}
diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/Log.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogView.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/BasicGestureDetect/AndroidManifest.xml b/samples/browseable/BasicGestureDetect/AndroidManifest.xml
new file mode 100644
index 0000000..1d7b3bd
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicgesturedetect"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name"
+                  android:uiOptions="splitActionBarWhenNarrow">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+
+</manifest>
diff --git a/samples/browseable/BasicGestureDetect/_index.jd b/samples/browseable/BasicGestureDetect/_index.jd
new file mode 100644
index 0000000..762217a
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/_index.jd
@@ -0,0 +1,12 @@
+
+
+
+page.tags="BasicGestureDetect"
+sample.group=Input
+@jd:body
+
+<p>This sample demonstrates how to use the {@link android.view.GestureDetector}
+API to detect simple dragging and tapping gestures.</p>
+<p>To learn more about detecting basic touch gestures such as scrolling,
+flinging, and double-tapping, see
+<a href="{@docRoot}training/gestures/detector.html">Detecting Common Gestures</a>.</p>
diff --git a/samples/browseable/BasicGestureDetect/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicGestureDetect/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicGestureDetect/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicGestureDetect/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicGestureDetect/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicGestureDetect/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicGestureDetect/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicGestureDetect/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicGestureDetect/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicGestureDetect/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicGestureDetect/res/layout/activity_main.xml b/samples/browseable/BasicGestureDetect/res/layout/activity_main.xml
new file mode 100755
index 0000000..bc5a575
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:id="@+id/sample_main_layout">
+    <TextView android:id="@+id/sample_output"
+              style="@style/Widget.SampleMessage"
+              android:layout_weight="1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:text="@string/intro_message" />
+    <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:background="@android:color/darker_gray"/>
+    <fragment
+            android:name="com.example.android.common.logger.LogFragment"
+            android:id="@+id/log_fragment"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/samples/browseable/BasicGestureDetect/res/menu/main.xml b/samples/browseable/BasicGestureDetect/res/menu/main.xml
new file mode 100644
index 0000000..2c3515d
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/sample_action"
+          android:showAsAction="ifRoom|withText"
+          android:title="@string/sample_action" />
+</menu>
diff --git a/samples/browseable/BasicGestureDetect/res/values-sw600dp/dimens.xml b/samples/browseable/BasicGestureDetect/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicGestureDetect/res/values-sw600dp/styles.xml b/samples/browseable/BasicGestureDetect/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicGestureDetect/res/values/base-strings.xml b/samples/browseable/BasicGestureDetect/res/values/base-strings.xml
new file mode 100644
index 0000000..e9ce7cd
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicGestureDetect</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            Welcome to Basic Gesture Detect!
+            In order to try this sample out, try dragging or tapping this text to see what happens!
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicGestureDetect/res/values/dimens.xml b/samples/browseable/BasicGestureDetect/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicGestureDetect/res/values/strings.xml b/samples/browseable/BasicGestureDetect/res/values/strings.xml
new file mode 100644
index 0000000..c047c4f
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+        <string name="sample_action">Clear Text</string>
+</resources>
diff --git a/samples/browseable/BasicGestureDetect/res/values/styles.xml b/samples/browseable/BasicGestureDetect/res/values/styles.xml
new file mode 100644
index 0000000..d3f82ff
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/res/values/styles.xml
@@ -0,0 +1,51 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="AppTheme" parent="Theme.Base" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+
+    <style name="Widget.SampleOutput">
+        <item name="android:padding">@dimen/margin_medium</item>
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Log" parent="Widget.SampleOutput">
+        <item name="android:typeface">monospace</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/BasicGestureDetectFragment.java b/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/BasicGestureDetectFragment.java
new file mode 100644
index 0000000..820e972
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/BasicGestureDetectFragment.java
@@ -0,0 +1,81 @@
+/*
+* Copyright (C) 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.basicgesturedetect;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.GestureDetector;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+
+public class BasicGestureDetectFragment extends Fragment{
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        View gestureView = getActivity().findViewById(R.id.sample_output);
+        gestureView.setClickable(true);
+        gestureView.setFocusable(true);
+
+        // BEGIN_INCLUDE(init_detector)
+
+        // First create the GestureListener that will include all our callbacks.
+        // Then create the GestureDetector, which takes that listener as an argument.
+        GestureDetector.SimpleOnGestureListener gestureListener = new GestureListener();
+        final GestureDetector gd = new GestureDetector(getActivity(), gestureListener);
+
+        /* For the view where gestures will occur, create an onTouchListener that sends
+         * all motion events to the gesture detector.  When the gesture detector
+         * actually detects an event, it will use the callbacks you created in the
+         * SimpleOnGestureListener to alert your application.
+        */
+
+        gestureView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View view, MotionEvent motionEvent) {
+                gd.onTouchEvent(motionEvent);
+                return false;
+            }
+        });
+        // END_INCLUDE(init_detector)
+    }
+
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.sample_action) {
+            clearLog();
+        }
+        return true;
+    }
+
+    public void clearLog() {
+        LogFragment logFragment =  ((LogFragment) getActivity().getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment));
+        logFragment.getLogView().setText("");
+    }
+}
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java b/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java
new file mode 100644
index 0000000..c2d2b6f
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicgesturedetect;
+
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+
+import com.example.android.common.logger.Log;
+
+public class GestureListener extends GestureDetector.SimpleOnGestureListener {
+
+    public static final String TAG = "GestureListener";
+
+    // BEGIN_INCLUDE(init_gestureListener)
+    @Override
+    public boolean onSingleTapUp(MotionEvent e) {
+        // Up motion completing a single tap occurred.
+        Log.i(TAG, "Single Tap Up");
+        return false;
+    }
+
+    @Override
+    public void onLongPress(MotionEvent e) {
+        // Touch has been long enough to indicate a long press.
+        // Does not indicate motion is complete yet (no up event necessarily)
+        Log.i(TAG, "Long Press");
+    }
+
+    @Override
+    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
+                            float distanceY) {
+        // User attempted to scroll
+        Log.i(TAG, "Scroll");
+        return false;
+    }
+
+    @Override
+    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+                           float velocityY) {
+        // Fling event occurred.  Notification of this one happens after an "up" event.
+        Log.i(TAG, "Fling");
+        return false;
+    }
+
+    @Override
+    public void onShowPress(MotionEvent e) {
+        // User performed a down event, and hasn't moved yet.
+        Log.i(TAG, "Show Press");
+    }
+
+    @Override
+    public boolean onDown(MotionEvent e) {
+        // "Down" event - User touched the screen.
+        Log.i(TAG, "Down");
+        return false;
+    }
+
+    @Override
+    public boolean onDoubleTap(MotionEvent e) {
+        // User tapped the screen twice.
+        Log.i(TAG, "Double tap");
+        return false;
+    }
+
+    @Override
+    public boolean onDoubleTapEvent(MotionEvent e) {
+        // Since double-tap is actually several events which are considered one aggregate
+        // gesture, there's a separate callback for an individual event within the doubletap
+        // occurring.  This occurs for down, up, and move.
+        Log.i(TAG, "Event within double tap");
+        return false;
+    }
+
+    @Override
+    public boolean onSingleTapConfirmed(MotionEvent e) {
+        // A confirmed single-tap event has occurred.  Only called when the detector has
+        // determined that the first tap stands alone, and is not part of a double tap.
+        Log.i(TAG, "Single tap confirmed");
+        return false;
+    }
+    // END_INCLUDE(init_gestureListener)
+}
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/MainActivity.java b/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/MainActivity.java
new file mode 100644
index 0000000..1547807
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/MainActivity.java
@@ -0,0 +1,80 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+
+
+package com.example.android.basicgesturedetect;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description
+ * and a few action bar buttons.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    public static final String FRAGTAG = "BasicGestureDetectFragment";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        if (getSupportFragmentManager().findFragmentByTag(FRAGTAG) == null ) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            BasicGestureDetectFragment fragment = new BasicGestureDetectFragment();
+            transaction.add(fragment, FRAGTAG);
+            transaction.commit();
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+    public static final String TAG = "SampleActivityBase";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected  void onStart() {
+        super.onStart();
+        initializeLogging();
+    }
+
+    /** Set up targets to receive log data */
+    public void initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/Log.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogNode.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogView.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/BasicImmersiveMode/AndroidManifest.xml b/samples/browseable/BasicImmersiveMode/AndroidManifest.xml
new file mode 100644
index 0000000..00b4e3c
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicimmersivemode"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name"
+                  android:uiOptions="splitActionBarWhenNarrow">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/samples/browseable/BasicImmersiveMode/_index.jd b/samples/browseable/BasicImmersiveMode/_index.jd
new file mode 100644
index 0000000..625e7a2
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/_index.jd
@@ -0,0 +1,12 @@
+
+
+
+page.tags="BasicImmersiveMode"
+sample.group=UI
+@jd:body
+
+<p>Android 4.4 introduces a way for you to provide a more immersive screen
+experience in your app, by letting users show or hide the status bar and
+navigation bar with a swipe.</p>
+<p>This sample demonstrates how to enable and disable this feature
+programmatically.</p>
diff --git a/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicImmersiveMode/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicImmersiveMode/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicImmersiveMode/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicImmersiveMode/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicImmersiveMode/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicImmersiveMode/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicImmersiveMode/res/layout/activity_main.xml b/samples/browseable/BasicImmersiveMode/res/layout/activity_main.xml
new file mode 100755
index 0000000..bc5a575
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:id="@+id/sample_main_layout">
+    <TextView android:id="@+id/sample_output"
+              style="@style/Widget.SampleMessage"
+              android:layout_weight="1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:text="@string/intro_message" />
+    <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:background="@android:color/darker_gray"/>
+    <fragment
+            android:name="com.example.android.common.logger.LogFragment"
+            android:id="@+id/log_fragment"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/samples/browseable/BasicImmersiveMode/res/menu/main.xml b/samples/browseable/BasicImmersiveMode/res/menu/main.xml
new file mode 100644
index 0000000..2c3515d
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/sample_action"
+          android:showAsAction="ifRoom|withText"
+          android:title="@string/sample_action" />
+</menu>
diff --git a/samples/browseable/BasicImmersiveMode/res/values-sw600dp/dimens.xml b/samples/browseable/BasicImmersiveMode/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicImmersiveMode/res/values-sw600dp/styles.xml b/samples/browseable/BasicImmersiveMode/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicImmersiveMode/res/values/base-strings.xml b/samples/browseable/BasicImmersiveMode/res/values/base-strings.xml
new file mode 100644
index 0000000..20a0647
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/values/base-strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicImmersiveMode</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            \"Immersive Mode\" is a new UI mode which improves \"hide full screen\" and
+            \"hide nav bar\" modes, by letting users swipe the bars in and out.  This sample
+            demonstrates how to enable and disable immersive mode programmatically.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicImmersiveMode/res/values/dimens.xml b/samples/browseable/BasicImmersiveMode/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicImmersiveMode/res/values/strings.xml b/samples/browseable/BasicImmersiveMode/res/values/strings.xml
new file mode 100644
index 0000000..e845261
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+        <string name="sample_action">Toggle Immersive Mode!</string>
+</resources>
diff --git a/samples/browseable/BasicImmersiveMode/res/values/styles.xml b/samples/browseable/BasicImmersiveMode/res/values/styles.xml
new file mode 100644
index 0000000..d3f82ff
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/res/values/styles.xml
@@ -0,0 +1,51 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="AppTheme" parent="Theme.Base" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+
+    <style name="Widget.SampleOutput">
+        <item name="android:padding">@dimen/margin_medium</item>
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Log" parent="Widget.SampleOutput">
+        <item name="android:typeface">monospace</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.basicimmersivemode/BasicImmersiveModeFragment.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.basicimmersivemode/BasicImmersiveModeFragment.java
new file mode 100644
index 0000000..a675e05
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.basicimmersivemode/BasicImmersiveModeFragment.java
@@ -0,0 +1,88 @@
+/*
+* Copyright (C) 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.example.android.basicimmersivemode;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.example.android.common.logger.Log;
+
+public class BasicImmersiveModeFragment extends Fragment {
+
+    public static final String TAG = "BasicImmersiveModeFragment";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        final View decorView = getActivity().getWindow().getDecorView();
+        decorView.setOnSystemUiVisibilityChangeListener(
+                new View.OnSystemUiVisibilityChangeListener() {
+                    @Override
+                    public void onSystemUiVisibilityChange(int i) {
+                        int height = decorView.getHeight();
+                        Log.i(TAG, "Current height: " + height);
+                    }
+                });
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.sample_action) {
+            toggleHideyBar();
+        }
+        return true;
+    }
+
+    /**
+     * Detects and toggles immersive mode.
+     */
+    public void toggleHideyBar() {
+        // BEGIN_INCLUDE (get_current_ui_flags)
+        // The UI options currently enabled are represented by a bitfield.
+        // getSystemUiVisibility() gives us that bitfield.
+        int uiOptions = getActivity().getWindow().getDecorView().getSystemUiVisibility();
+        int newUiOptions = uiOptions;
+        // END_INCLUDE (get_current_ui_flags)
+        // BEGIN_INCLUDE (toggle_ui_flags)
+        boolean isImmersiveModeEnabled =
+                ((uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) == uiOptions);
+        if (isImmersiveModeEnabled) {
+            Log.i(TAG, "Turning immersive mode mode off. ");
+        } else {
+            Log.i(TAG, "Turning immersive mode mode on.");
+        }
+
+        // Immersive mode: Backward compatible to KitKat (API 19).
+        // Note that this flag doesn't do anything by itself, it only augments the behavior
+        // of HIDE_NAVIGATION and FLAG_FULLSCREEN.  For the purposes of this sample
+        // all three flags are being toggled together.
+        // This sample uses the "sticky" form of immersive mode, which will let the user swipe
+        // the bars back in again, but will automatically make them disappear a few seconds later.
+        newUiOptions ^= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+        newUiOptions ^= View.SYSTEM_UI_FLAG_FULLSCREEN;
+        newUiOptions ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+        getActivity().getWindow().getDecorView().setSystemUiVisibility(newUiOptions);
+        //END_INCLUDE (set_ui_flags)
+    }
+}
diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.basicimmersivemode/MainActivity.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.basicimmersivemode/MainActivity.java
new file mode 100644
index 0000000..83e8f0e
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.basicimmersivemode/MainActivity.java
@@ -0,0 +1,80 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+
+
+package com.example.android.basicimmersivemode;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description
+ * and a few action bar buttons.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    public static final String FRAGTAG = "BasicImmersiveModeFragment";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        if (getSupportFragmentManager().findFragmentByTag(FRAGTAG) == null ) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            BasicImmersiveModeFragment fragment = new BasicImmersiveModeFragment();
+            transaction.add(fragment, FRAGTAG);
+            transaction.commit();
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+    public static final String TAG = "SampleActivityBase";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected  void onStart() {
+        super.onStart();
+        initializeLogging();
+    }
+
+    /** Set up targets to receive log data */
+    public void initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/Log.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogNode.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogView.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/BasicMediaDecoder/AndroidManifest.xml b/samples/browseable/BasicMediaDecoder/AndroidManifest.xml
new file mode 100644
index 0000000..d191491
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicmediadecoder"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="17"/>
+    <application
+        android:label="@string/app_name" android:icon="@drawable/ic_launcher">
+        <activity
+            android:name=".MainActivity"
+            android:screenOrientation="landscape"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/BasicMediaDecoder/_index.jd b/samples/browseable/BasicMediaDecoder/_index.jd
new file mode 100644
index 0000000..3d1a33c
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/_index.jd
@@ -0,0 +1,9 @@
+
+
+
+page.tags="BasicMediaDecoder"
+sample.group=Media
+@jd:body
+
+<p>This sample demonstrates how to decode a video using
+the {@link android.media.MediaCodec} API and render in an activity.</p>
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play.png b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play.png
new file mode 100755
index 0000000..dbfd337
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play_disabled.png b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play_disabled.png
new file mode 100755
index 0000000..e4310ef
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play_disabled.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..9bc536b
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play.png b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play.png
new file mode 100755
index 0000000..a2f198a
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play_disabled.png b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play_disabled.png
new file mode 100755
index 0000000..d69107b
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play_disabled.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..d656b21
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play.png b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play.png
new file mode 100755
index 0000000..9e63c90
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play_disabled.png b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play_disabled.png
new file mode 100755
index 0000000..2ff8c39
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play_disabled.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bbb9b16
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicMediaDecoder/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4a5c33f
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable/selector_play.xml b/samples/browseable/BasicMediaDecoder/res/drawable/selector_play.xml
new file mode 100644
index 0000000..2307135
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/drawable/selector_play.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true"
+          android:drawable="@drawable/ic_action_play"/>
+
+    <item android:state_enabled="false"
+          android:drawable="@drawable/ic_action_play_disabled"/>
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/BasicMediaDecoder/res/layout/activity_main.xml b/samples/browseable/BasicMediaDecoder/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BasicMediaDecoder/res/layout/sample_main.xml b/samples/browseable/BasicMediaDecoder/res/layout/sample_main.xml
new file mode 100644
index 0000000..7543120
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/layout/sample_main.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"
+    >
+    <TextureView
+        android:id="@+id/PlaybackView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+    <TextView
+            android:id="@+id/AttribView"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="right|bottom"
+            android:visibility="gone"
+            android:textColor="@android:color/holo_blue_bright"
+            android:text="@string/app_video_attrib"/>
+</FrameLayout>
+
diff --git a/samples/browseable/BasicMediaDecoder/res/menu/action_menu.xml b/samples/browseable/BasicMediaDecoder/res/menu/action_menu.xml
new file mode 100644
index 0000000..2b31a86
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/menu/action_menu.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_play"
+          android:icon="@drawable/selector_play"
+          android:title="Play"
+          android:showAsAction="ifRoom|withText" />
+</menu>
\ No newline at end of file
diff --git a/samples/browseable/BasicMediaDecoder/res/raw/vid_bigbuckbunny.mp4 b/samples/browseable/BasicMediaDecoder/res/raw/vid_bigbuckbunny.mp4
new file mode 100644
index 0000000..81d11df
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/raw/vid_bigbuckbunny.mp4
Binary files differ
diff --git a/samples/browseable/BasicMediaDecoder/res/values-sw600dp/dimens.xml b/samples/browseable/BasicMediaDecoder/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicMediaDecoder/res/values-sw600dp/styles.xml b/samples/browseable/BasicMediaDecoder/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicMediaDecoder/res/values/base-strings.xml b/samples/browseable/BasicMediaDecoder/res/values/base-strings.xml
new file mode 100644
index 0000000..94d02a8
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicMediaDecoder</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+             This activity uses a TextureView to render the frames of a video decoded using the
+             MediaCodec API.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicMediaDecoder/res/values/dimens.xml b/samples/browseable/BasicMediaDecoder/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicMediaDecoder/res/values/strings.xml b/samples/browseable/BasicMediaDecoder/res/values/strings.xml
new file mode 100644
index 0000000..2cf79ab
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <string name="app_video_attrib">(c) copyright 2008, Blender Foundation / www.bigbuckbunny.org
+    </string>
+</resources>
diff --git a/samples/browseable/BasicMediaDecoder/res/values/styles.xml b/samples/browseable/BasicMediaDecoder/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicMediaDecoder/src/com.example.android.basicmediadecoder/MainActivity.java b/samples/browseable/BasicMediaDecoder/src/com.example.android.basicmediadecoder/MainActivity.java
new file mode 100644
index 0000000..cac5bf2
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/src/com.example.android.basicmediadecoder/MainActivity.java
@@ -0,0 +1,189 @@
+/*
+ * 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.basicmediadecoder;
+
+
+import android.animation.TimeAnimator;
+import android.app.Activity;
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.View;
+import android.widget.TextView;
+
+import com.example.android.common.media.MediaCodecWrapper;
+
+import java.io.IOException;
+
+/**
+ * This activity uses a {@link android.view.TextureView} to render the frames of a video decoded using
+ * {@link android.media.MediaCodec} API.
+ */
+public class MainActivity extends Activity {
+
+    private TextureView mPlaybackView;
+    private TimeAnimator mTimeAnimator = new TimeAnimator();
+
+    // A utility that wraps up the underlying input and output buffer processing operations
+    // into an east to use API.
+    private MediaCodecWrapper mCodecWrapper;
+    private MediaExtractor mExtractor = new MediaExtractor();
+    TextView mAttribView = null;
+
+
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+        mPlaybackView = (TextureView) findViewById(R.id.PlaybackView);
+        mAttribView =  (TextView)findViewById(R.id.AttribView);
+
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.action_menu, menu);
+        return true;
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if(mTimeAnimator != null && mTimeAnimator.isRunning()) {
+            mTimeAnimator.end();
+        }
+
+        if (mCodecWrapper != null ) {
+            mCodecWrapper.stopAndRelease();
+            mExtractor.release();
+        }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.menu_play) {
+            mAttribView.setVisibility(View.VISIBLE);
+            startPlayback();
+            item.setEnabled(false);
+        }
+        return true;
+    }
+
+
+    public void startPlayback() {
+
+        // Construct a URI that points to the video resource that we want to play
+        Uri videoUri = Uri.parse("android.resource://"
+                + getPackageName() + "/"
+                + R.raw.vid_bigbuckbunny);
+
+        try {
+
+            // BEGIN_INCLUDE(initialize_extractor)
+            mExtractor.setDataSource(this, videoUri, null);
+            int nTracks = mExtractor.getTrackCount();
+
+            // Begin by unselecting all of the tracks in the extractor, so we won't see
+            // any tracks that we haven't explicitly selected.
+            for (int i = 0; i < nTracks; ++i) {
+                mExtractor.unselectTrack(i);
+            }
+
+
+            // Find the first video track in the stream. In a real-world application
+            // it's possible that the stream would contain multiple tracks, but this
+            // sample assumes that we just want to play the first one.
+            for (int i = 0; i < nTracks; ++i) {
+                // Try to create a video codec for this track. This call will return null if the
+                // track is not a video track, or not a recognized video format. Once it returns
+                // a valid MediaCodecWrapper, we can break out of the loop.
+                mCodecWrapper = MediaCodecWrapper.fromVideoFormat(mExtractor.getTrackFormat(i),
+                        new Surface(mPlaybackView.getSurfaceTexture()));
+                if (mCodecWrapper != null) {
+                    mExtractor.selectTrack(i);
+                    break;
+                }
+            }
+            // END_INCLUDE(initialize_extractor)
+
+
+
+
+            // By using a {@link TimeAnimator}, we can sync our media rendering commands with
+            // the system display frame rendering. The animator ticks as the {@link Choreographer}
+            // recieves VSYNC events.
+            mTimeAnimator.setTimeListener(new TimeAnimator.TimeListener() {
+                @Override
+                public void onTimeUpdate(final TimeAnimator animation,
+                                         final long totalTime,
+                                         final long deltaTime) {
+
+                    boolean isEos = ((mExtractor.getSampleFlags() & MediaCodec
+                            .BUFFER_FLAG_END_OF_STREAM) == MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+
+                    // BEGIN_INCLUDE(write_sample)
+                    if (!isEos) {
+                        // Try to submit the sample to the codec and if successful advance the
+                        // extractor to the next available sample to read.
+                        boolean result = mCodecWrapper.writeSample(mExtractor, false,
+                                mExtractor.getSampleTime(), mExtractor.getSampleFlags());
+
+                        if (result) {
+                            // Advancing the extractor is a blocking operation and it MUST be
+                            // executed outside the main thread in real applications.
+                            mExtractor.advance();
+                        }
+                    }
+                    // END_INCLUDE(write_sample)
+
+                    // Examine the sample at the head of the queue to see if its ready to be
+                    // rendered and is not zero sized End-of-Stream record.
+                    MediaCodec.BufferInfo out_bufferInfo = new MediaCodec.BufferInfo();
+                    mCodecWrapper.peekSample(out_bufferInfo);
+
+                    // BEGIN_INCLUDE(render_sample)
+                    if (out_bufferInfo.size <= 0 && isEos) {
+                        mTimeAnimator.end();
+                        mCodecWrapper.stopAndRelease();
+                        mExtractor.release();
+                    } else if (out_bufferInfo.presentationTimeUs / 1000 < totalTime) {
+                        // Pop the sample off the queue and send it to {@link Surface}
+                        mCodecWrapper.popSample(true);
+                    }
+                    // END_INCLUDE(render_sample)
+
+                }
+            });
+
+            // We're all set. Kick off the animator to process buffers and render video frames as
+            // they become available
+            mTimeAnimator.start();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/CameraHelper.java b/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/CameraHelper.java
new file mode 100644
index 0000000..1fa8416
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/CameraHelper.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.media;
+
+import android.annotation.TargetApi;
+import android.hardware.Camera;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Camera related utilities.
+ */
+public class CameraHelper {
+
+    public static final int MEDIA_TYPE_IMAGE = 1;
+    public static final int MEDIA_TYPE_VIDEO = 2;
+
+    /**
+     * Iterate over supported camera preview sizes to see which one best fits the
+     * dimensions of the given view while maintaining the aspect ratio. If none can,
+     * be lenient with the aspect ratio.
+     *
+     * @param sizes Supported camera preview sizes.
+     * @param w The width of the view.
+     * @param h The height of the view.
+     * @return Best match camera preview size to fit in the view.
+     */
+    public static  Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
+        // Use a very small tolerance because we want an exact match.
+        final double ASPECT_TOLERANCE = 0.1;
+        double targetRatio = (double) w / h;
+        if (sizes == null)
+            return null;
+
+        Camera.Size optimalSize = null;
+
+        // Start with max value and refine as we iterate over available preview sizes. This is the
+        // minimum difference between view and camera height.
+        double minDiff = Double.MAX_VALUE;
+
+        // Target view height
+        int targetHeight = h;
+
+        // Try to find a preview size that matches aspect ratio and the target view size.
+        // Iterate over all available sizes and pick the largest size that can fit in the view and
+        // still maintain the aspect ratio.
+        for (Camera.Size size : sizes) {
+            double ratio = (double) size.width / size.height;
+            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
+                continue;
+            if (Math.abs(size.height - targetHeight) < minDiff) {
+                optimalSize = size;
+                minDiff = Math.abs(size.height - targetHeight);
+            }
+        }
+
+        // Cannot find preview size that matches the aspect ratio, ignore the requirement
+        if (optimalSize == null) {
+            minDiff = Double.MAX_VALUE;
+            for (Camera.Size size : sizes) {
+                if (Math.abs(size.height - targetHeight) < minDiff) {
+                    optimalSize = size;
+                    minDiff = Math.abs(size.height - targetHeight);
+                }
+            }
+        }
+        return optimalSize;
+    }
+
+    /**
+     * @return the default camera on the device. Return null if there is no camera on the device.
+     */
+    public static Camera getDefaultCameraInstance() {
+        return Camera.open();
+    }
+
+
+    /**
+     * @return the default rear/back facing camera on the device. Returns null if camera is not
+     * available.
+     */
+    public static Camera getDefaultBackFacingCameraInstance() {
+        return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
+    }
+
+    /**
+     * @return the default front facing camera on the device. Returns null if camera is not
+     * available.
+     */
+    public static Camera getDefaultFrontFacingCameraInstance() {
+        return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);
+    }
+
+
+    /**
+     *
+     * @param position Physical position of the camera i.e Camera.CameraInfo.CAMERA_FACING_FRONT
+     *                 or Camera.CameraInfo.CAMERA_FACING_BACK.
+     * @return the default camera on the device. Returns null if camera is not available.
+     */
+    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
+    private static Camera getDefaultCamera(int position) {
+        // Find the total number of cameras available
+        int  mNumberOfCameras = Camera.getNumberOfCameras();
+
+        // Find the ID of the back-facing ("default") camera
+        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+        for (int i = 0; i < mNumberOfCameras; i++) {
+            Camera.getCameraInfo(i, cameraInfo);
+            if (cameraInfo.facing == position) {
+                return Camera.open(i);
+
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates a media file in the {@code Environment.DIRECTORY_PICTURES} directory. The directory
+     * is persistent and available to other applications like gallery.
+     *
+     * @param type Media type. Can be video or image.
+     * @return A file object pointing to the newly created file.
+     */
+    public  static File getOutputMediaFile(int type){
+        // To be safe, you should check that the SDCard is mounted
+        // using Environment.getExternalStorageState() before doing this.
+        if (!Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) {
+            return  null;
+        }
+
+        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_PICTURES), "CameraSample");
+        // This location works best if you want the created images to be shared
+        // between applications and persist after your app has been uninstalled.
+
+        // Create the storage directory if it does not exist
+        if (! mediaStorageDir.exists()){
+            if (! mediaStorageDir.mkdirs()) {
+                Log.d("CameraSample", "failed to create directory");
+                return null;
+            }
+        }
+
+        // Create a media file name
+        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+        File mediaFile;
+        if (type == MEDIA_TYPE_IMAGE){
+            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
+                    "IMG_"+ timeStamp + ".jpg");
+        } else if(type == MEDIA_TYPE_VIDEO) {
+            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
+                    "VID_"+ timeStamp + ".mp4");
+        } else {
+            return null;
+        }
+
+        return mediaFile;
+    }
+
+}
diff --git a/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java b/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java
new file mode 100644
index 0000000..a511221
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.media;
+
+import android.media.*;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * Simplifies the MediaCodec interface by wrapping around the buffer processing operations.
+ */
+public class MediaCodecWrapper {
+
+    // Handler to use for {@code OutputSampleListener} and {code OutputFormatChangedListener}
+    // callbacks
+    private Handler mHandler;
+
+
+    // Callback when media output format changes.
+    public interface OutputFormatChangedListener {
+        void outputFormatChanged(MediaCodecWrapper sender, MediaFormat newFormat);
+    }
+
+    private OutputFormatChangedListener mOutputFormatChangedListener = null;
+
+    /**
+     * Callback for decodes frames. Observers can register a listener for optional stream
+     * of decoded data
+     */
+    public interface OutputSampleListener {
+        void outputSample(MediaCodecWrapper sender, MediaCodec.BufferInfo info, ByteBuffer buffer);
+    }
+
+    /**
+     * The {@link MediaCodec} that is managed by this class.
+     */
+    private MediaCodec mDecoder;
+
+    // References to the internal buffers managed by the codec. The codec
+    // refers to these buffers by index, never by reference so it's up to us
+    // to keep track of which buffer is which.
+    private ByteBuffer[] mInputBuffers;
+    private ByteBuffer[] mOutputBuffers;
+
+    // Indices of the input buffers that are currently available for writing. We'll
+    // consume these in the order they were dequeued from the codec.
+    private Queue<Integer> mAvailableInputBuffers;
+
+    // Indices of the output buffers that currently hold valid data, in the order
+    // they were produced by the codec.
+    private Queue<Integer> mAvailableOutputBuffers;
+
+    // Information about each output buffer, by index. Each entry in this array
+    // is valid if and only if its index is currently contained in mAvailableOutputBuffers.
+    private MediaCodec.BufferInfo[] mOutputBufferInfo;
+
+    // An (optional) stream that will receive decoded data.
+    private OutputSampleListener mOutputSampleListener;
+
+    private MediaCodecWrapper(MediaCodec codec) {
+        mDecoder = codec;
+        codec.start();
+        mInputBuffers = codec.getInputBuffers();
+        mOutputBuffers = codec.getOutputBuffers();
+        mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
+        mAvailableInputBuffers = new ArrayDeque<Integer>(mOutputBuffers.length);
+        mAvailableOutputBuffers = new ArrayDeque<Integer>(mInputBuffers.length);
+    }
+
+    /**
+     * Releases resources and ends the encoding/decoding session.
+     */
+    public void stopAndRelease() {
+        mDecoder.stop();
+        mDecoder.release();
+        mDecoder = null;
+        mHandler = null;
+    }
+
+    /**
+     * Getter for the registered {@link OutputFormatChangedListener}
+     */
+    public OutputFormatChangedListener getOutputFormatChangedListener() {
+        return mOutputFormatChangedListener;
+    }
+
+    /**
+     *
+     * @param outputFormatChangedListener the listener for callback.
+     * @param handler message handler for posting the callback.
+     */
+    public void setOutputFormatChangedListener(final OutputFormatChangedListener
+            outputFormatChangedListener, Handler handler) {
+        mOutputFormatChangedListener = outputFormatChangedListener;
+
+        // Making sure we don't block ourselves due to a bad implementation of the callback by
+        // using a handler provided by client.
+        Looper looper;
+        mHandler = handler;
+        if (outputFormatChangedListener != null && mHandler == null) {
+            if ((looper = Looper.myLooper()) != null) {
+                mHandler = new Handler();
+            } else {
+                throw new IllegalArgumentException(
+                        "Looper doesn't exist in the calling thread");
+            }
+        }
+    }
+
+    /**
+     * Constructs the {@link MediaCodecWrapper} wrapper object around the video codec.
+     * The codec is created using the encapsulated information in the
+     * {@link MediaFormat} object.
+     *
+     * @param trackFormat The format of the media object to be decoded.
+     * @param surface Surface to render the decoded frames.
+     * @return
+     */
+    public static MediaCodecWrapper fromVideoFormat(final MediaFormat trackFormat,
+            Surface surface) {
+        MediaCodecWrapper result = null;
+        MediaCodec videoCodec = null;
+
+        // BEGIN_INCLUDE(create_codec)
+        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+
+        // Check to see if this is actually a video mime type. If it is, then create
+        // a codec that can decode this mime type.
+        if (mimeType.contains("video/")) {
+            videoCodec = MediaCodec.createDecoderByType(mimeType);
+            videoCodec.configure(trackFormat, surface, null,  0);
+
+        }
+
+        // If codec creation was successful, then create a wrapper object around the
+        // newly created codec.
+        if (videoCodec != null) {
+            result = new MediaCodecWrapper(videoCodec);
+        }
+        // END_INCLUDE(create_codec)
+
+        return result;
+    }
+
+
+    /**
+     * Write a media sample to the decoder.
+     *
+     * A "sample" here refers to a single atomic access unit in the media stream. The definition
+     * of "access unit" is dependent on the type of encoding used, but it typically refers to
+     * a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
+     * extracts data from a stream one sample at a time.
+     *
+     * @param input A ByteBuffer containing the input data for one sample. The buffer must be set
+     * up for reading, with its position set to the beginning of the sample data and its limit
+     * set to the end of the sample data.
+     *
+     * @param presentationTimeUs  The time, relative to the beginning of the media stream,
+     * at which this buffer should be rendered.
+     *
+     * @param flags Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
+     * int, int, long, int)}
+     *
+     * @throws MediaCodec.CryptoException
+     */
+    public boolean writeSample(final ByteBuffer input,
+            final MediaCodec.CryptoInfo crypto,
+            final long presentationTimeUs,
+            final int flags) throws MediaCodec.CryptoException, WriteException {
+        boolean result = false;
+        int size = input.remaining();
+
+        // check if we have dequed input buffers available from the codec
+        if (size > 0 &&  !mAvailableInputBuffers.isEmpty()) {
+            int index = mAvailableInputBuffers.remove();
+            ByteBuffer buffer = mInputBuffers[index];
+
+            // we can't write our sample to a lesser capacity input buffer.
+            if (size > buffer.capacity()) {
+                throw new MediaCodecWrapper.WriteException(String.format(
+                        "Insufficient capacity in MediaCodec buffer: "
+                            + "tried to write %d, buffer capacity is %d.",
+                        input.remaining(),
+                        buffer.capacity()));
+            }
+
+            buffer.clear();
+            buffer.put(input);
+
+            // Submit the buffer to the codec for decoding. The presentationTimeUs
+            // indicates the position (play time) for the current sample.
+            if (crypto == null) {
+                mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
+            } else {
+                mDecoder.queueSecureInputBuffer(index, 0, crypto, presentationTimeUs, flags);
+            }
+            result = true;
+        }
+        return result;
+    }
+
+    static MediaCodec.CryptoInfo cryptoInfo= new MediaCodec.CryptoInfo();
+
+    /**
+     * Write a media sample to the decoder.
+     *
+     * A "sample" here refers to a single atomic access unit in the media stream. The definition
+     * of "access unit" is dependent on the type of encoding used, but it typically refers to
+     * a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
+     * extracts data from a stream one sample at a time.
+     *
+     * @param extractor  Instance of {@link android.media.MediaExtractor} wrapping the media.
+     *
+     * @param presentationTimeUs The time, relative to the beginning of the media stream,
+     * at which this buffer should be rendered.
+     *
+     * @param flags  Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
+     * int, int, long, int)}
+     *
+     * @throws MediaCodec.CryptoException
+     */
+    public boolean writeSample(final MediaExtractor extractor,
+            final boolean isSecure,
+            final long presentationTimeUs,
+            int flags) {
+        boolean result = false;
+        boolean isEos = false;
+
+        if (!mAvailableInputBuffers.isEmpty()) {
+            int index = mAvailableInputBuffers.remove();
+            ByteBuffer buffer = mInputBuffers[index];
+
+            // reads the sample from the file using extractor into the buffer
+            int size = extractor.readSampleData(buffer, 0);
+            if (size <= 0) {
+                flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+            }
+
+            // Submit the buffer to the codec for decoding. The presentationTimeUs
+            // indicates the position (play time) for the current sample.
+            if (!isSecure) {
+                mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
+            } else {
+                extractor.getSampleCryptoInfo(cryptoInfo);
+                mDecoder.queueSecureInputBuffer(index, 0, cryptoInfo, presentationTimeUs, flags);
+            }
+
+            result = true;
+        }
+        return result;
+    }
+
+    /**
+     * Performs a peek() operation in the queue to extract media info for the buffer ready to be
+     * released i.e. the head element of the queue.
+     *
+     * @param out_bufferInfo An output var to hold the buffer info.
+     *
+     * @return True, if the peek was successful.
+     */
+    public boolean peekSample(MediaCodec.BufferInfo out_bufferInfo) {
+        // dequeue available buffers and synchronize our data structures with the codec.
+        update();
+        boolean result = false;
+        if (!mAvailableOutputBuffers.isEmpty()) {
+            int index = mAvailableOutputBuffers.peek();
+            MediaCodec.BufferInfo info = mOutputBufferInfo[index];
+            // metadata of the sample
+            out_bufferInfo.set(
+                    info.offset,
+                    info.size,
+                    info.presentationTimeUs,
+                    info.flags);
+            result = true;
+        }
+        return result;
+    }
+
+    /**
+     * Processes, releases and optionally renders the output buffer available at the head of the
+     * queue. All observers are notified with a callback. See {@link
+     * OutputSampleListener#outputSample(MediaCodecWrapper, android.media.MediaCodec.BufferInfo,
+     * java.nio.ByteBuffer)}
+     *
+     * @param render True, if the buffer is to be rendered on the {@link Surface} configured
+     *
+     */
+    public void popSample(boolean render) {
+        // dequeue available buffers and synchronize our data structures with the codec.
+        update();
+        if (!mAvailableOutputBuffers.isEmpty()) {
+            int index = mAvailableOutputBuffers.remove();
+
+            if (render && mOutputSampleListener != null) {
+                ByteBuffer buffer = mOutputBuffers[index];
+                MediaCodec.BufferInfo info = mOutputBufferInfo[index];
+                mOutputSampleListener.outputSample(this, info, buffer);
+            }
+
+            // releases the buffer back to the codec
+            mDecoder.releaseOutputBuffer(index, render);
+        }
+    }
+
+    /**
+     * Synchronize this object's state with the internal state of the wrapped
+     * MediaCodec.
+     */
+    private void update() {
+        // BEGIN_INCLUDE(update_codec_state)
+        int index;
+
+        // Get valid input buffers from the codec to fill later in the same order they were
+        // made available by the codec.
+        while ((index = mDecoder.dequeueInputBuffer(0)) != MediaCodec.INFO_TRY_AGAIN_LATER) {
+            mAvailableInputBuffers.add(index);
+        }
+
+
+        // Likewise with output buffers. If the output buffers have changed, start using the
+        // new set of output buffers. If the output format has changed, notify listeners.
+        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+        while ((index = mDecoder.dequeueOutputBuffer(info, 0)) !=  MediaCodec.INFO_TRY_AGAIN_LATER) {
+            switch (index) {
+                case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
+                    mOutputBuffers = mDecoder.getOutputBuffers();
+                    mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
+                    mAvailableOutputBuffers.clear();
+                    break;
+                case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
+                    if (mOutputFormatChangedListener != null) {
+                        mHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                mOutputFormatChangedListener
+                                        .outputFormatChanged(MediaCodecWrapper.this,
+                                                mDecoder.getOutputFormat());
+
+                            }
+                        });
+                    }
+                    break;
+                default:
+                    // Making sure the index is valid before adding to output buffers. We've already
+                    // handled INFO_TRY_AGAIN_LATER, INFO_OUTPUT_FORMAT_CHANGED &
+                    // INFO_OUTPUT_BUFFERS_CHANGED i.e all the other possible return codes but
+                    // asserting index value anyways for future-proofing the code.
+                    if(index >= 0) {
+                        mOutputBufferInfo[index] = info;
+                        mAvailableOutputBuffers.add(index);
+                    } else {
+                        throw new IllegalStateException("Unknown status from dequeueOutputBuffer");
+                    }
+                    break;
+            }
+
+        }
+        // END_INCLUDE(update_codec_state)
+
+    }
+
+    private class WriteException extends Throwable {
+        private WriteException(final String detailMessage) {
+            super(detailMessage);
+        }
+    }
+}
diff --git a/samples/browseable/BasicMediaRouter/AndroidManifest.xml b/samples/browseable/BasicMediaRouter/AndroidManifest.xml
new file mode 100644
index 0000000..33c20d5
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicmediarouter"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="17"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/samples/browseable/BasicMediaRouter/_index.jd b/samples/browseable/BasicMediaRouter/_index.jd
new file mode 100644
index 0000000..54081ed
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/_index.jd
@@ -0,0 +1,18 @@
+
+
+
+page.tags="BasicMediaRouter"
+sample.group=Media
+@jd:body
+
+<p>This sample demonstrates how to use the {@link android.media.MediaRouter}
+API to display content on a secondary display.</p>
+<p>To see this in action, run the sample and use the
+<strong>Media Route Action Item</strong> in the action bar to select an
+output device. If your device supports Miracast wireless displays, you may
+need to enable <strong>Wireless Display</strong> functionality in the
+system settings.</p>
+<p>You can also enable secondary screen simulation from the
+<em>Developer options</em> in the system Settings. Once
+connected, use the <strong>Change Color</strong> button to change the
+background color of the secondary screen.</p>
diff --git a/samples/browseable/BasicMediaRouter/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicMediaRouter/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMediaRouter/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicMediaRouter/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicMediaRouter/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicMediaRouter/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMediaRouter/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicMediaRouter/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMediaRouter/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicMediaRouter/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMediaRouter/res/layout/activity_main.xml b/samples/browseable/BasicMediaRouter/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BasicMediaRouter/res/layout/display.xml b/samples/browseable/BasicMediaRouter/res/layout/display.xml
new file mode 100644
index 0000000..47d5aa9
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/layout/display.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/display_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/display_text"
+        style="@style/DisplayLargeText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="" />
+
+    <TextView
+        android:id="@+id/display_smalltext"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text=""
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/BasicMediaRouter/res/layout/sample_main.xml b/samples/browseable/BasicMediaRouter/res/layout/sample_main.xml
new file mode 100644
index 0000000..2768514
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/layout/sample_main.xml
@@ -0,0 +1,32 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/LinearLayout1"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical"
+    tools:context=".MainActivity" >
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="5dp"
+        android:text="@string/intro_message" />
+
+    <TextView
+        android:id="@+id/textStatus"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:text="@string/secondary_notconnected"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:layout_margin="5dp" />
+
+    <Button
+        android:id="@+id/button1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:enabled="false"
+        android:text="@string/change_color" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/BasicMediaRouter/res/menu/main.xml b/samples/browseable/BasicMediaRouter/res/menu/main.xml
new file mode 100644
index 0000000..ebb6286
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/menu/main.xml
@@ -0,0 +1,12 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <!-- This ActionProvider is configured to  -->
+    <item
+        android:id="@+id/menu_media_route"
+        android:actionProviderClass="android.app.MediaRouteActionProvider"
+        android:orderInCategory="1"
+        android:showAsAction="always"
+        android:title="@string/menu_present_to"
+        android:visible="true"/>
+
+</menu>
\ No newline at end of file
diff --git a/samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml b/samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml b/samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicMediaRouter/res/values/base-strings.xml b/samples/browseable/BasicMediaRouter/res/values/base-strings.xml
new file mode 100644
index 0000000..2115771
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/values/base-strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicMediaRouter</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates the use of the MediaRouter API to display
+ content on a secondary display.\n\nUse the "Media Route Action Item" in the ActionBar
+ to select an output device. If your device supports Miracast wireless displays,
+ you may need to enable "Wireless Display" functionality in the system settings.
+ Secondary screen simulation can also be enabled from the "Developer Options".\n\n
+Once connected, use the "Change Color" button to change the background color of the secondary screen.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicMediaRouter/res/values/colors.xml b/samples/browseable/BasicMediaRouter/res/values/colors.xml
new file mode 100644
index 0000000..521d9cd
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/values/colors.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <item name="blue" type="color">#FF33B5E5</item>
+    <item name="purple" type="color">#FFAA66CC</item>
+    <item name="green" type="color">#FF99CC00</item>
+    <item name="orange" type="color">#FFFFBB33</item>
+    <item name="red" type="color">#FFFF4444</item>
+    <item name="darkblue" type="color">#FF0099CC</item>
+    <item name="darkpurple" type="color">#FF9933CC</item>
+    <item name="darkgreen" type="color">#FF669900</item>
+    <item name="darkorange" type="color">#FFFF8800</item>
+    <item name="darkred" type="color">#FFCC0000</item>
+
+    <integer-array name="androidcolors">
+        <item>@color/blue</item>
+        <item>@color/purple</item>
+        <item>@color/green</item>
+        <item>@color/orange</item>
+        <item>@color/red</item>
+        <item>@color/darkblue</item>
+        <item>@color/darkpurple</item>
+        <item>@color/darkgreen</item>
+        <item>@color/darkorange</item>
+        <item>@color/darkred</item>
+    </integer-array>
+
+</resources> 
\ No newline at end of file
diff --git a/samples/browseable/BasicMediaRouter/res/values/dimens.xml b/samples/browseable/BasicMediaRouter/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicMediaRouter/res/values/strings.xml b/samples/browseable/BasicMediaRouter/res/values/strings.xml
new file mode 100644
index 0000000..40c023a
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/values/strings.xml
@@ -0,0 +1,9 @@
+<resources>
+    <string name="menu_present_to">Present to</string>
+    <string name="title_activity_main">MainActivity</string>
+    <string name="secondary_connected">Connected to:\n%s</string>
+    <string name="secondary_notconnected">No secondary display connected.</string>
+    <string name="change_color">Change Color</string>
+    <string name="display_name">This display is: %s</string>
+    <string name="display_color">Background color: #%X</string>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BasicMediaRouter/res/values/styles.xml b/samples/browseable/BasicMediaRouter/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.basicmediarouter/MainActivity.java b/samples/browseable/BasicMediaRouter/src/com.example.android.basicmediarouter/MainActivity.java
new file mode 100644
index 0000000..23b2709
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/src/com.example.android.basicmediarouter/MainActivity.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicmediarouter;
+
+import android.app.Activity;
+import android.app.MediaRouteActionProvider;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+import android.os.Bundle;
+import android.view.Display;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * <p>
+ * This sample demonstrates the use of the MediaRouter API to show content on a
+ * secondary display using a {@link android.app.Presentation}.
+ * </p>
+ * <p>
+ * The activity uses the {@link android.media.MediaRouter} API to automatically detect when a
+ * presentation display is available and to allow the user to control the media
+ * routes using a menu item provided by the {@link android.app.MediaRouteActionProvider}.
+ * When a presentation display is available a {@link android.app.Presentation} (implemented
+ * as a {@link SamplePresentation}) is shown on the preferred display. A button
+ * toggles the background color of the secondary screen to show the interaction
+ * between the primary and secondary screens.
+ * </p>
+ * <p>
+ * This sample requires an HDMI or Wifi display. Alternatively, the
+ * "Simulate secondary displays" feature in Development Settings can be enabled
+ * to simulate secondary displays.
+ * </p>
+ *
+ * @see android.app.Presentation
+ * @see android.media.MediaRouter
+ */
+public class MainActivity extends Activity {
+
+    private MediaRouter mMediaRouter;
+
+    // Active Presentation, set to null if no secondary screen is enabled
+    private SamplePresentation mPresentation;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.sample_main);
+        mTextStatus = (TextView) findViewById(R.id.textStatus);
+
+        // get the list of background colors
+        mColors = getResources().getIntArray(R.array.androidcolors);
+
+        // Enable clicks on the 'change color' button
+        mButton = (Button) findViewById(R.id.button1);
+        mButton.setOnClickListener(new View.OnClickListener() {
+
+            @Override
+            public void onClick(View v) {
+                showNextColor();
+            }
+        });
+
+        // BEGIN_INCLUDE(getMediaRouter)
+        // Get the MediaRouter service
+        mMediaRouter = (MediaRouter) getSystemService(Context.MEDIA_ROUTER_SERVICE);
+        // END_INCLUDE(getMediaRouter)
+    }
+
+    /**
+     * Implementing a {@link android.media.MediaRouter.Callback} to update the displayed
+     * {@link android.app.Presentation} when a route is selected, unselected or the
+     * presentation display has changed. The provided stub implementation
+     * {@link android.media.MediaRouter.SimpleCallback} is extended and only
+     * {@link android.media.MediaRouter.SimpleCallback#onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo)}
+     * ,
+     * {@link android.media.MediaRouter.SimpleCallback#onRouteUnselected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo)}
+     * and
+     * {@link android.media.MediaRouter.SimpleCallback#onRoutePresentationDisplayChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo)}
+     * are overridden to update the displayed {@link android.app.Presentation} in
+     * {@link #updatePresentation()}. These callbacks enable or disable the
+     * second screen presentation based on the routing provided by the
+     * {@link android.media.MediaRouter} for {@link android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO}
+     * streams. @
+     */
+    private final MediaRouter.SimpleCallback mMediaRouterCallback =
+            new MediaRouter.SimpleCallback() {
+
+                // BEGIN_INCLUDE(SimpleCallback)
+                /**
+                 * A new route has been selected as active. Disable the current
+                 * route and enable the new one.
+                 */
+                @Override
+                public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
+                    updatePresentation();
+                }
+
+                /**
+                 * The route has been unselected.
+                 */
+                @Override
+                public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
+                    updatePresentation();
+
+                }
+
+                /**
+                 * The route's presentation display has changed. This callback
+                 * is called when the presentation has been activated, removed
+                 * or its properties have changed.
+                 */
+                @Override
+                public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
+                    updatePresentation();
+                }
+                // END_INCLUDE(SimpleCallback)
+            };
+
+    /**
+     * Updates the displayed presentation to enable a secondary screen if it has
+     * been selected in the {@link android.media.MediaRouter} for the
+     * {@link android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO} type. If no screen has been
+     * selected by the {@link android.media.MediaRouter}, the current screen is disabled.
+     * Otherwise a new {@link SamplePresentation} is initialized and shown on
+     * the secondary screen.
+     */
+    private void updatePresentation() {
+
+        // BEGIN_INCLUDE(updatePresentationInit)
+        // Get the selected route for live video
+        RouteInfo selectedRoute = mMediaRouter.getSelectedRoute(
+                MediaRouter.ROUTE_TYPE_LIVE_VIDEO);
+
+        // Get its Display if a valid route has been selected
+        Display selectedDisplay = null;
+        if (selectedRoute != null) {
+            selectedDisplay = selectedRoute.getPresentationDisplay();
+        }
+        // END_INCLUDE(updatePresentationInit)
+
+        // BEGIN_INCLUDE(updatePresentationDismiss)
+        /*
+         * Dismiss the current presentation if the display has changed or no new
+         * route has been selected
+         */
+        if (mPresentation != null && mPresentation.getDisplay() != selectedDisplay) {
+            mPresentation.dismiss();
+            mPresentation = null;
+            mButton.setEnabled(false);
+            mTextStatus.setText(R.string.secondary_notconnected);
+        }
+        // END_INCLUDE(updatePresentationDismiss)
+
+        // BEGIN_INCLUDE(updatePresentationNew)
+        /*
+         * Show a new presentation if the previous one has been dismissed and a
+         * route has been selected.
+         */
+        if (mPresentation == null && selectedDisplay != null) {
+
+            // Initialise a new Presentation for the Display
+            mPresentation = new SamplePresentation(this, selectedDisplay);
+            mPresentation.setOnDismissListener(mOnDismissListener);
+
+            // Try to show the presentation, this might fail if the display has
+            // gone away in the mean time
+            try {
+                mPresentation.show();
+                mTextStatus.setText(getResources().getString(R.string.secondary_connected,
+                        selectedRoute.getName(MainActivity.this)));
+                mButton.setEnabled(true);
+                showNextColor();
+            } catch (WindowManager.InvalidDisplayException ex) {
+                // Couldn't show presentation - display was already removed
+                mPresentation = null;
+            }
+        }
+        // END_INCLUDE(updatePresentationNew)
+
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        // BEGIN_INCLUDE(addCallback)
+        // Register a callback for all events related to live video devices
+        mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_LIVE_VIDEO, mMediaRouterCallback);
+        // END_INCLUDE(addCallback)
+
+        // Show the 'Not connected' status message
+        mButton.setEnabled(false);
+        mTextStatus.setText(R.string.secondary_notconnected);
+
+        // Update the displays based on the currently active routes
+        updatePresentation();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+
+        // BEGIN_INCLUDE(onPause)
+        // Stop listening for changes to media routes.
+        mMediaRouter.removeCallback(mMediaRouterCallback);
+        // END_INCLUDE(onPause)
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        // BEGIN_INCLUDE(onStop)
+        // Dismiss the presentation when the activity is not visible.
+        if (mPresentation != null) {
+            mPresentation.dismiss();
+            mPresentation = null;
+        }
+        // BEGIN_INCLUDE(onStop)
+    }
+
+    /**
+     * Inflates the ActionBar or options menu. The menu file defines an item for
+     * the {@link android.app.MediaRouteActionProvider}, which is registered here for all
+     * live video devices using {@link android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO}.
+     */
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+
+        getMenuInflater().inflate(R.menu.main, menu);
+
+        // BEGIN_INCLUDE(MediaRouteActionProvider)
+        // Configure the media router action provider
+        MenuItem mediaRouteMenuItem = menu.findItem(R.id.menu_media_route);
+        MediaRouteActionProvider mediaRouteActionProvider =
+                (MediaRouteActionProvider) mediaRouteMenuItem.getActionProvider();
+        mediaRouteActionProvider.setRouteTypes(MediaRouter.ROUTE_TYPE_LIVE_VIDEO);
+        // BEGIN_INCLUDE(MediaRouteActionProvider)
+
+        return true;
+    }
+
+    /**
+     * Listens for dismissal of the {@link SamplePresentation} and removes its
+     * reference.
+     */
+    private final DialogInterface.OnDismissListener mOnDismissListener =
+            new DialogInterface.OnDismissListener() {
+                @Override
+                public void onDismiss(DialogInterface dialog) {
+                    if (dialog == mPresentation) {
+                        mPresentation = null;
+                    }
+                }
+            };
+
+    // Views used to display status information on the primary screen
+    private TextView mTextStatus;
+    private Button mButton;
+
+    // selected color index
+    private int mColor = 0;
+
+    // background colors
+    public int[] mColors;
+
+    /**
+     * Displays the next color on the secondary screen if it is activate.
+     */
+    private void showNextColor() {
+        if (mPresentation != null) {
+            // a second screen is active and initialized, show the next color
+            mPresentation.setColor(mColors[mColor]);
+            mColor = (mColor + 1) % mColors.length;
+        }
+    }
+
+}
diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.basicmediarouter/SamplePresentation.java b/samples/browseable/BasicMediaRouter/src/com.example.android.basicmediarouter/SamplePresentation.java
new file mode 100644
index 0000000..ac1f40f
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/src/com.example.android.basicmediarouter/SamplePresentation.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicmediarouter;
+
+import android.app.Presentation;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.Display;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * <p>
+ * A {@link android.app.Presentation} used to demonstrate interaction between primary and
+ * secondary screens.
+ * </p>
+ * <p>
+ * It displays the name of the display in which it has been embedded (see
+ * {@link android.app.Presentation#getDisplay()}) and exposes a facility to change its
+ * background color and display its text.
+ * </p>
+ */
+public class SamplePresentation extends Presentation {
+
+    private LinearLayout mLayout;
+    private TextView mText;
+
+    public SamplePresentation(Context outerContext, Display display) {
+        super(outerContext, display);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set the content view to the custom layout
+        setContentView(R.layout.display);
+
+        // Get the Views
+        mLayout = (LinearLayout) findViewById(R.id.display_layout);
+        mText = (TextView) findViewById(R.id.display_text);
+
+        /*
+         * Show the name of the display this presentation was embedded in.
+         */
+        TextView smallText = (TextView) findViewById(R.id.display_smalltext);
+        final String name = getDisplay().getName();
+        smallText.setText(getResources().getString(R.string.display_name, name));
+    }
+
+    /**
+     * Set the background color of the layout and display the color as a String.
+     *
+     * @param color The background color
+     */
+    public void setColor(int color) {
+        mLayout.setBackgroundColor(color);
+
+        // Display the color as a string on screen
+        String s = getResources().getString(R.string.display_color, color);
+        mText.setText(s);
+    }
+
+}
diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/Log.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogView.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/BasicMultitouch/AndroidManifest.xml b/samples/browseable/BasicMultitouch/AndroidManifest.xml
new file mode 100644
index 0000000..043345c
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicmultitouch"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/browseable/BasicMultitouch/_index.jd b/samples/browseable/BasicMultitouch/_index.jd
new file mode 100644
index 0000000..43a1e90
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/_index.jd
@@ -0,0 +1,12 @@
+
+
+
+page.tags="BasicMultitouch"
+sample.group=Input
+@jd:body
+
+<p>This samples demonstrates how to use the {@link android.view.MotionEvent}
+API to keep track of individual touches across multiple touch events.</p>
+<p>To see this in action, run the sample and touch the screen with multiple
+fingers to show that the pointer id (also represented by a colour) does not
+change as new touch events are received.</p>
diff --git a/samples/browseable/BasicMultitouch/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicMultitouch/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMultitouch/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicMultitouch/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicMultitouch/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicMultitouch/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMultitouch/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicMultitouch/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMultitouch/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicMultitouch/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicMultitouch/res/layout/activity_main.xml b/samples/browseable/BasicMultitouch/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BasicMultitouch/res/layout/layout_mainactivity.xml b/samples/browseable/BasicMultitouch/res/layout/layout_mainactivity.xml
new file mode 100644
index 0000000..539a43a
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/layout/layout_mainactivity.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:padding="75dp"
+        android:text="@string/intro_message" />
+
+    <com.example.android.basicmultitouch.TouchDisplayView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/samples/browseable/BasicMultitouch/res/values-sw600dp/dimens.xml b/samples/browseable/BasicMultitouch/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicMultitouch/res/values-sw600dp/styles.xml b/samples/browseable/BasicMultitouch/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicMultitouch/res/values-v11/styles.xml b/samples/browseable/BasicMultitouch/res/values-v11/styles.xml
new file mode 100644
index 0000000..9daaa26
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/values-v11/styles.xml
@@ -0,0 +1,27 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+  <resources>
+
+    <!--
+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/styles.xml on API 11+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!-- API 11 theme customizations can go here. -->
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BasicMultitouch/res/values-v14/styles.xml b/samples/browseable/BasicMultitouch/res/values-v14/styles.xml
new file mode 100644
index 0000000..42ce193
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/values-v14/styles.xml
@@ -0,0 +1,28 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+  <resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.NoActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BasicMultitouch/res/values/base-strings.xml b/samples/browseable/BasicMultitouch/res/values/base-strings.xml
new file mode 100644
index 0000000..a5388a7
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/values/base-strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicMultitouch</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+This samples demonstrates the use of MotionEvent properties to keep track of individual touches
+across multiple touch events.
+\n\nTouch the screen with multiple fingers to show that the pointer id
+(also represented by a colour) does not change as new touch events are received.</string>
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicMultitouch/res/values/dimens.xml b/samples/browseable/BasicMultitouch/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicMultitouch/res/values/strings.xml b/samples/browseable/BasicMultitouch/res/values/strings.xml
new file mode 100644
index 0000000..5765548
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BasicMultitouch/res/values/styles.xml b/samples/browseable/BasicMultitouch/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/MainActivity.java b/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/MainActivity.java
new file mode 100644
index 0000000..fc95a60
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/MainActivity.java
@@ -0,0 +1,43 @@
+/*
+ * 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.basicmultitouch;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * This is an example of keeping track of individual touches across multiple
+ * {@link android.view.MotionEvent}s.
+ * <p>
+ * This is illustrated by a View ({@link TouchDisplayView}) that responds to
+ * touch events and draws coloured circles for each pointer, stores the last
+ * positions of this pointer and draws them. This example shows the relationship
+ * between MotionEvent indices, pointer identifiers and actions.
+ *
+ * @see android.view.MotionEvent
+ */
+public class MainActivity extends Activity {
+    TouchDisplayView mView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.layout_mainactivity);
+    }
+
+}
diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/Pools.java b/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/Pools.java
new file mode 100644
index 0000000..0eda0ee
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/Pools.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.basicmultitouch;
+
+/**
+ * Helper class for crating pools of objects. An example use looks like this:
+ * <pre>
+ * public class MyPooledClass {
+ *
+ *     private static final SynchronizedPool<MyPooledClass> sPool =
+ *             new SynchronizedPool<MyPooledClass>(10);
+ *
+ *     public static MyPooledClass obtain() {
+ *         MyPooledClass instance = sPool.acquire();
+ *         return (instance != null) ? instance : new MyPooledClass();
+ *     }
+ *
+ *     public void recycle() {
+ *          // Clear state if needed.
+ *          sPool.release(this);
+ *     }
+ *
+ *     . . .
+ * }
+ * </pre>
+ *
+ * @hide
+ */
+public final class Pools {
+
+    /**
+     * Interface for managing a pool of objects.
+     *
+     * @param <T> The pooled type.
+     */
+    public static interface Pool<T> {
+
+        /**
+         * @return An instance from the pool if such, null otherwise.
+         */
+        public T acquire();
+
+        /**
+         * Release an instance to the pool.
+         *
+         * @param instance The instance to release.
+         * @return Whether the instance was put in the pool.
+         *
+         * @throws IllegalStateException If the instance is already in the pool.
+         */
+        public boolean release(T instance);
+    }
+
+    private Pools() {
+        /* do nothing - hiding constructor */
+    }
+
+    /**
+     * Simple (non-synchronized) pool of objects.
+     *
+     * @param <T> The pooled type.
+     */
+    public static class SimplePool<T> implements Pool<T> {
+        private final Object[] mPool;
+
+        private int mPoolSize;
+
+        /**
+         * Creates a new instance.
+         *
+         * @param maxPoolSize The max pool size.
+         *
+         * @throws IllegalArgumentException If the max pool size is less than zero.
+         */
+        public SimplePool(int maxPoolSize) {
+            if (maxPoolSize <= 0) {
+                throw new IllegalArgumentException("The max pool size must be > 0");
+            }
+            mPool = new Object[maxPoolSize];
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public T acquire() {
+            if (mPoolSize > 0) {
+                final int lastPooledIndex = mPoolSize - 1;
+                T instance = (T) mPool[lastPooledIndex];
+                mPool[lastPooledIndex] = null;
+                mPoolSize--;
+                return instance;
+            }
+            return null;
+        }
+
+        @Override
+        public boolean release(T instance) {
+            if (isInPool(instance)) {
+                throw new IllegalStateException("Already in the pool!");
+            }
+            if (mPoolSize < mPool.length) {
+                mPool[mPoolSize] = instance;
+                mPoolSize++;
+                return true;
+            }
+            return false;
+        }
+
+        private boolean isInPool(T instance) {
+            for (int i = 0; i < mPoolSize; i++) {
+                if (mPool[i] == instance) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Synchronized) pool of objects.
+     *
+     * @param <T> The pooled type.
+     */
+    public static class SynchronizedPool<T> extends SimplePool<T> {
+        private final Object mLock = new Object();
+
+        /**
+         * Creates a new instance.
+         *
+         * @param maxPoolSize The max pool size.
+         *
+         * @throws IllegalArgumentException If the max pool size is less than zero.
+         */
+        public SynchronizedPool(int maxPoolSize) {
+            super(maxPoolSize);
+        }
+
+        @Override
+        public T acquire() {
+            synchronized (mLock) {
+                return super.acquire();
+            }
+        }
+
+        @Override
+        public boolean release(T element) {
+            synchronized (mLock) {
+                return super.release(element);
+            }
+        }
+    }
+}
diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/TouchDisplayView.java b/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/TouchDisplayView.java
new file mode 100644
index 0000000..78e6abe
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/TouchDisplayView.java
@@ -0,0 +1,401 @@
+/*
+ * 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.basicmultitouch;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.example.android.basicmultitouch.Pools.SimplePool;
+
+/**
+ * View that shows touch events and their history. This view demonstrates the
+ * use of {@link #onTouchEvent(android.view.MotionEvent)} and {@link android.view.MotionEvent}s to keep
+ * track of touch pointers across events.
+ */
+public class TouchDisplayView extends View {
+
+    // Hold data for active touch pointer IDs
+    private SparseArray<TouchHistory> mTouches;
+
+    // Is there an active touch?
+    private boolean mHasTouch = false;
+
+    /**
+     * Holds data related to a touch pointer, including its current position,
+     * pressure and historical positions. Objects are allocated through an
+     * object pool using {@link #obtain()} and {@link #recycle()} to reuse
+     * existing objects.
+     */
+    static final class TouchHistory {
+
+        // number of historical points to store
+        public static final int HISTORY_COUNT = 20;
+
+        public float x;
+        public float y;
+        public float pressure = 0f;
+        public String label = null;
+
+        // current position in history array
+        public int historyIndex = 0;
+        public int historyCount = 0;
+
+        // arrray of pointer position history
+        public PointF[] history = new PointF[HISTORY_COUNT];
+
+        private static final int MAX_POOL_SIZE = 10;
+        private static final SimplePool<TouchHistory> sPool =
+                new SimplePool<TouchHistory>(MAX_POOL_SIZE);
+
+        public static TouchHistory obtain(float x, float y, float pressure) {
+            TouchHistory data = sPool.acquire();
+            if (data == null) {
+                data = new TouchHistory();
+            }
+
+            data.setTouch(x, y, pressure);
+
+            return data;
+        }
+
+        public TouchHistory() {
+
+            // initialise history array
+            for (int i = 0; i < HISTORY_COUNT; i++) {
+                history[i] = new PointF();
+            }
+        }
+
+        public void setTouch(float x, float y, float pressure) {
+            this.x = x;
+            this.y = y;
+            this.pressure = pressure;
+        }
+
+        public void recycle() {
+            this.historyIndex = 0;
+            this.historyCount = 0;
+            sPool.release(this);
+        }
+
+        /**
+         * Add a point to its history. Overwrites oldest point if the maximum
+         * number of historical points is already stored.
+         *
+         * @param point
+         */
+        public void addHistory(float x, float y) {
+            PointF p = history[historyIndex];
+            p.x = x;
+            p.y = y;
+
+            historyIndex = (historyIndex + 1) % history.length;
+
+            if (historyCount < HISTORY_COUNT) {
+                historyCount++;
+            }
+        }
+
+    }
+
+    public TouchDisplayView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        // SparseArray for touch events, indexed by touch id
+        mTouches = new SparseArray<TouchHistory>(10);
+
+        initialisePaint();
+    }
+
+    // BEGIN_INCLUDE(onTouchEvent)
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+
+        final int action = event.getAction();
+
+        /*
+         * Switch on the action. The action is extracted from the event by
+         * applying the MotionEvent.ACTION_MASK. Alternatively a call to
+         * event.getActionMasked() would yield in the action as well.
+         */
+        switch (action & MotionEvent.ACTION_MASK) {
+
+            case MotionEvent.ACTION_DOWN: {
+                // first pressed gesture has started
+
+                /*
+                 * Only one touch event is stored in the MotionEvent. Extract
+                 * the pointer identifier of this touch from the first index
+                 * within the MotionEvent object.
+                 */
+                int id = event.getPointerId(0);
+
+                TouchHistory data = TouchHistory.obtain(event.getX(0), event.getY(0),
+                        event.getPressure(0));
+                data.label = "id: " + 0;
+
+                /*
+                 * Store the data under its pointer identifier. The pointer
+                 * number stays consistent for the duration of a gesture,
+                 * accounting for other pointers going up or down.
+                 */
+                mTouches.put(id, data);
+
+                mHasTouch = true;
+
+                break;
+            }
+
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                /*
+                 * A non-primary pointer has gone down, after an event for the
+                 * primary pointer (ACTION_DOWN) has already been received.
+                 */
+
+                /*
+                 * The MotionEvent object contains multiple pointers. Need to
+                 * extract the index at which the data for this particular event
+                 * is stored.
+                 */
+                int index = event.getActionIndex();
+                int id = event.getPointerId(index);
+
+                TouchHistory data = TouchHistory.obtain(event.getX(index), event.getY(index),
+                        event.getPressure(index));
+                data.label = "id: " + id;
+
+                /*
+                 * Store the data under its pointer identifier. The index of
+                 * this pointer can change over multiple events, but this
+                 * pointer is always identified by the same identifier for this
+                 * active gesture.
+                 */
+                mTouches.put(id, data);
+
+                break;
+            }
+
+            case MotionEvent.ACTION_UP: {
+                /*
+                 * Final pointer has gone up and has ended the last pressed
+                 * gesture.
+                 */
+
+                /*
+                 * Extract the pointer identifier for the only event stored in
+                 * the MotionEvent object and remove it from the list of active
+                 * touches.
+                 */
+                int id = event.getPointerId(0);
+                TouchHistory data = mTouches.get(id);
+                mTouches.remove(id);
+                data.recycle();
+
+                mHasTouch = false;
+
+                break;
+            }
+
+            case MotionEvent.ACTION_POINTER_UP: {
+                /*
+                 * A non-primary pointer has gone up and other pointers are
+                 * still active.
+                 */
+
+                /*
+                 * The MotionEvent object contains multiple pointers. Need to
+                 * extract the index at which the data for this particular event
+                 * is stored.
+                 */
+                int index = event.getActionIndex();
+                int id = event.getPointerId(index);
+
+                TouchHistory data = mTouches.get(id);
+                mTouches.remove(id);
+                data.recycle();
+
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                /*
+                 * A change event happened during a pressed gesture. (Between
+                 * ACTION_DOWN and ACTION_UP or ACTION_POINTER_DOWN and
+                 * ACTION_POINTER_UP)
+                 */
+
+                /*
+                 * Loop through all active pointers contained within this event.
+                 * Data for each pointer is stored in a MotionEvent at an index
+                 * (starting from 0 up to the number of active pointers). This
+                 * loop goes through each of these active pointers, extracts its
+                 * data (position and pressure) and updates its stored data. A
+                 * pointer is identified by its pointer number which stays
+                 * constant across touch events as long as it remains active.
+                 * This identifier is used to keep track of a pointer across
+                 * events.
+                 */
+                for (int index = 0; index < event.getPointerCount(); index++) {
+                    // get pointer id for data stored at this index
+                    int id = event.getPointerId(index);
+
+                    // get the data stored externally about this pointer.
+                    TouchHistory data = mTouches.get(id);
+
+                    // add previous position to history and add new values
+                    data.addHistory(data.x, data.y);
+                    data.setTouch(event.getX(index), event.getY(index),
+                            event.getPressure(index));
+
+                }
+
+                break;
+            }
+        }
+
+        // trigger redraw on UI thread
+        this.postInvalidate();
+
+        return true;
+    }
+
+    // END_INCLUDE(onTouchEvent)
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        // Canvas background color depends on whether there is an active touch
+        if (mHasTouch) {
+            canvas.drawColor(BACKGROUND_ACTIVE);
+        } else {
+            // draw inactive border
+            canvas.drawRect(mBorderWidth, mBorderWidth, getWidth() - mBorderWidth, getHeight()
+                    - mBorderWidth, mBorderPaint);
+        }
+
+        // loop through all active touches and draw them
+        for (int i = 0; i < mTouches.size(); i++) {
+
+            // get the pointer id and associated data for this index
+            int id = mTouches.keyAt(i);
+            TouchHistory data = mTouches.valueAt(i);
+
+            // draw the data and its history to the canvas
+            drawCircle(canvas, id, data);
+        }
+    }
+
+    /*
+     * Below are only helper methods and variables required for drawing.
+     */
+
+    // radius of active touch circle in dp
+    private static final float CIRCLE_RADIUS_DP = 75f;
+    // radius of historical circle in dp
+    private static final float CIRCLE_HISTORICAL_RADIUS_DP = 7f;
+
+    // calculated radiuses in px
+    private float mCircleRadius;
+    private float mCircleHistoricalRadius;
+
+    private Paint mCirclePaint = new Paint();
+    private Paint mTextPaint = new Paint();
+
+    private static final int BACKGROUND_ACTIVE = Color.WHITE;
+
+    // inactive border
+    private static final float INACTIVE_BORDER_DP = 15f;
+    private static final int INACTIVE_BORDER_COLOR = 0xFFffd060;
+    private Paint mBorderPaint = new Paint();
+    private float mBorderWidth;
+
+    public final int[] COLORS = {
+            0xFF33B5E5, 0xFFAA66CC, 0xFF99CC00, 0xFFFFBB33, 0xFFFF4444,
+            0xFF0099CC, 0xFF9933CC, 0xFF669900, 0xFFFF8800, 0xFFCC0000
+    };
+
+    /**
+     * Sets up the required {@link android.graphics.Paint} objects for the screen density of this
+     * device.
+     */
+    private void initialisePaint() {
+
+        // Calculate radiuses in px from dp based on screen density
+        float density = getResources().getDisplayMetrics().density;
+        mCircleRadius = CIRCLE_RADIUS_DP * density;
+        mCircleHistoricalRadius = CIRCLE_HISTORICAL_RADIUS_DP * density;
+
+        // Setup text paint for circle label
+        mTextPaint.setTextSize(27f);
+        mTextPaint.setColor(Color.BLACK);
+
+        // Setup paint for inactive border
+        mBorderWidth = INACTIVE_BORDER_DP * density;
+        mBorderPaint.setStrokeWidth(mBorderWidth);
+        mBorderPaint.setColor(INACTIVE_BORDER_COLOR);
+        mBorderPaint.setStyle(Paint.Style.STROKE);
+
+    }
+
+    /**
+     * Draws the data encapsulated by a {@link TouchDisplayView.TouchHistory} object to a canvas.
+     * A large circle indicates the current position held by the
+     * {@link TouchDisplayView.TouchHistory} object, while a smaller circle is drawn for each
+     * entry in its history. The size of the large circle is scaled depending on
+     * its pressure, clamped to a maximum of <code>1.0</code>.
+     *
+     * @param canvas
+     * @param id
+     * @param data
+     */
+    protected void drawCircle(Canvas canvas, int id, TouchHistory data) {
+        // select the color based on the id
+        int color = COLORS[id % COLORS.length];
+        mCirclePaint.setColor(color);
+
+        /*
+         * Draw the circle, size scaled to its pressure. Pressure is clamped to
+         * 1.0 max to ensure proper drawing. (Reported pressure values can
+         * exceed 1.0, depending on the calibration of the touch screen).
+         */
+        float pressure = Math.min(data.pressure, 1f);
+        float radius = pressure * mCircleRadius;
+
+        canvas.drawCircle(data.x, (data.y) - (radius / 2f), radius,
+                mCirclePaint);
+
+        // draw all historical points with a lower alpha value
+        mCirclePaint.setAlpha(125);
+        for (int j = 0; j < data.history.length && j < data.historyCount; j++) {
+            PointF p = data.history[j];
+            canvas.drawCircle(p.x, p.y, mCircleHistoricalRadius, mCirclePaint);
+        }
+
+        // draw its label next to the main circle
+        canvas.drawText(data.label, data.x + radius, data.y
+                - radius, mTextPaint);
+    }
+
+}
diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/Log.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogView.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/BasicNetworking/AndroidManifest.xml b/samples/browseable/BasicNetworking/AndroidManifest.xml
new file mode 100644
index 0000000..48bfeac
--- /dev/null
+++ b/samples/browseable/BasicNetworking/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicnetworking"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+    <application
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/Theme.Sample"
+        android:allowBackup="true">
+
+        <activity
+            android:name="com.example.android.basicnetworking.MainActivity"
+            android:label="@string/app_name"
+            android:uiOptions="splitActionBarWhenNarrow">
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/samples/browseable/BasicNetworking/_index.jd b/samples/browseable/BasicNetworking/_index.jd
new file mode 100644
index 0000000..223ba76
--- /dev/null
+++ b/samples/browseable/BasicNetworking/_index.jd
@@ -0,0 +1,10 @@
+
+
+
+page.tags="BasicNetworking"
+sample.group=Connectivity
+@jd:body
+
+<p>This sample demonstrates how to use the
+{@link android.net.ConnectivityManager} to determine if the device has an
+active network connection, and if so, retrieve the connection type.</p>
diff --git a/samples/browseable/BasicNetworking/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicNetworking/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..22ce606
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicNetworking/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicNetworking/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicNetworking/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicNetworking/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..f21e17b
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicNetworking/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicNetworking/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..64b8059
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicNetworking/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicNetworking/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..6b4434a
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicNetworking/res/layout/activity_main.xml b/samples/browseable/BasicNetworking/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BasicNetworking/res/layout/sample_main.xml b/samples/browseable/BasicNetworking/res/layout/sample_main.xml
new file mode 100755
index 0000000..ccbe6ae
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/layout/sample_main.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    <fragment
+        android:name="com.example.android.basicnetworking.SimpleTextFragment"
+        android:id="@+id/intro_fragment"
+        android:layout_weight="1"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+    <View
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:background="@android:color/darker_gray"/>
+    <fragment
+        android:name="com.example.android.common.logger.LogFragment"
+        android:id="@+id/log_fragment"
+        android:layout_weight="1"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/samples/browseable/BasicNetworking/res/menu/main.xml b/samples/browseable/BasicNetworking/res/menu/main.xml
new file mode 100644
index 0000000..f05f16a
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/menu/main.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/test_action"
+        android:showAsAction="ifRoom|withText"
+        android:title="@string/test_text" />
+    <item android:id="@+id/clear_action"
+        android:showAsAction="ifRoom|withText"
+        android:title="@string/clear_text" />
+</menu>
diff --git a/samples/browseable/BasicNetworking/res/values-sw600dp/dimens.xml b/samples/browseable/BasicNetworking/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicNetworking/res/values-sw600dp/styles.xml b/samples/browseable/BasicNetworking/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicNetworking/res/values/base-strings.xml b/samples/browseable/BasicNetworking/res/values/base-strings.xml
new file mode 100644
index 0000000..668bcdf
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/values/base-strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicNetworking</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+                This sample demonstrates how to use the ConnectivityManager to determine if you have
+                a network connection, and if so, what type of connection it is.
+                \n\nA "NetworkInfo" object is retrieved from the ConnectivityManager, which contains information
+                on the active connection, and then the connection type is printed to an on-screen console.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicNetworking/res/values/dimens.xml b/samples/browseable/BasicNetworking/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicNetworking/res/values/strings.xml b/samples/browseable/BasicNetworking/res/values/strings.xml
new file mode 100755
index 0000000..d39460a
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/values/strings.xml
@@ -0,0 +1,23 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="test_text">Test</string>
+    <string name="clear_text">Clear</string>
+    <string name="wifi_connection">The active connection is wifi.</string>
+    <string name="mobile_connection">The active connection is mobile.</string>
+    <string name="no_wifi_or_mobile">No wireless or mobile connection.</string>
+</resources>
diff --git a/samples/browseable/BasicNetworking/res/values/styles.xml b/samples/browseable/BasicNetworking/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/BasicNetworking/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicNetworking/src/com.example.android.basicnetworking/MainActivity.java b/samples/browseable/BasicNetworking/src/com.example.android.basicnetworking/MainActivity.java
new file mode 100755
index 0000000..39ed4b1
--- /dev/null
+++ b/samples/browseable/BasicNetworking/src/com.example.android.basicnetworking/MainActivity.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicnetworking;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.util.TypedValue;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * Sample application demonstrating how to test whether a device is connected,
+ * and if so, whether the connection happens to be wifi or mobile (it could be
+ * something else).
+ *
+ * This sample uses the logging framework to display log output in the log
+ * fragment (LogFragment).
+ */
+public class MainActivity extends FragmentActivity {
+
+    public static final String TAG = "Basic Network Demo";
+    // Whether there is a Wi-Fi connection.
+    private static boolean wifiConnected = false;
+    // Whether there is a mobile connection.
+    private static boolean mobileConnected = false;
+
+    // Reference to the fragment showing events, so we can clear it with a button
+    // as necessary.
+    private LogFragment mLogFragment;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+
+        // Initialize text fragment that displays intro text.
+        SimpleTextFragment introFragment = (SimpleTextFragment)
+                    getSupportFragmentManager().findFragmentById(R.id.intro_fragment);
+        introFragment.setText(R.string.intro_message);
+        introFragment.getTextView().setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16.0f);
+
+        // Initialize the logging framework.
+        initializeLogging();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            // When the user clicks TEST, display the connection status.
+            case R.id.test_action:
+                checkNetworkConnection();
+                return true;
+            // Clear the log view fragment.
+            case R.id.clear_action:
+                mLogFragment.getLogView().setText("");
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Check whether the device is connected, and if so, whether the connection
+     * is wifi or mobile (it could be something else).
+     */
+    private void checkNetworkConnection() {
+      // BEGIN_INCLUDE(connect)
+      ConnectivityManager connMgr =
+          (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+      NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
+      if (activeInfo != null && activeInfo.isConnected()) {
+          wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
+          mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
+          if(wifiConnected) {
+              Log.i(TAG, getString(R.string.wifi_connection));
+          } else if (mobileConnected){
+              Log.i(TAG, getString(R.string.mobile_connection));
+          }
+      } else {
+          Log.i(TAG, getString(R.string.no_wifi_or_mobile));
+      }
+      // END_INCLUDE(connect)
+    }
+
+    /** Create a chain of targets that will receive log data */
+    public void initializeLogging() {
+
+        // Using Log, front-end to the logging chain, emulates
+        // android.util.log method signatures.
+
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        // A filter that strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        mLogFragment =
+                (LogFragment) getSupportFragmentManager().findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(mLogFragment.getLogView());
+    }
+}
diff --git a/samples/browseable/BasicNetworking/src/com.example.android.basicnetworking/SimpleTextFragment.java b/samples/browseable/BasicNetworking/src/com.example.android.basicnetworking/SimpleTextFragment.java
new file mode 100644
index 0000000..c6d409c
--- /dev/null
+++ b/samples/browseable/BasicNetworking/src/com.example.android.basicnetworking/SimpleTextFragment.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicnetworking;
+
+import android.os.Bundle;
+
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Simple fragment containing only a TextView. Used by TextPagerAdapter to create
+ * tutorial-style pages for apps.
+ */
+public class SimpleTextFragment extends Fragment {
+
+    // Contains the text that will be displayed by this Fragment
+    String mText;
+
+    // Contains a resource ID for the text that will be displayed by this fragment.
+    int mTextId = -1;
+
+    // Keys which will be used to store/retrieve text passed in via setArguments.
+    public static final String TEXT_KEY = "text";
+    public static final String TEXT_ID_KEY = "text_id";
+
+    // For situations where the app wants to modify text at Runtime, exposing the TextView.
+    private TextView mTextView;
+
+    public SimpleTextFragment() {
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        // Before initializing the textView, check if any arguments were provided via setArguments.
+        processArguments();
+
+        // Create a new TextView and set its text to whatever was provided.
+        mTextView = new TextView(getActivity());
+        mTextView.setGravity(Gravity.CENTER);
+
+        if (mText != null) {
+            mTextView.setText(mText);
+            Log.i("SimpleTextFragment", mText);
+        }
+        return mTextView;
+    }
+
+    public TextView getTextView() {
+        return mTextView;
+    }
+
+    /**
+     * Changes the text for this TextView, according to the resource ID provided.
+     * @param stringId A resource ID representing the text content for this Fragment's TextView.
+     */
+    public void setText(int stringId) {
+        getTextView().setText(getActivity().getString(stringId));
+    }
+
+    /**
+     * Processes the arguments passed into this Fragment via setArguments method.
+     * Currently the method only looks for text or a textID, nothing else.
+     */
+    public void processArguments() {
+        // For most objects we'd handle the multiple possibilities for initialization variables
+        // as multiple constructors.  For Fragments, however, it's customary to use
+        // setArguments / getArguments.
+        if (getArguments() != null) {
+            Bundle args = getArguments();
+            if (args.containsKey(TEXT_KEY)) {
+                mText = args.getString(TEXT_KEY);
+                Log.d("Constructor", "Added Text.");
+            } else if (args.containsKey(TEXT_ID_KEY)) {
+                mTextId = args.getInt(TEXT_ID_KEY);
+                mText = getString(mTextId);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/Log.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogView.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/BasicNotifications/AndroidManifest.xml b/samples/browseable/BasicNotifications/AndroidManifest.xml
new file mode 100644
index 0000000..1e37d0b
--- /dev/null
+++ b/samples/browseable/BasicNotifications/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicnotifications"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="17"/>
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme">
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/BasicNotifications/_index.jd b/samples/browseable/BasicNotifications/_index.jd
new file mode 100644
index 0000000..02a9b56
--- /dev/null
+++ b/samples/browseable/BasicNotifications/_index.jd
@@ -0,0 +1,10 @@
+
+
+
+page.tags="BasicNotifications"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to display events in the system's notification
+bar. The {@link android.support.v4.app.NotificationCompat} API is used for
+compatibility with devices running Android 2.2 or higher.</p>
diff --git a/samples/browseable/BasicNotifications/res/drawable-hdpi-v11/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-hdpi-v11/ic_stat_notification.png
new file mode 100644
index 0000000..604d3a3
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-hdpi-v11/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-hdpi-v9/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-hdpi-v9/ic_stat_notification.png
new file mode 100644
index 0000000..5c86ffd
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-hdpi-v9/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..743382b
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_stat_notification.png
new file mode 100644
index 0000000..f39c3b3
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicNotifications/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-ldpi-v11/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-ldpi-v11/ic_stat_notification.png
new file mode 100644
index 0000000..b919a32
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-ldpi-v11/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-ldpi-v9/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-ldpi-v9/ic_stat_notification.png
new file mode 100644
index 0000000..1ce3e7e
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-ldpi-v9/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-mdpi-v11/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-mdpi-v11/ic_stat_notification.png
new file mode 100644
index 0000000..3f4d4a6
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-mdpi-v11/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-mdpi-v9/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-mdpi-v9/ic_stat_notification.png
new file mode 100644
index 0000000..1dbd17c
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-mdpi-v9/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..46a51a4
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_stat_notification.png
new file mode 100644
index 0000000..eafbbd1
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-xhdpi-v11/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-xhdpi-v11/ic_stat_notification.png
new file mode 100644
index 0000000..d2317d7
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-xhdpi-v11/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-xhdpi-v9/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-xhdpi-v9/ic_stat_notification.png
new file mode 100644
index 0000000..7011de8
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-xhdpi-v9/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..f97cef3
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_stat_notification.png
new file mode 100644
index 0000000..1f0d652
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_stat_notification.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicNotifications/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..17fa130
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicNotifications/res/layout/activity_main.xml b/samples/browseable/BasicNotifications/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BasicNotifications/res/layout/sample_layout.xml b/samples/browseable/BasicNotifications/res/layout/sample_layout.xml
new file mode 100644
index 0000000..4b0adf6
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/layout/sample_layout.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/coreLayout"
+    android:orientation="vertical"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/description"
+        android:id="@+id/description"
+        android:scrollbars="vertical"
+        android:layout_gravity="fill_vertical"
+        android:layout_weight="1"/>
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Do it!"
+        android:id="@+id/button"
+        android:layout_gravity="center"
+        android:onClick="sendNotification"/>
+
+</LinearLayout>
diff --git a/samples/browseable/BasicNotifications/res/values-sw600dp/dimens.xml b/samples/browseable/BasicNotifications/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicNotifications/res/values-sw600dp/styles.xml b/samples/browseable/BasicNotifications/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicNotifications/res/values/base-strings.xml b/samples/browseable/BasicNotifications/res/values/base-strings.xml
new file mode 100644
index 0000000..15dafec
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/values/base-strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicNotifications</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates how to display events in the system\'s notification bar. The
+            NotificationCompat API is used for compatibility with older devices, running Android
+            2.2 (Froyo) or newer.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicNotifications/res/values/dimens.xml b/samples/browseable/BasicNotifications/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicNotifications/res/values/strings.xml b/samples/browseable/BasicNotifications/res/values/strings.xml
new file mode 100644
index 0000000..075f681
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/values/strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<resources>
+
+    <string name="description">
+        Tap the button below to send a notification.\n\nThe notification\'s icon will immediately
+        appear in the notification bar. Drag the notification bar open to see the full
+        notification. Depending on which version of Android you\'re running, the full
+        notification will display an icon and two or three lines of text.
+        \n\nTap the notification to execute the notification\'s \"action,\" which is an intent
+        that we associate with the notification when it\'s created. This sample notification\'s
+        action is to send a browse intent with the url of the Notification docs on
+        developer.android.com.
+        \n\nThis sample uses the NotificationCompat API for maximum compatibility with versions
+        of Android from Froyo (Android 2.2) to the present. Try it on devices or AVDs that are
+        running different versions of Android. You\'ll see that while the presentation varies
+        slightly, the basic functionality is the same. NotificationCompat automatically takes
+        advantage of the expanded notification format in newer versions of Android, and
+        falls back gracefully to a reduced set of functionality on earlier versions.
+    </string>
+
+</resources>
diff --git a/samples/browseable/BasicNotifications/res/values/styles.xml b/samples/browseable/BasicNotifications/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/BasicNotifications/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicNotifications/src/com.example.android.basicnotifications/MainActivity.java b/samples/browseable/BasicNotifications/src/com.example.android.basicnotifications/MainActivity.java
new file mode 100644
index 0000000..3e78c34
--- /dev/null
+++ b/samples/browseable/BasicNotifications/src/com.example.android.basicnotifications/MainActivity.java
@@ -0,0 +1,101 @@
+package com.example.android.basicnotifications;
+
+import android.app.Activity;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.NotificationCompat;
+import android.view.View;
+
+/**
+ * The entry point to the BasicNotification sample.
+ */
+public class MainActivity extends Activity {
+    /**
+     * A numeric value that identifies the notification that we'll be sending.
+     * This value needs to be unique within this app, but it doesn't need to be
+     * unique system-wide.
+     */
+    public static final int NOTIFICATION_ID = 1;
+
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_layout);
+
+    }
+
+    /**
+     * Send a sample notification using the NotificationCompat API.
+     */
+    public void sendNotification(View view) {
+
+        // BEGIN_INCLUDE(build_action)
+        /** Create an intent that will be fired when the user clicks the notification.
+         * The intent needs to be packaged into a {@link android.app.PendingIntent} so that the
+         * notification service can fire it on our behalf.
+         */
+        Intent intent = new Intent(Intent.ACTION_VIEW,
+                Uri.parse("http://developer.android.com/reference/android/app/Notification.html"));
+        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
+        // END_INCLUDE(build_action)
+
+        // BEGIN_INCLUDE (build_notification)
+        /**
+         * Use NotificationCompat.Builder to set up our notification.
+         */
+        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
+
+        /** Set the icon that will appear in the notification bar. This icon also appears
+         * in the lower right hand corner of the notification itself.
+         *
+         * Important note: although you can use any drawable as the small icon, Android
+         * design guidelines state that the icon should be simple and monochrome. Full-color
+         * bitmaps or busy images don't render well on smaller screens and can end up
+         * confusing the user.
+         */
+        builder.setSmallIcon(R.drawable.ic_stat_notification);
+
+        // Set the intent that will fire when the user taps the notification.
+        builder.setContentIntent(pendingIntent);
+
+        // Set the notification to auto-cancel. This means that the notification will disappear
+        // after the user taps it, rather than remaining until it's explicitly dismissed.
+        builder.setAutoCancel(true);
+
+        /**
+         *Build the notification's appearance.
+         * Set the large icon, which appears on the left of the notification. In this
+         * sample we'll set the large icon to be the same as our app icon. The app icon is a
+         * reasonable default if you don't have anything more compelling to use as an icon.
+         */
+        builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
+
+        /**
+         * Set the text of the notification. This sample sets the three most commononly used
+         * text areas:
+         * 1. The content title, which appears in large type at the top of the notification
+         * 2. The content text, which appears in smaller text below the title
+         * 3. The subtext, which appears under the text on newer devices. Devices running
+         *    versions of Android prior to 4.2 will ignore this field, so don't use it for
+         *    anything vital!
+         */
+        builder.setContentTitle("BasicNotifications Sample");
+        builder.setContentText("Time to learn about notifications!");
+        builder.setSubText("Tap to view documentation about notifications.");
+
+        // END_INCLUDE (build_notification)
+
+        // BEGIN_INCLUDE(send_notification)
+        /**
+         * Send the notification. This will immediately display the notification icon in the
+         * notification bar.
+         */
+        NotificationManager notificationManager = (NotificationManager) getSystemService(
+                NOTIFICATION_SERVICE);
+        notificationManager.notify(NOTIFICATION_ID, builder.build());
+        // END_INCLUDE(send_notification)
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/AndroidManifest.xml b/samples/browseable/BasicSyncAdapter/AndroidManifest.xml
new file mode 100644
index 0000000..dd59b06
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/AndroidManifest.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicsyncadapter"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!-- SyncAdapters are available in API 5 and above. We use API 7 as a baseline for samples. -->
+    <uses-sdk
+        android:minSdkVersion="7"
+        android:targetSdkVersion="17" />
+
+    <!-- Required for fetching feed data. -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <!-- Required to register a SyncStatusObserver to display a "syncing..." progress indicator. -->
+    <uses-permission android:name="android.permission.READ_SYNC_STATS"/>
+    <!-- Required to enable our SyncAdapter after it's created. -->
+    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
+    <!-- Required because we're manually creating a new account. -->
+    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
+
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+
+        <!-- Main activity, responsible for showing a list of feed entries. -->
+        <activity
+            android:name=".EntryListActivity"
+            android:label="@string/app_name" >
+            <!-- This intent filter places this activity in the system's app launcher. -->
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <!-- ContentProvider to store feed data.
+
+        The "authorities" here are defined as part of a ContentProvider interface. It's used here
+        as an attachment point for the SyncAdapter. See res/xml/syncadapter.xml and
+        SyncService.java.
+
+        Since this ContentProvider is not exported, it will not be accessible outside of this app's
+        package. -->
+        <provider
+            android:name=".provider.FeedProvider"
+            android:authorities="com.example.android.basicsyncadapter"
+            android:exported="false" />
+
+        <!-- This service implements our SyncAdapter. It needs to be exported, so that the system
+        sync framework can access it. -->
+        <service android:name=".SyncService"
+            android:exported="true">
+            <!-- This intent filter is required. It allows the system to launch our sync service
+            as needed. -->
+            <intent-filter>
+                <action android:name="android.content.SyncAdapter" />
+            </intent-filter>
+            <!-- This points to a required XML file which describes our SyncAdapter. -->
+            <meta-data android:name="android.content.SyncAdapter"
+                android:resource="@xml/syncadapter" />
+        </service>
+
+        <!-- This implements the account we'll use as an attachment point for our SyncAdapter. Since
+        our SyncAdapter doesn't need to authenticate the current user (it just fetches a public RSS
+        feed), this account's implementation is largely empty.
+
+        It's also possible to attach a SyncAdapter to an existing account provided by another
+        package. In that case, this element could be omitted here. -->
+        <service android:name="com.example.android.common.accounts.GenericAccountService">
+            <!-- Required filter used by the system to launch our account service. -->
+            <intent-filter>
+                <action android:name="android.accounts.AccountAuthenticator" />
+            </intent-filter>
+            <!-- This points to an XMLf ile which describes our account service. -->
+            <meta-data android:name="android.accounts.AccountAuthenticator"
+                android:resource="@xml/authenticator" />
+        </service>
+
+    </application>
+
+</manifest>
diff --git a/samples/browseable/BasicSyncAdapter/_index.jd b/samples/browseable/BasicSyncAdapter/_index.jd
new file mode 100644
index 0000000..7217e9a
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/_index.jd
@@ -0,0 +1,14 @@
+
+
+
+page.tags="BasicSyncAdapter"
+sample.group=Connectivity
+@jd:body
+
+<p>This sample demonstrates how to implement a sync adapter to fetch background
+data for an app that doesn't require a user-visible account type or two-way
+synchronization.</p>
+<p>The sample periodically downloads the feed from the <a href="http://android-developers.blogspot.com/">Android Developers Blog</a> and caches the data in a content provider. At runtime, the cached feed data is
+displayed inside a {@link android.widget.ListView}.</p>
+<p>To learn more about creating and using sync adapters, see
+<a href="{@docRoot}training/sync-adapters/index.html">Transferring Data Using Sync Adapters</a>.</p>
diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a0f7005
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicSyncAdapter/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a085462
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_action_refresh.png b/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_action_refresh.png
new file mode 100644
index 0000000..4f5d255
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..4f78eb8
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicSyncAdapter/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b198ee3
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicSyncAdapter/res/layout/actionbar_indeterminate_progress.xml b/samples/browseable/BasicSyncAdapter/res/layout/actionbar_indeterminate_progress.xml
new file mode 100644
index 0000000..b254013
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/layout/actionbar_indeterminate_progress.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2012 Google Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_height="wrap_content"
+             android:layout_width="@dimen/action_button_min_width"
+             android:minWidth="@dimen/action_button_min_width">
+
+    <ProgressBar android:layout_width="@dimen/indeterminate_progress_size"
+                 android:layout_height="@dimen/indeterminate_progress_size"
+                 android:layout_gravity="center"
+                 style="?indeterminateProgressStyle" />
+</FrameLayout>
diff --git a/samples/browseable/BasicSyncAdapter/res/layout/activity_entry_list.xml b/samples/browseable/BasicSyncAdapter/res/layout/activity_entry_list.xml
new file mode 100644
index 0000000..3c8c901
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/layout/activity_entry_list.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<fragment xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          android:id="@+id/entry_list"
+          android:name="com.example.android.basicsyncadapter.EntryListFragment"
+          android:layout_width="match_parent"
+          android:layout_height="match_parent"
+          android:layout_marginLeft="16dp"
+          android:layout_marginRight="16dp"
+          tools:context=".EntryListActivity"
+          tools:layout="@android:layout/list_content" />
diff --git a/samples/browseable/BasicSyncAdapter/res/layout/activity_main.xml b/samples/browseable/BasicSyncAdapter/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BasicSyncAdapter/res/menu/main.xml b/samples/browseable/BasicSyncAdapter/res/menu/main.xml
new file mode 100644
index 0000000..63ad3d1
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/menu/main.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_refresh"
+          android:icon="@drawable/ic_action_refresh"
+          android:title="@string/description_refresh"
+          android:orderInCategory="1"
+          android:showAsAction="always" />
+</menu>
\ No newline at end of file
diff --git a/samples/browseable/BasicSyncAdapter/res/values-sw600dp/dimens.xml b/samples/browseable/BasicSyncAdapter/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicSyncAdapter/res/values-sw600dp/styles.xml b/samples/browseable/BasicSyncAdapter/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicSyncAdapter/res/values/attrs.xml b/samples/browseable/BasicSyncAdapter/res/values/attrs.xml
new file mode 100644
index 0000000..6c15504
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/values/attrs.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+    <!-- Specifies a style resource to use for an indeterminate progress spinner. -->
+    <attr name="indeterminateProgressStyle" format="reference"/>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BasicSyncAdapter/res/values/base-strings.xml b/samples/browseable/BasicSyncAdapter/res/values/base-strings.xml
new file mode 100644
index 0000000..2670484
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/values/base-strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BasicSyncAdapter</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates using SyncAdapter to fetch background data for an app that
+            doesn\'t require a user-visible account type or 2-way synchronization.
+
+            \n\nThis sample periodically downloads the feed from the Android Developer Blog and
+            caches the data in a content provider. At runtime, the cached feed data is displayed
+            inside a ListView.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BasicSyncAdapter/res/values/dimen.xml b/samples/browseable/BasicSyncAdapter/res/values/dimen.xml
new file mode 100644
index 0000000..d838c69
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/values/dimen.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+    <dimen name="action_button_min_width">56dp</dimen>
+    <dimen name="indeterminate_progress_size">32dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BasicSyncAdapter/res/values/dimens.xml b/samples/browseable/BasicSyncAdapter/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicSyncAdapter/res/values/strings.xml b/samples/browseable/BasicSyncAdapter/res/values/strings.xml
new file mode 100644
index 0000000..f4cade9
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+    <string name="account_name">FeedSync Service</string>
+    <string name="title_entry_detail">Entry Detail</string>
+    <string name="loading">Waiting for sync...</string>
+    <string name="description_refresh">Refresh</string>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BasicSyncAdapter/res/values/styles.xml b/samples/browseable/BasicSyncAdapter/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicSyncAdapter/res/xml/authenticator.xml b/samples/browseable/BasicSyncAdapter/res/xml/authenticator.xml
new file mode 100644
index 0000000..8b96907
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/xml/authenticator.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+                       android:accountType="com.example.android.basicsyncadapter.account"
+                       android:icon="@drawable/ic_launcher"
+                       android:smallIcon="@drawable/ic_launcher"
+                       android:label="@string/app_name"
+        />
diff --git a/samples/browseable/BasicSyncAdapter/res/xml/syncadapter.xml b/samples/browseable/BasicSyncAdapter/res/xml/syncadapter.xml
new file mode 100644
index 0000000..6e12882
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/res/xml/syncadapter.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+              android:contentAuthority="com.example.android.basicsyncadapter"
+              android:accountType="com.example.android.basicsyncadapter.account"
+              android:userVisible="false"
+              android:supportsUploading="false"
+              android:allowParallelSyncs="false"
+              android:isAlwaysSyncable="true"
+        />
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListActivity.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListActivity.java
new file mode 100644
index 0000000..9d8cb77
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListActivity.java
@@ -0,0 +1,16 @@
+package com.example.android.basicsyncadapter;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+/**
+ * Activity for holding EntryListFragment.
+ */
+public class EntryListActivity extends FragmentActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_entry_list);
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListFragment.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListFragment.java
new file mode 100644
index 0000000..83e240a
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListFragment.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicsyncadapter;
+
+import android.accounts.Account;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.SyncStatusObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.support.v4.widget.SimpleCursorAdapter;
+import android.text.format.Time;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.example.android.common.accounts.GenericAccountService;
+import com.example.android.basicsyncadapter.provider.FeedContract;
+
+/**
+ * List fragment containing a list of Atom entry objects (articles) stored in the local database.
+ *
+ * <p>Database access is mediated by a content provider, specified in
+ * {@link com.example.android.basicsyncadapter.provider.FeedProvider}. This content
+ * provider is
+ * automatically populated by  {@link SyncService}.
+ *
+ * <p>Selecting an item from the displayed list displays the article in the default browser.
+ *
+ * <p>If the content provider doesn't return any data, then the first sync hasn't run yet. This sync
+ * adapter assumes data exists in the provider once a sync has run. If your app doesn't work like
+ * this, you should add a flag that notes if a sync has run, so you can differentiate between "no
+ * available data" and "no initial sync", and display this in the UI.
+ *
+ * <p>The ActionBar displays a "Refresh" button. When the user clicks "Refresh", the sync adapter
+ * runs immediately. An indeterminate ProgressBar element is displayed, showing that the sync is
+ * occurring.
+ */
+public class EntryListFragment extends ListFragment
+        implements LoaderManager.LoaderCallbacks<Cursor> {
+
+    private static final String TAG = "EntryListFragment";
+
+    /**
+     * Cursor adapter for controlling ListView results.
+     */
+    private SimpleCursorAdapter mAdapter;
+
+    /**
+     * Handle to a SyncObserver. The ProgressBar element is visible until the SyncObserver reports
+     * that the sync is complete.
+     *
+     * <p>This allows us to delete our SyncObserver once the application is no longer in the
+     * foreground.
+     */
+    private Object mSyncObserverHandle;
+
+    /**
+     * Options menu used to populate ActionBar.
+     */
+    private Menu mOptionsMenu;
+
+    /**
+     * Projection for querying the content provider.
+     */
+    private static final String[] PROJECTION = new String[]{
+            FeedContract.Entry._ID,
+            FeedContract.Entry.COLUMN_NAME_TITLE,
+            FeedContract.Entry.COLUMN_NAME_LINK,
+            FeedContract.Entry.COLUMN_NAME_PUBLISHED
+    };
+
+    // Column indexes. The index of a column in the Cursor is the same as its relative position in
+    // the projection.
+    /** Column index for _ID */
+    private static final int COLUMN_ID = 0;
+    /** Column index for title */
+    private static final int COLUMN_TITLE = 1;
+    /** Column index for link */
+    private static final int COLUMN_URL_STRING = 2;
+    /** Column index for published */
+    private static final int COLUMN_PUBLISHED = 3;
+
+    /**
+     * List of Cursor columns to read from when preparing an adapter to populate the ListView.
+     */
+    private static final String[] FROM_COLUMNS = new String[]{
+            FeedContract.Entry.COLUMN_NAME_TITLE,
+            FeedContract.Entry.COLUMN_NAME_PUBLISHED
+    };
+
+    /**
+     * List of Views which will be populated by Cursor data.
+     */
+    private static final int[] TO_FIELDS = new int[]{
+            android.R.id.text1,
+            android.R.id.text2};
+
+    /**
+     * Mandatory empty constructor for the fragment manager to instantiate the
+     * fragment (e.g. upon screen orientation changes).
+     */
+    public EntryListFragment() {}
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    /**
+     * Create SyncAccount at launch, if needed.
+     *
+     * <p>This will create a new account with the system for our application, register our
+     * {@link SyncService} with it, and establish a sync schedule.
+     */
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+
+        // Create account, if needed
+        SyncUtils.CreateSyncAccount(activity);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        mAdapter = new SimpleCursorAdapter(
+                getActivity(),       // Current context
+                android.R.layout.simple_list_item_activated_2,  // Layout for individual rows
+                null,                // Cursor
+                FROM_COLUMNS,        // Cursor columns to use
+                TO_FIELDS,           // Layout fields to use
+                0                    // No flags
+        );
+        mAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
+            @Override
+            public boolean setViewValue(View view, Cursor cursor, int i) {
+                if (i == COLUMN_PUBLISHED) {
+                    // Convert timestamp to human-readable date
+                    Time t = new Time();
+                    t.set(cursor.getLong(i));
+                    ((TextView) view).setText(t.format("%Y-%m-%d %H:%M"));
+                    return true;
+                } else {
+                    // Let SimpleCursorAdapter handle other fields automatically
+                    return false;
+                }
+            }
+        });
+        setListAdapter(mAdapter);
+        setEmptyText(getText(R.string.loading));
+        getLoaderManager().initLoader(0, null, this);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mSyncStatusObserver.onStatusChanged(0);
+
+        // Watch for sync state changes
+        final int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING |
+                ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
+        mSyncObserverHandle = ContentResolver.addStatusChangeListener(mask, mSyncStatusObserver);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        if (mSyncObserverHandle != null) {
+            ContentResolver.removeStatusChangeListener(mSyncObserverHandle);
+            mSyncObserverHandle = null;
+        }
+    }
+
+    /**
+     * Query the content provider for data.
+     *
+     * <p>Loaders do queries in a background thread. They also provide a ContentObserver that is
+     * triggered when data in the content provider changes. When the sync adapter updates the
+     * content provider, the ContentObserver responds by resetting the loader and then reloading
+     * it.
+     */
+    @Override
+    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
+        // We only have one loader, so we can ignore the value of i.
+        // (It'll be '0', as set in onCreate().)
+        return new CursorLoader(getActivity(),  // Context
+                FeedContract.Entry.CONTENT_URI, // URI
+                PROJECTION,                // Projection
+                null,                           // Selection
+                null,                           // Selection args
+                FeedContract.Entry.COLUMN_NAME_PUBLISHED + " desc"); // Sort
+    }
+
+    /**
+     * Move the Cursor returned by the query into the ListView adapter. This refreshes the existing
+     * UI with the data in the Cursor.
+     */
+    @Override
+    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
+        mAdapter.changeCursor(cursor);
+    }
+
+    /**
+     * Called when the ContentObserver defined for the content provider detects that data has
+     * changed. The ContentObserver resets the loader, and then re-runs the loader. In the adapter,
+     * set the Cursor value to null. This removes the reference to the Cursor, allowing it to be
+     * garbage-collected.
+     */
+    @Override
+    public void onLoaderReset(Loader<Cursor> cursorLoader) {
+        mAdapter.changeCursor(null);
+    }
+
+    /**
+     * Create the ActionBar.
+     */
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+        mOptionsMenu = menu;
+        inflater.inflate(R.menu.main, menu);
+    }
+
+    /**
+     * Respond to user gestures on the ActionBar.
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            // If the user clicks the "Refresh" button.
+            case R.id.menu_refresh:
+                SyncUtils.TriggerRefresh();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /**
+     * Load an article in the default browser when selected by the user.
+     */
+    @Override
+    public void onListItemClick(ListView listView, View view, int position, long id) {
+        super.onListItemClick(listView, view, position, id);
+
+        // Get a URI for the selected item, then start an Activity that displays the URI. Any
+        // Activity that filters for ACTION_VIEW and a URI can accept this. In most cases, this will
+        // be a browser.
+
+        // Get the item at the selected position, in the form of a Cursor.
+        Cursor c = (Cursor) mAdapter.getItem(position);
+        // Get the link to the article represented by the item.
+        String articleUrlString = c.getString(COLUMN_URL_STRING);
+        if (articleUrlString == null) {
+            Log.e(TAG, "Attempt to launch entry with null link");
+            return;
+        }
+
+        Log.i(TAG, "Opening URL: " + articleUrlString);
+        // Get a Uri object for the URL string
+        Uri articleURL = Uri.parse(articleUrlString);
+        Intent i = new Intent(Intent.ACTION_VIEW, articleURL);
+        startActivity(i);
+    }
+
+    /**
+     * Set the state of the Refresh button. If a sync is active, turn on the ProgressBar widget.
+     * Otherwise, turn it off.
+     *
+     * @param refreshing True if an active sync is occuring, false otherwise
+     */
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    public void setRefreshActionButtonState(boolean refreshing) {
+        if (mOptionsMenu == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+            return;
+        }
+
+        final MenuItem refreshItem = mOptionsMenu.findItem(R.id.menu_refresh);
+        if (refreshItem != null) {
+            if (refreshing) {
+                refreshItem.setActionView(R.layout.actionbar_indeterminate_progress);
+            } else {
+                refreshItem.setActionView(null);
+            }
+        }
+    }
+
+    /**
+     * Crfate a new anonymous SyncStatusObserver. It's attached to the app's ContentResolver in
+     * onResume(), and removed in onPause(). If status changes, it sets the state of the Refresh
+     * button. If a sync is active or pending, the Refresh button is replaced by an indeterminate
+     * ProgressBar; otherwise, the button itself is displayed.
+     */
+    private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() {
+        /** Callback invoked with the sync adapter status changes. */
+        @Override
+        public void onStatusChanged(int which) {
+            getActivity().runOnUiThread(new Runnable() {
+                /**
+                 * The SyncAdapter runs on a background thread. To update the UI, onStatusChanged()
+                 * runs on the UI thread.
+                 */
+                @Override
+                public void run() {
+                    // Create a handle to the account that was created by
+                    // SyncService.CreateSyncAccount(). This will be used to query the system to
+                    // see how the sync status has changed.
+                    Account account = GenericAccountService.GetAccount(SyncUtils.ACCOUNT_TYPE);
+                    if (account == null) {
+                        // GetAccount() returned an invalid value. This shouldn't happen, but
+                        // we'll set the status to "not refreshing".
+                        setRefreshActionButtonState(false);
+                        return;
+                    }
+
+                    // Test the ContentResolver to see if the sync adapter is active or pending.
+                    // Set the state of the refresh button accordingly.
+                    boolean syncActive = ContentResolver.isSyncActive(
+                            account, FeedContract.CONTENT_AUTHORITY);
+                    boolean syncPending = ContentResolver.isSyncPending(
+                            account, FeedContract.CONTENT_AUTHORITY);
+                    setRefreshActionButtonState(syncActive || syncPending);
+                }
+            });
+        }
+    };
+
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncAdapter.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncAdapter.java
new file mode 100644
index 0000000..da67107
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncAdapter.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicsyncadapter;
+
+import android.accounts.Account;
+import android.annotation.TargetApi;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.OperationApplicationException;
+import android.content.SyncResult;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.example.android.basicsyncadapter.net.FeedParser;
+import com.example.android.basicsyncadapter.provider.FeedContract;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Define a sync adapter for the app.
+ *
+ * <p>This class is instantiated in {@link SyncService}, which also binds SyncAdapter to the system.
+ * SyncAdapter should only be initialized in SyncService, never anywhere else.
+ *
+ * <p>The system calls onPerformSync() via an RPC call through the IBinder object supplied by
+ * SyncService.
+ */
+class SyncAdapter extends AbstractThreadedSyncAdapter {
+    public static final String TAG = "SyncAdapter";
+
+    /**
+     * URL to fetch content from during a sync.
+     *
+     * <p>This points to the Android Developers Blog. (Side note: We highly recommend reading the
+     * Android Developer Blog to stay up to date on the latest Android platform developments!)
+     */
+    private static final String FEED_URL = "http://android-developers.blogspot.com/atom.xml";
+
+    /**
+     * Network connection timeout, in milliseconds.
+     */
+    private static final int NET_CONNECT_TIMEOUT_MILLIS = 15000;  // 15 seconds
+
+    /**
+     * Network read timeout, in milliseconds.
+     */
+    private static final int NET_READ_TIMEOUT_MILLIS = 10000;  // 10 seconds
+
+    /**
+     * Content resolver, for performing database operations.
+     */
+    private final ContentResolver mContentResolver;
+
+    /**
+     * Project used when querying content provider. Returns all known fields.
+     */
+    private static final String[] PROJECTION = new String[] {
+            FeedContract.Entry._ID,
+            FeedContract.Entry.COLUMN_NAME_ENTRY_ID,
+            FeedContract.Entry.COLUMN_NAME_TITLE,
+            FeedContract.Entry.COLUMN_NAME_LINK,
+            FeedContract.Entry.COLUMN_NAME_PUBLISHED};
+
+    // Constants representing column positions from PROJECTION.
+    public static final int COLUMN_ID = 0;
+    public static final int COLUMN_ENTRY_ID = 1;
+    public static final int COLUMN_TITLE = 2;
+    public static final int COLUMN_LINK = 3;
+    public static final int COLUMN_PUBLISHED = 4;
+
+    /**
+     * Constructor. Obtains handle to content resolver for later use.
+     */
+    public SyncAdapter(Context context, boolean autoInitialize) {
+        super(context, autoInitialize);
+        mContentResolver = context.getContentResolver();
+    }
+
+    /**
+     * Constructor. Obtains handle to content resolver for later use.
+     */
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
+        super(context, autoInitialize, allowParallelSyncs);
+        mContentResolver = context.getContentResolver();
+    }
+
+    /**
+     * Called by the Android system in response to a request to run the sync adapter. The work
+     * required to read data from the network, parse it, and store it in the content provider is
+     * done here. Extending AbstractThreadedSyncAdapter ensures that all methods within SyncAdapter
+     * run on a background thread. For this reason, blocking I/O and other long-running tasks can be
+     * run <em>in situ</em>, and you don't have to set up a separate thread for them.
+     .
+     *
+     * <p>This is where we actually perform any work required to perform a sync.
+     * {@link android.content.AbstractThreadedSyncAdapter} guarantees that this will be called on a non-UI thread,
+     * so it is safe to peform blocking I/O here.
+     *
+     * <p>The syncResult argument allows you to pass information back to the method that triggered
+     * the sync.
+     */
+    @Override
+    public void onPerformSync(Account account, Bundle extras, String authority,
+                              ContentProviderClient provider, SyncResult syncResult) {
+        Log.i(TAG, "Beginning network synchronization");
+        try {
+            final URL location = new URL(FEED_URL);
+            InputStream stream = null;
+
+            try {
+                Log.i(TAG, "Streaming data from network: " + location);
+                stream = downloadUrl(location);
+                updateLocalFeedData(stream, syncResult);
+                // Makes sure that the InputStream is closed after the app is
+                // finished using it.
+            } finally {
+                if (stream != null) {
+                    stream.close();
+                }
+            }
+        } catch (MalformedURLException e) {
+            Log.e(TAG, "Feed URL is malformed", e);
+            syncResult.stats.numParseExceptions++;
+            return;
+        } catch (IOException e) {
+            Log.e(TAG, "Error reading from network: " + e.toString());
+            syncResult.stats.numIoExceptions++;
+            return;
+        } catch (XmlPullParserException e) {
+            Log.e(TAG, "Error parsing feed: " + e.toString());
+            syncResult.stats.numParseExceptions++;
+            return;
+        } catch (ParseException e) {
+            Log.e(TAG, "Error parsing feed: " + e.toString());
+            syncResult.stats.numParseExceptions++;
+            return;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error updating database: " + e.toString());
+            syncResult.databaseError = true;
+            return;
+        } catch (OperationApplicationException e) {
+            Log.e(TAG, "Error updating database: " + e.toString());
+            syncResult.databaseError = true;
+            return;
+        }
+        Log.i(TAG, "Network synchronization complete");
+    }
+
+    /**
+     * Read XML from an input stream, storing it into the content provider.
+     *
+     * <p>This is where incoming data is persisted, committing the results of a sync. In order to
+     * minimize (expensive) disk operations, we compare incoming data with what's already in our
+     * database, and compute a merge. Only changes (insert/update/delete) will result in a database
+     * write.
+     *
+     * <p>As an additional optimization, we use a batch operation to perform all database writes at
+     * once.
+     *
+     * <p>Merge strategy:
+     * 1. Get cursor to all items in feed<br/>
+     * 2. For each item, check if it's in the incoming data.<br/>
+     *    a. YES: Remove from "incoming" list. Check if data has mutated, if so, perform
+     *            database UPDATE.<br/>
+     *    b. NO: Schedule DELETE from database.<br/>
+     * (At this point, incoming database only contains missing items.)<br/>
+     * 3. For any items remaining in incoming list, ADD to database.
+     */
+    public void updateLocalFeedData(final InputStream stream, final SyncResult syncResult)
+            throws IOException, XmlPullParserException, RemoteException,
+            OperationApplicationException, ParseException {
+        final FeedParser feedParser = new FeedParser();
+        final ContentResolver contentResolver = getContext().getContentResolver();
+
+        Log.i(TAG, "Parsing stream as Atom feed");
+        final List<FeedParser.Entry> entries = feedParser.parse(stream);
+        Log.i(TAG, "Parsing complete. Found " + entries.size() + " entries");
+
+
+        ArrayList<ContentProviderOperation> batch = new ArrayList<ContentProviderOperation>();
+
+        // Build hash table of incoming entries
+        HashMap<String, FeedParser.Entry> entryMap = new HashMap<String, FeedParser.Entry>();
+        for (FeedParser.Entry e : entries) {
+            entryMap.put(e.id, e);
+        }
+
+        // Get list of all items
+        Log.i(TAG, "Fetching local entries for merge");
+        Uri uri = FeedContract.Entry.CONTENT_URI; // Get all entries
+        Cursor c = contentResolver.query(uri, PROJECTION, null, null, null);
+        assert c != null;
+        Log.i(TAG, "Found " + c.getCount() + " local entries. Computing merge solution...");
+
+        // Find stale data
+        int id;
+        String entryId;
+        String title;
+        String link;
+        long published;
+        while (c.moveToNext()) {
+            syncResult.stats.numEntries++;
+            id = c.getInt(COLUMN_ID);
+            entryId = c.getString(COLUMN_ENTRY_ID);
+            title = c.getString(COLUMN_TITLE);
+            link = c.getString(COLUMN_LINK);
+            published = c.getLong(COLUMN_PUBLISHED);
+            FeedParser.Entry match = entryMap.get(entryId);
+            if (match != null) {
+                // Entry exists. Remove from entry map to prevent insert later.
+                entryMap.remove(entryId);
+                // Check to see if the entry needs to be updated
+                Uri existingUri = FeedContract.Entry.CONTENT_URI.buildUpon()
+                        .appendPath(Integer.toString(id)).build();
+                if ((match.title != null && !match.title.equals(title)) ||
+                        (match.link != null && !match.link.equals(link)) ||
+                        (match.published != published)) {
+                    // Update existing record
+                    Log.i(TAG, "Scheduling update: " + existingUri);
+                    batch.add(ContentProviderOperation.newUpdate(existingUri)
+                            .withValue(FeedContract.Entry.COLUMN_NAME_TITLE, title)
+                            .withValue(FeedContract.Entry.COLUMN_NAME_LINK, link)
+                            .withValue(FeedContract.Entry.COLUMN_NAME_PUBLISHED, published)
+                            .build());
+                    syncResult.stats.numUpdates++;
+                } else {
+                    Log.i(TAG, "No action: " + existingUri);
+                }
+            } else {
+                // Entry doesn't exist. Remove it from the database.
+                Uri deleteUri = FeedContract.Entry.CONTENT_URI.buildUpon()
+                        .appendPath(Integer.toString(id)).build();
+                Log.i(TAG, "Scheduling delete: " + deleteUri);
+                batch.add(ContentProviderOperation.newDelete(deleteUri).build());
+                syncResult.stats.numDeletes++;
+            }
+        }
+        c.close();
+
+        // Add new items
+        for (FeedParser.Entry e : entryMap.values()) {
+            Log.i(TAG, "Scheduling insert: entry_id=" + e.id);
+            batch.add(ContentProviderOperation.newInsert(FeedContract.Entry.CONTENT_URI)
+                    .withValue(FeedContract.Entry.COLUMN_NAME_ENTRY_ID, e.id)
+                    .withValue(FeedContract.Entry.COLUMN_NAME_TITLE, e.title)
+                    .withValue(FeedContract.Entry.COLUMN_NAME_LINK, e.link)
+                    .withValue(FeedContract.Entry.COLUMN_NAME_PUBLISHED, e.published)
+                    .build());
+            syncResult.stats.numInserts++;
+        }
+        Log.i(TAG, "Merge solution ready. Applying batch update");
+        mContentResolver.applyBatch(FeedContract.CONTENT_AUTHORITY, batch);
+        mContentResolver.notifyChange(
+                FeedContract.Entry.CONTENT_URI, // URI where data was modified
+                null,                           // No local observer
+                false);                         // IMPORTANT: Do not sync to network
+        // This sample doesn't support uploads, but if *your* code does, make sure you set
+        // syncToNetwork=false in the line above to prevent duplicate syncs.
+    }
+
+    /**
+     * Given a string representation of a URL, sets up a connection and gets an input stream.
+     */
+    private InputStream downloadUrl(final URL url) throws IOException {
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+        conn.setReadTimeout(NET_READ_TIMEOUT_MILLIS /* milliseconds */);
+        conn.setConnectTimeout(NET_CONNECT_TIMEOUT_MILLIS /* milliseconds */);
+        conn.setRequestMethod("GET");
+        conn.setDoInput(true);
+        // Starts the query
+        conn.connect();
+        return conn.getInputStream();
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncService.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncService.java
new file mode 100644
index 0000000..41e9c03
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncService.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicsyncadapter;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+/** Service to handle sync requests.
+ *
+ * <p>This service is invoked in response to Intents with action android.content.SyncAdapter, and
+ * returns a Binder connection to SyncAdapter.
+ *
+ * <p>For performance, only one sync adapter will be initialized within this application's context.
+ *
+ * <p>Note: The SyncService itself is not notified when a new sync occurs. It's role is to
+ * manage the lifecycle of our {@link SyncAdapter} and provide a handle to said SyncAdapter to the
+ * OS on request.
+ */
+public class SyncService extends Service {
+    private static final String TAG = "SyncService";
+
+    private static final Object sSyncAdapterLock = new Object();
+    private static SyncAdapter sSyncAdapter = null;
+
+    /**
+     * Thread-safe constructor, creates static {@link SyncAdapter} instance.
+     */
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.i(TAG, "Service created");
+        synchronized (sSyncAdapterLock) {
+            if (sSyncAdapter == null) {
+                sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
+            }
+        }
+    }
+
+    @Override
+    /**
+     * Logging-only destructor.
+     */
+    public void onDestroy() {
+        super.onDestroy();
+        Log.i(TAG, "Service destroyed");
+    }
+
+    /**
+     * Return Binder handle for IPC communication with {@link SyncAdapter}.
+     *
+     * <p>New sync requests will be sent directly to the SyncAdapter using this channel.
+     *
+     * @param intent Calling intent
+     * @return Binder handle for {@link SyncAdapter}
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        return sSyncAdapter.getSyncAdapterBinder();
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncUtils.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncUtils.java
new file mode 100644
index 0000000..b327c72
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncUtils.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicsyncadapter;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.annotation.TargetApi;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+
+import com.example.android.common.accounts.GenericAccountService;
+import com.example.android.basicsyncadapter.provider.FeedContract;
+
+/**
+ * Static helper methods for working with the sync framework.
+ */
+public class SyncUtils {
+    private static final long SYNC_FREQUENCY = 60 * 60;  // 1 hour (in seconds)
+    private static final String CONTENT_AUTHORITY = FeedContract.CONTENT_AUTHORITY;
+    private static final String PREF_SETUP_COMPLETE = "setup_complete";
+    // Value below must match the account type specified in res/xml/syncadapter.xml
+    public static final String ACCOUNT_TYPE = "com.example.android.basicsyncadapter.account";
+
+    /**
+     * Create an entry for this application in the system account list, if it isn't already there.
+     *
+     * @param context Context
+     */
+    @TargetApi(Build.VERSION_CODES.FROYO)
+    public static void CreateSyncAccount(Context context) {
+        boolean newAccount = false;
+        boolean setupComplete = PreferenceManager
+                .getDefaultSharedPreferences(context).getBoolean(PREF_SETUP_COMPLETE, false);
+
+        // Create account, if it's missing. (Either first run, or user has deleted account.)
+        Account account = GenericAccountService.GetAccount(ACCOUNT_TYPE);
+        AccountManager accountManager =
+                (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
+        if (accountManager.addAccountExplicitly(account, null, null)) {
+            // Inform the system that this account supports sync
+            ContentResolver.setIsSyncable(account, CONTENT_AUTHORITY, 1);
+            // Inform the system that this account is eligible for auto sync when the network is up
+            ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, true);
+            // Recommend a schedule for automatic synchronization. The system may modify this based
+            // on other scheduled syncs and network utilization.
+            ContentResolver.addPeriodicSync(
+                    account, CONTENT_AUTHORITY, new Bundle(),SYNC_FREQUENCY);
+            newAccount = true;
+        }
+
+        // Schedule an initial sync if we detect problems with either our account or our local
+        // data has been deleted. (Note that it's possible to clear app data WITHOUT affecting
+        // the account list, so wee need to check both.)
+        if (newAccount || !setupComplete) {
+            TriggerRefresh();
+            PreferenceManager.getDefaultSharedPreferences(context).edit()
+                    .putBoolean(PREF_SETUP_COMPLETE, true).commit();
+        }
+    }
+
+    /**
+     * Helper method to trigger an immediate sync ("refresh").
+     *
+     * <p>This should only be used when we need to preempt the normal sync schedule. Typically, this
+     * means the user has pressed the "refresh" button.
+     *
+     * Note that SYNC_EXTRAS_MANUAL will cause an immediate sync, without any optimization to
+     * preserve battery life. If you know new data is available (perhaps via a GCM notification),
+     * but the user is not actively waiting for that data, you should omit this flag; this will give
+     * the OS additional freedom in scheduling your sync request.
+     */
+    public static void TriggerRefresh() {
+        Bundle b = new Bundle();
+        // Disable sync backoff and ignore sync preferences. In other words...perform sync NOW!
+        b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+        b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+        ContentResolver.requestSync(
+                GenericAccountService.GetAccount(ACCOUNT_TYPE), // Sync account
+                FeedContract.CONTENT_AUTHORITY,                 // Content authority
+                b);                                             // Extras
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/net/FeedParser.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/net/FeedParser.java
new file mode 100644
index 0000000..a778390
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/net/FeedParser.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicsyncadapter.net;
+
+import android.text.format.Time;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class parses generic Atom feeds.
+ *
+ * <p>Given an InputStream representation of a feed, it returns a List of entries,
+ * where each list element represents a single entry (post) in the XML feed.
+ *
+ * <p>An example of an Atom feed can be found at:
+ * http://en.wikipedia.org/w/index.php?title=Atom_(standard)&oldid=560239173#Example_of_an_Atom_1.0_feed
+ */
+public class FeedParser {
+
+    // Constants indicting XML element names that we're interested in
+    private static final int TAG_ID = 1;
+    private static final int TAG_TITLE = 2;
+    private static final int TAG_PUBLISHED = 3;
+    private static final int TAG_LINK = 4;
+
+    // We don't use XML namespaces
+    private static final String ns = null;
+
+    /** Parse an Atom feed, returning a collection of Entry objects.
+     *
+     * @param in Atom feed, as a stream.
+     * @return List of {@link com.example.android.basicsyncadapter.net.FeedParser.Entry} objects.
+     * @throws org.xmlpull.v1.XmlPullParserException on error parsing feed.
+     * @throws java.io.IOException on I/O error.
+     */
+    public List<Entry> parse(InputStream in)
+            throws XmlPullParserException, IOException, ParseException {
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+            parser.setInput(in, null);
+            parser.nextTag();
+            return readFeed(parser);
+        } finally {
+            in.close();
+        }
+    }
+
+    /**
+     * Decode a feed attached to an XmlPullParser.
+     *
+     * @param parser Incoming XMl
+     * @return List of {@link com.example.android.basicsyncadapter.net.FeedParser.Entry} objects.
+     * @throws org.xmlpull.v1.XmlPullParserException on error parsing feed.
+     * @throws java.io.IOException on I/O error.
+     */
+    private List<Entry> readFeed(XmlPullParser parser)
+            throws XmlPullParserException, IOException, ParseException {
+        List<Entry> entries = new ArrayList<Entry>();
+
+        // Search for <feed> tags. These wrap the beginning/end of an Atom document.
+        //
+        // Example:
+        // <?xml version="1.0" encoding="utf-8"?>
+        // <feed xmlns="http://www.w3.org/2005/Atom">
+        // ...
+        // </feed>
+        parser.require(XmlPullParser.START_TAG, ns, "feed");
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+            String name = parser.getName();
+            // Starts by looking for the <entry> tag. This tag repeates inside of <feed> for each
+            // article in the feed.
+            //
+            // Example:
+            // <entry>
+            //   <title>Article title</title>
+            //   <link rel="alternate" type="text/html" href="http://example.com/article/1234"/>
+            //   <link rel="edit" href="http://example.com/admin/article/1234"/>
+            //   <id>urn:uuid:218AC159-7F68-4CC6-873F-22AE6017390D</id>
+            //   <published>2003-06-27T12:00:00Z</published>
+            //   <updated>2003-06-28T12:00:00Z</updated>
+            //   <summary>Article summary goes here.</summary>
+            //   <author>
+            //     <name>Rick Deckard</name>
+            //     <email>deckard@example.com</email>
+            //   </author>
+            // </entry>
+            if (name.equals("entry")) {
+                entries.add(readEntry(parser));
+            } else {
+                skip(parser);
+            }
+        }
+        return entries;
+    }
+
+    /**
+     * Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them
+     * off to their respective "read" methods for processing. Otherwise, skips the tag.
+     */
+    private Entry readEntry(XmlPullParser parser)
+            throws XmlPullParserException, IOException, ParseException {
+        parser.require(XmlPullParser.START_TAG, ns, "entry");
+        String id = null;
+        String title = null;
+        String link = null;
+        long publishedOn = 0;
+
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+            String name = parser.getName();
+            if (name.equals("id")){
+                // Example: <id>urn:uuid:218AC159-7F68-4CC6-873F-22AE6017390D</id>
+                id = readTag(parser, TAG_ID);
+            } else if (name.equals("title")) {
+                // Example: <title>Article title</title>
+                title = readTag(parser, TAG_TITLE);
+            } else if (name.equals("link")) {
+                // Example: <link rel="alternate" type="text/html" href="http://example.com/article/1234"/>
+                //
+                // Multiple link types can be included. readAlternateLink() will only return
+                // non-null when reading an "alternate"-type link. Ignore other responses.
+                String tempLink = readTag(parser, TAG_LINK);
+                if (tempLink != null) {
+                    link = tempLink;
+                }
+            } else if (name.equals("published")) {
+                // Example: <published>2003-06-27T12:00:00Z</published>
+                Time t = new Time();
+                t.parse3339(readTag(parser, TAG_PUBLISHED));
+                publishedOn = t.toMillis(false);
+            } else {
+                skip(parser);
+            }
+        }
+        return new Entry(id, title, link, publishedOn);
+    }
+
+    /**
+     * Process an incoming tag and read the selected value from it.
+     */
+    private String readTag(XmlPullParser parser, int tagType)
+            throws IOException, XmlPullParserException {
+        String tag = null;
+        String endTag = null;
+
+        switch (tagType) {
+            case TAG_ID:
+                return readBasicTag(parser, "id");
+            case TAG_TITLE:
+                return readBasicTag(parser, "title");
+            case TAG_PUBLISHED:
+                return readBasicTag(parser, "published");
+            case TAG_LINK:
+                return readAlternateLink(parser);
+            default:
+                throw new IllegalArgumentException("Unknown tag type: " + tagType);
+        }
+    }
+
+    /**
+     * Reads the body of a basic XML tag, which is guaranteed not to contain any nested elements.
+     *
+     * <p>You probably want to call readTag().
+     *
+     * @param parser Current parser object
+     * @param tag XML element tag name to parse
+     * @return Body of the specified tag
+     * @throws java.io.IOException
+     * @throws org.xmlpull.v1.XmlPullParserException
+     */
+    private String readBasicTag(XmlPullParser parser, String tag)
+            throws IOException, XmlPullParserException {
+        parser.require(XmlPullParser.START_TAG, ns, tag);
+        String result = readText(parser);
+        parser.require(XmlPullParser.END_TAG, ns, tag);
+        return result;
+    }
+
+    /**
+     * Processes link tags in the feed.
+     */
+    private String readAlternateLink(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        String link = null;
+        parser.require(XmlPullParser.START_TAG, ns, "link");
+        String tag = parser.getName();
+        String relType = parser.getAttributeValue(null, "rel");
+        if (relType.equals("alternate")) {
+            link = parser.getAttributeValue(null, "href");
+        }
+        while (true) {
+            if (parser.nextTag() == XmlPullParser.END_TAG) break;
+            // Intentionally break; consumes any remaining sub-tags.
+        }
+        return link;
+    }
+
+    /**
+     * For the tags title and summary, extracts their text values.
+     */
+    private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
+        String result = null;
+        if (parser.next() == XmlPullParser.TEXT) {
+            result = parser.getText();
+            parser.nextTag();
+        }
+        return result;
+    }
+
+    /**
+     * Skips tags the parser isn't interested in. Uses depth to handle nested tags. i.e.,
+     * if the next tag after a START_TAG isn't a matching END_TAG, it keeps going until it
+     * finds the matching END_TAG (as indicated by the value of "depth" being 0).
+     */
+    private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+        if (parser.getEventType() != XmlPullParser.START_TAG) {
+            throw new IllegalStateException();
+        }
+        int depth = 1;
+        while (depth != 0) {
+            switch (parser.next()) {
+                case XmlPullParser.END_TAG:
+                    depth--;
+                    break;
+                case XmlPullParser.START_TAG:
+                    depth++;
+                    break;
+            }
+        }
+    }
+
+    /**
+     * This class represents a single entry (post) in the XML feed.
+     *
+     * <p>It includes the data members "title," "link," and "summary."
+     */
+    public static class Entry {
+        public final String id;
+        public final String title;
+        public final String link;
+        public final long published;
+
+        Entry(String id, String title, String link, long published) {
+            this.id = id;
+            this.title = title;
+            this.link = link;
+            this.published = published;
+        }
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedContract.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedContract.java
new file mode 100644
index 0000000..e29ec48
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedContract.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicsyncadapter.provider;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+/**
+ * Field and table name constants for
+ * {@link com.example.android.basicsyncadapter.provider.FeedProvider}.
+ */
+public class FeedContract {
+    private FeedContract() {
+    }
+
+    /**
+     * Content provider authority.
+     */
+    public static final String CONTENT_AUTHORITY = "com.example.android.basicsyncadapter";
+
+    /**
+     * Base URI. (content://com.example.android.basicsyncadapter)
+     */
+    public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
+
+    /**
+     * Path component for "entry"-type resources..
+     */
+    private static final String PATH_ENTRIES = "entries";
+
+    /**
+     * Columns supported by "entries" records.
+     */
+    public static class Entry implements BaseColumns {
+        /**
+         * MIME type for lists of entries.
+         */
+        public static final String CONTENT_TYPE =
+                ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.basicsyncadapter.entries";
+        /**
+         * MIME type for individual entries.
+         */
+        public static final String CONTENT_ITEM_TYPE =
+                ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.basicsyncadapter.entry";
+
+        /**
+         * Fully qualified URI for "entry" resources.
+         */
+        public static final Uri CONTENT_URI =
+                BASE_CONTENT_URI.buildUpon().appendPath(PATH_ENTRIES).build();
+
+        /**
+         * Table name where records are stored for "entry" resources.
+         */
+        public static final String TABLE_NAME = "entry";
+        /**
+         * Atom ID. (Note: Not to be confused with the database primary key, which is _ID.
+         */
+        public static final String COLUMN_NAME_ENTRY_ID = "entry_id";
+        /**
+         * Article title
+         */
+        public static final String COLUMN_NAME_TITLE = "title";
+        /**
+         * Article hyperlink. Corresponds to the rel="alternate" link in the
+         * Atom spec.
+         */
+        public static final String COLUMN_NAME_LINK = "link";
+        /**
+         * Date article was published.
+         */
+        public static final String COLUMN_NAME_PUBLISHED = "published";
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedProvider.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedProvider.java
new file mode 100644
index 0000000..80bf1d3
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedProvider.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicsyncadapter.provider;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
+
+import com.example.android.common.db.SelectionBuilder;
+
+public class FeedProvider extends ContentProvider {
+    FeedDatabase mDatabaseHelper;
+
+    /**
+     * Content authority for this provider.
+     */
+    private static final String AUTHORITY = FeedContract.CONTENT_AUTHORITY;
+
+    // The constants below represent individual URI routes, as IDs. Every URI pattern recognized by
+    // this ContentProvider is defined using sUriMatcher.addURI(), and associated with one of these
+    // IDs.
+    //
+    // When a incoming URI is run through sUriMatcher, it will be tested against the defined
+    // URI patterns, and the corresponding route ID will be returned.
+    /**
+     * URI ID for route: /entries
+     */
+    public static final int ROUTE_ENTRIES = 1;
+
+    /**
+     * URI ID for route: /entries/{ID}
+     */
+    public static final int ROUTE_ENTRIES_ID = 2;
+
+    /**
+     * UriMatcher, used to decode incoming URIs.
+     */
+    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+    static {
+        sUriMatcher.addURI(AUTHORITY, "entries", ROUTE_ENTRIES);
+        sUriMatcher.addURI(AUTHORITY, "entries/*", ROUTE_ENTRIES_ID);
+    }
+
+    @Override
+    public boolean onCreate() {
+        mDatabaseHelper = new FeedDatabase(getContext());
+        return true;
+    }
+
+    /**
+     * Determine the mime type for entries returned by a given URI.
+     */
+    @Override
+    public String getType(Uri uri) {
+        final int match = sUriMatcher.match(uri);
+        switch (match) {
+            case ROUTE_ENTRIES:
+                return FeedContract.Entry.CONTENT_TYPE;
+            case ROUTE_ENTRIES_ID:
+                return FeedContract.Entry.CONTENT_ITEM_TYPE;
+            default:
+                throw new UnsupportedOperationException("Unknown uri: " + uri);
+        }
+    }
+
+    /**
+     * Perform a database query by URI.
+     *
+     * <p>Currently supports returning all entries (/entries) and individual entries by ID
+     * (/entries/{ID}).
+     */
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+                        String sortOrder) {
+        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
+        SelectionBuilder builder = new SelectionBuilder();
+        int uriMatch = sUriMatcher.match(uri);
+        switch (uriMatch) {
+            case ROUTE_ENTRIES_ID:
+                // Return a single entry, by ID.
+                String id = uri.getLastPathSegment();
+                builder.where(FeedContract.Entry._ID + "=?", id);
+            case ROUTE_ENTRIES:
+                // Return all known entries.
+                builder.table(FeedContract.Entry.TABLE_NAME)
+                       .where(selection, selectionArgs);
+                Cursor c = builder.query(db, projection, sortOrder);
+                // Note: Notification URI must be manually set here for loaders to correctly
+                // register ContentObservers.
+                Context ctx = getContext();
+                assert ctx != null;
+                c.setNotificationUri(ctx.getContentResolver(), uri);
+                return c;
+            default:
+                throw new UnsupportedOperationException("Unknown uri: " + uri);
+        }
+    }
+
+    /**
+     * Insert a new entry into the database.
+     */
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+        assert db != null;
+        final int match = sUriMatcher.match(uri);
+        Uri result;
+        switch (match) {
+            case ROUTE_ENTRIES:
+                long id = db.insertOrThrow(FeedContract.Entry.TABLE_NAME, null, values);
+                result = Uri.parse(FeedContract.Entry.CONTENT_URI + "/" + id);
+                break;
+            case ROUTE_ENTRIES_ID:
+                throw new UnsupportedOperationException("Insert not supported on URI: " + uri);
+            default:
+                throw new UnsupportedOperationException("Unknown uri: " + uri);
+        }
+        // Send broadcast to registered ContentObservers, to refresh UI.
+        Context ctx = getContext();
+        assert ctx != null;
+        ctx.getContentResolver().notifyChange(uri, null, false);
+        return result;
+    }
+
+    /**
+     * Delete an entry by database by URI.
+     */
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        SelectionBuilder builder = new SelectionBuilder();
+        final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+        final int match = sUriMatcher.match(uri);
+        int count;
+        switch (match) {
+            case ROUTE_ENTRIES:
+                count = builder.table(FeedContract.Entry.TABLE_NAME)
+                        .where(selection, selectionArgs)
+                        .delete(db);
+                break;
+            case ROUTE_ENTRIES_ID:
+                String id = uri.getLastPathSegment();
+                count = builder.table(FeedContract.Entry.TABLE_NAME)
+                       .where(FeedContract.Entry._ID + "=?", id)
+                       .where(selection, selectionArgs)
+                       .delete(db);
+                break;
+            default:
+                throw new UnsupportedOperationException("Unknown uri: " + uri);
+        }
+        // Send broadcast to registered ContentObservers, to refresh UI.
+        Context ctx = getContext();
+        assert ctx != null;
+        ctx.getContentResolver().notifyChange(uri, null, false);
+        return count;
+    }
+
+    /**
+     * Update an etry in the database by URI.
+     */
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        SelectionBuilder builder = new SelectionBuilder();
+        final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+        final int match = sUriMatcher.match(uri);
+        int count;
+        switch (match) {
+            case ROUTE_ENTRIES:
+                count = builder.table(FeedContract.Entry.TABLE_NAME)
+                        .where(selection, selectionArgs)
+                        .update(db, values);
+                break;
+            case ROUTE_ENTRIES_ID:
+                String id = uri.getLastPathSegment();
+                count = builder.table(FeedContract.Entry.TABLE_NAME)
+                        .where(FeedContract.Entry._ID + "=?", id)
+                        .where(selection, selectionArgs)
+                        .update(db, values);
+                break;
+            default:
+                throw new UnsupportedOperationException("Unknown uri: " + uri);
+        }
+        Context ctx = getContext();
+        assert ctx != null;
+        ctx.getContentResolver().notifyChange(uri, null, false);
+        return count;
+    }
+
+    /**
+     * SQLite backend for @{link FeedProvider}.
+     *
+     * Provides access to an disk-backed, SQLite datastore which is utilized by FeedProvider. This
+     * database should never be accessed by other parts of the application directly.
+     */
+    static class FeedDatabase extends SQLiteOpenHelper {
+        /** Schema version. */
+        public static final int DATABASE_VERSION = 1;
+        /** Filename for SQLite file. */
+        public static final String DATABASE_NAME = "feed.db";
+
+        private static final String TYPE_TEXT = " TEXT";
+        private static final String TYPE_INTEGER = " INTEGER";
+        private static final String COMMA_SEP = ",";
+        /** SQL statement to create "entry" table. */
+        private static final String SQL_CREATE_ENTRIES =
+                "CREATE TABLE " + FeedContract.Entry.TABLE_NAME + " (" +
+                        FeedContract.Entry._ID + " INTEGER PRIMARY KEY," +
+                        FeedContract.Entry.COLUMN_NAME_ENTRY_ID + TYPE_TEXT + COMMA_SEP +
+                        FeedContract.Entry.COLUMN_NAME_TITLE    + TYPE_TEXT + COMMA_SEP +
+                        FeedContract.Entry.COLUMN_NAME_LINK + TYPE_TEXT + COMMA_SEP +
+                        FeedContract.Entry.COLUMN_NAME_PUBLISHED + TYPE_INTEGER + ")";
+
+        /** SQL statement to drop "entry" table. */
+        private static final String SQL_DELETE_ENTRIES =
+                "DROP TABLE IF EXISTS " + FeedContract.Entry.TABLE_NAME;
+
+        public FeedDatabase(Context context) {
+            super(context, DATABASE_NAME, null, DATABASE_VERSION);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL(SQL_CREATE_ENTRIES);
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            // This database is only a cache for online data, so its upgrade policy is
+            // to simply to discard the data and start over
+            db.execSQL(SQL_DELETE_ENTRIES);
+            onCreate(db);
+        }
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/accounts/GenericAccountService.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/accounts/GenericAccountService.java
new file mode 100644
index 0000000..0cd499a
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/accounts/GenericAccountService.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.accounts;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.NetworkErrorException;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+public class GenericAccountService extends Service {
+    private static final String TAG = "GenericAccountService";
+    public static final String ACCOUNT_NAME = "Account";
+    private Authenticator mAuthenticator;
+
+    /**
+     * Obtain a handle to the {@link android.accounts.Account} used for sync in this application.
+     *
+     * <p>It is important that the accountType specified here matches the value in your sync adapter
+     * configuration XML file for android.accounts.AccountAuthenticator (often saved in
+     * res/xml/syncadapter.xml). If this is not set correctly, you'll receive an error indicating
+     * that "caller uid XXXXX is different than the authenticator's uid".
+     *
+     * @param accountType AccountType defined in the configuration XML file for
+     *                    android.accounts.AccountAuthenticator (e.g. res/xml/syncadapter.xml).
+     * @return Handle to application's account (not guaranteed to resolve unless CreateSyncAccount()
+     *         has been called)
+     */
+    public static Account GetAccount(String accountType) {
+        // Note: Normally the account name is set to the user's identity (username or email
+        // address). However, since we aren't actually using any user accounts, it makes more sense
+        // to use a generic string in this case.
+        //
+        // This string should *not* be localized. If the user switches locale, we would not be
+        // able to locate the old account, and may erroneously register multiple accounts.
+        final String accountName = ACCOUNT_NAME;
+        return new Account(accountName, accountType);
+    }
+
+    @Override
+    public void onCreate() {
+        Log.i(TAG, "Service created");
+        mAuthenticator = new Authenticator(this);
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.i(TAG, "Service destroyed");
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mAuthenticator.getIBinder();
+    }
+
+    public class Authenticator extends AbstractAccountAuthenticator {
+        public Authenticator(Context context) {
+            super(context);
+        }
+
+        @Override
+        public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                     String s) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Bundle addAccount(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                 String s, String s2, String[] strings, Bundle bundle)
+                throws NetworkErrorException {
+            return null;
+        }
+
+        @Override
+        public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                         Account account, Bundle bundle)
+                throws NetworkErrorException {
+            return null;
+        }
+
+        @Override
+        public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                   Account account, String s, Bundle bundle)
+                throws NetworkErrorException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getAuthTokenLabel(String s) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                        Account account, String s, Bundle bundle)
+                throws NetworkErrorException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                  Account account, String[] strings)
+                throws NetworkErrorException {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+}
+
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/db/SelectionBuilder.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/db/SelectionBuilder.java
new file mode 100644
index 0000000..a1964c5
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/db/SelectionBuilder.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Modifications:
+ * -Imported from AOSP frameworks/base/core/java/com/android/internal/content
+ * -Changed package name
+ */
+
+package com.example.android.common.db;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Helper for building selection clauses for {@link SQLiteDatabase}.
+ *
+ * <p>This class provides a convenient frontend for working with SQL. Instead of composing statements
+ * manually using string concatenation, method calls are used to construct the statement one
+ * clause at a time. These methods can be chained together.
+ *
+ * <p>If multiple where() statements are provided, they're combined using {@code AND}.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ *     SelectionBuilder builder = new SelectionBuilder();
+ *     Cursor c = builder.table(FeedContract.Entry.TABLE_NAME)       // String TABLE_NAME = "entry"
+ *                       .where(FeedContract.Entry._ID + "=?", id);  // String _ID = "_ID"
+ *                       .query(db, projection, sortOrder)
+ *
+ * </pre>
+ *
+ * <p>In this example, the table name and filters ({@code WHERE} clauses) are both explicitly
+ * specified via method call. SelectionBuilder takes care of issuing a "query" command to the
+ * database, and returns the resulting {@link Cursor} object.
+ *
+ * <p>Inner {@code JOIN}s can be accomplished using the mapToTable() function. The map() function
+ * can be used to create new columns based on arbitrary (SQL-based) criteria. In advanced usage,
+ * entire subqueries can be passed into the map() function.
+ *
+ * <p>Advanced example:
+ *
+ * <pre>
+ *     // String SESSIONS_JOIN_BLOCKS_ROOMS = "sessions "
+ *     //        + "LEFT OUTER JOIN blocks ON sessions.block_id=blocks.block_id "
+ *     //        + "LEFT OUTER JOIN rooms ON sessions.room_id=rooms.room_id";
+ *
+ *     // String Subquery.BLOCK_NUM_STARRED_SESSIONS =
+ *     //       "(SELECT COUNT(1) FROM "
+ *     //        + Tables.SESSIONS + " WHERE " + Qualified.SESSIONS_BLOCK_ID + "="
+ *     //        + Qualified.BLOCKS_BLOCK_ID + " AND " + Qualified.SESSIONS_STARRED + "=1)";
+ *
+ *     String Subqery.BLOCK_SESSIONS_COUNT =
+ *     Cursor c = builder.table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS)
+ *               .map(Blocks.NUM_STARRED_SESSIONS, Subquery.BLOCK_NUM_STARRED_SESSIONS)
+ *               .mapToTable(Sessions._ID, Tables.SESSIONS)
+ *               .mapToTable(Sessions.SESSION_ID, Tables.SESSIONS)
+ *               .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
+ *               .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
+ *               .where(Qualified.SESSIONS_BLOCK_ID + "=?", blockId);
+ * </pre>
+ *
+ * <p>In this example, we have two different types of {@code JOIN}s: a left outer join using a
+ * modified table name (since this class doesn't directly support these), and an inner join using
+ * the mapToTable() function. The map() function is used to insert a count based on specific
+ * criteria, executed as a sub-query.
+ *
+ * This class is <em>not</em> thread safe.
+ */
+public class SelectionBuilder {
+    private static final String TAG = "basicsyncadapter";
+
+    private String mTable = null;
+    private Map<String, String> mProjectionMap = new HashMap<String, String>();
+    private StringBuilder mSelection = new StringBuilder();
+    private ArrayList<String> mSelectionArgs = new ArrayList<String>();
+
+    /**
+     * Reset any internal state, allowing this builder to be recycled.
+     *
+     * <p>Calling this method is more efficient than creating a new SelectionBuilder object.
+     *
+     * @return Fluent interface
+     */
+    public SelectionBuilder reset() {
+        mTable = null;
+        mSelection.setLength(0);
+        mSelectionArgs.clear();
+        return this;
+    }
+
+    /**
+     * Append the given selection clause to the internal state. Each clause is
+     * surrounded with parenthesis and combined using {@code AND}.
+     *
+     * <p>In the most basic usage, simply provide a selection in SQL {@code WHERE} statement format.
+     *
+     * <p>Example:
+     *
+     * <pre>
+     *     .where("blog_posts.category = 'PROGRAMMING');
+     * </pre>
+     *
+     * <p>User input should never be directly supplied as as part of the selection statement.
+     * Instead, use positional parameters in your selection statement, then pass the user input
+     * in via the selectionArgs parameter. This prevents SQL escape characters in user input from
+     * causing unwanted side effects. (Failure to follow this convention may have security
+     * implications.)
+     *
+     * <p>Positional parameters are specified using the '?' character.
+     *
+     * <p>Example:
+     * <pre>
+     *     .where("blog_posts.title contains ?, userSearchString);
+     * </pre>
+     *
+     * @param selection SQL where statement
+     * @param selectionArgs Values to substitute for positional parameters ('?' characters in
+     *                      {@code selection} statement. Will be automatically escaped.
+     * @return Fluent interface
+     */
+    public SelectionBuilder where(String selection, String... selectionArgs) {
+        if (TextUtils.isEmpty(selection)) {
+            if (selectionArgs != null && selectionArgs.length > 0) {
+                throw new IllegalArgumentException(
+                        "Valid selection required when including arguments=");
+            }
+
+            // Shortcut when clause is empty
+            return this;
+        }
+
+        if (mSelection.length() > 0) {
+            mSelection.append(" AND ");
+        }
+
+        mSelection.append("(").append(selection).append(")");
+        if (selectionArgs != null) {
+            Collections.addAll(mSelectionArgs, selectionArgs);
+        }
+
+        return this;
+    }
+
+    /**
+     * Table name to use for SQL {@code FROM} statement.
+     *
+     * <p>This method may only be called once. If multiple tables are required, concatenate them
+     * in SQL-format (typically comma-separated).
+     *
+     * <p>If you need to do advanced {@code JOIN}s, they can also be specified here.
+     *
+     * See also: mapToTable()
+     *
+     * @param table Table name
+     * @return Fluent interface
+     */
+    public SelectionBuilder table(String table) {
+        mTable = table;
+        return this;
+    }
+
+    /**
+     * Verify that a table name has been supplied using table().
+     *
+     * @throws IllegalStateException if table not set
+     */
+    private void assertTable() {
+        if (mTable == null) {
+            throw new IllegalStateException("Table not specified");
+        }
+    }
+
+    /**
+     * Perform an inner join.
+     *
+     * <p>Map columns from a secondary table onto the current result set. References to the column
+     * specified in {@code column} will be replaced with {@code table.column} in the SQL {@code
+     * SELECT} clause.
+     *
+     * @param column Column name to join on. Must be the same in both tables.
+     * @param table Secondary table to join.
+     * @return Fluent interface
+     */
+    public SelectionBuilder mapToTable(String column, String table) {
+        mProjectionMap.put(column, table + "." + column);
+        return this;
+    }
+
+    /**
+     * Create a new column based on custom criteria (such as aggregate functions).
+     *
+     * <p>This adds a new column to the result set, based upon custom criteria in SQL format. This
+     * is equivalent to the SQL statement: {@code SELECT toClause AS fromColumn}
+     *
+     * <p>This method is useful for executing SQL sub-queries.
+     *
+     * @param fromColumn Name of column for mapping
+     * @param toClause SQL string representing data to be mapped
+     * @return Fluent interface
+     */
+    public SelectionBuilder map(String fromColumn, String toClause) {
+        mProjectionMap.put(fromColumn, toClause + " AS " + fromColumn);
+        return this;
+    }
+
+    /**
+     * Return selection string based on current internal state.
+     *
+     * @return Current selection as a SQL statement
+     * @see #getSelectionArgs()
+     */
+    public String getSelection() {
+        return mSelection.toString();
+
+    }
+
+    /**
+     * Return selection arguments based on current internal state.
+     *
+     * @see #getSelection()
+     */
+    public String[] getSelectionArgs() {
+        return mSelectionArgs.toArray(new String[mSelectionArgs.size()]);
+    }
+
+    /**
+     * Process user-supplied projection (column list).
+     *
+     * <p>In cases where a column is mapped to another data source (either another table, or an
+     * SQL sub-query), the column name will be replaced with a more specific, SQL-compatible
+     * representation.
+     *
+     * Assumes that incoming columns are non-null.
+     *
+     * <p>See also: map(), mapToTable()
+     *
+     * @param columns User supplied projection (column list).
+     */
+    private void mapColumns(String[] columns) {
+        for (int i = 0; i < columns.length; i++) {
+            final String target = mProjectionMap.get(columns[i]);
+            if (target != null) {
+                columns[i] = target;
+            }
+        }
+    }
+
+    /**
+     * Return a description of this builder's state. Does NOT output SQL.
+     *
+     * @return Human-readable internal state
+     */
+    @Override
+    public String toString() {
+        return "SelectionBuilder[table=" + mTable + ", selection=" + getSelection()
+                + ", selectionArgs=" + Arrays.toString(getSelectionArgs()) + "]";
+    }
+
+    /**
+     * Execute query (SQL {@code SELECT}) against specified database.
+     *
+     * <p>Using a null projection (column list) is not supported.
+     *
+     * @param db Database to query.
+     * @param columns Database projection (column list) to return, must be non-NULL.
+     * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause (excluding the
+     *                ORDER BY itself). Passing null will use the default sort order, which may be
+     *                unordered.
+     * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+     *         {@link Cursor}s are not synchronized, see the documentation for more details.
+     */
+    public Cursor query(SQLiteDatabase db, String[] columns, String orderBy) {
+        return query(db, columns, null, null, orderBy, null);
+    }
+
+    /**
+     * Execute query ({@code SELECT}) against database.
+     *
+     * <p>Using a null projection (column list) is not supported.
+     *
+     * @param db Database to query.
+     * @param columns Database projection (column list) to return, must be non-null.
+     * @param groupBy A filter declaring how to group rows, formatted as an SQL GROUP BY clause
+     *                (excluding the GROUP BY itself). Passing null will cause the rows to not be
+     *                grouped.
+     * @param having A filter declare which row groups to include in the cursor, if row grouping is
+     *               being used, formatted as an SQL HAVING clause (excluding the HAVING itself).
+     *               Passing null will cause all row groups to be included, and is required when
+     *               row grouping is not being used.
+     * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause (excluding the
+     *                ORDER BY itself). Passing null will use the default sort order, which may be
+     *                unordered.
+     * @param limit Limits the number of rows returned by the query, formatted as LIMIT clause.
+     *              Passing null denotes no LIMIT clause.
+     * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+     *         {@link Cursor}s are not synchronized, see the documentation for more details.
+     */
+    public Cursor query(SQLiteDatabase db, String[] columns, String groupBy,
+                        String having, String orderBy, String limit) {
+        assertTable();
+        if (columns != null) mapColumns(columns);
+        Log.v(TAG, "query(columns=" + Arrays.toString(columns) + ") " + this);
+        return db.query(mTable, columns, getSelection(), getSelectionArgs(), groupBy, having,
+                orderBy, limit);
+    }
+
+    /**
+     * Execute an {@code UPDATE} against database.
+     *
+     * @param db Database to query.
+     * @param values A map from column names to new column values. null is a valid value that will
+     *               be translated to NULL
+     * @return The number of rows affected.
+     */
+    public int update(SQLiteDatabase db, ContentValues values) {
+        assertTable();
+        Log.v(TAG, "update() " + this);
+        return db.update(mTable, values, getSelection(), getSelectionArgs());
+    }
+
+    /**
+     * Execute {@code DELETE} against database.
+     *
+     * @param db Database to query.
+     * @return The number of rows affected.
+     */
+    public int delete(SQLiteDatabase db) {
+        assertTable();
+        Log.v(TAG, "delete() " + this);
+        return db.delete(mTable, getSelection(), getSelectionArgs());
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/Log.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogNode.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogView.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/BluetoothLeGatt/AndroidManifest.xml b/samples/browseable/BluetoothLeGatt/AndroidManifest.xml
new file mode 100644
index 0000000..babd6df
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.bluetoothlegatt"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="18"
+        android:targetSdkVersion="18"/>
+    <!-- Declare this required feature if you want to make the app available to BLE-capable
+    devices only.  If you want to make your app available to devices that don't support BLE,
+    you should omit this in the manifest.  Instead, determine BLE capability by using
+    PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) -->
+    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
+
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+
+    <application android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@android:style/Theme.Holo.Light">
+        <activity android:name=".DeviceScanActivity"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <activity android:name=".DeviceControlActivity"/>
+        <service android:name=".BluetoothLeService" android:enabled="true"/>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/BluetoothLeGatt/_index.jd b/samples/browseable/BluetoothLeGatt/_index.jd
new file mode 100644
index 0000000..6e89669
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/_index.jd
@@ -0,0 +1,12 @@
+
+
+
+page.tags="BluetoothLeGatt"
+sample.group=Connectivity
+@jd:body
+
+<p>This sample demonstrates how to use the Bluetooth Low Energy Generic
+Attribute Profile (GATT) to transmit arbitrary data between devices. For more
+information about using Android's suppport for Bluetooth Low Energy, see
+<a href="{@docRoot}guide/topics/connectivity/bluetooth-le.html">Bluetooth Low
+Energy</a>.</p>
diff --git a/samples/browseable/BluetoothLeGatt/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BluetoothLeGatt/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..15367c0
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BluetoothLeGatt/res/drawable-hdpi/tile.9.png b/samples/browseable/BluetoothLeGatt/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BluetoothLeGatt/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BluetoothLeGatt/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..ba810a7
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BluetoothLeGatt/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BluetoothLeGatt/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..14f1d74
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BluetoothLeGatt/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BluetoothLeGatt/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..81ff9cc
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BluetoothLeGatt/res/layout/actionbar_indeterminate_progress.xml b/samples/browseable/BluetoothLeGatt/res/layout/actionbar_indeterminate_progress.xml
new file mode 100644
index 0000000..a950833
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/layout/actionbar_indeterminate_progress.xml
@@ -0,0 +1,23 @@
+<!--
+  Copyright 2013 Google Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_height="wrap_content"
+             android:layout_width="56dp"
+             android:minWidth="56dp">
+    <ProgressBar android:layout_width="32dp"
+                 android:layout_height="32dp"
+                 android:layout_gravity="center"/>
+</FrameLayout>
diff --git a/samples/browseable/BluetoothLeGatt/res/layout/activity_main.xml b/samples/browseable/BluetoothLeGatt/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BluetoothLeGatt/res/layout/gatt_services_characteristics.xml b/samples/browseable/BluetoothLeGatt/res/layout/gatt_services_characteristics.xml
new file mode 100644
index 0000000..2f31061
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/layout/gatt_services_characteristics.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="10dp">
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_margin="10dp">
+        <TextView android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:text="@string/label_device_address"
+                  android:textSize="18sp"/>
+        <Space android:layout_width="5dp"
+               android:layout_height="wrap_content"/>
+        <TextView android:id="@+id/device_address"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textSize="18sp"/>
+    </LinearLayout>
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_margin="10dp">
+        <TextView android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:text="@string/label_state"
+                  android:textSize="18sp"/>
+        <Space android:layout_width="5dp"
+               android:layout_height="wrap_content"/>
+        <TextView android:id="@+id/connection_state"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:text="@string/disconnected"
+                  android:textSize="18sp"/>
+    </LinearLayout>
+    <LinearLayout android:orientation="horizontal"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_margin="10dp">
+        <TextView android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:text="@string/label_data"
+                  android:textSize="18sp"/>
+        <Space android:layout_width="5dp"
+               android:layout_height="wrap_content"/>
+        <TextView android:id="@+id/data_value"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:text="@string/no_data"
+                  android:textSize="18sp"/>
+    </LinearLayout>
+    <ExpandableListView android:id="@+id/gatt_services_list"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/BluetoothLeGatt/res/layout/listitem_device.xml b/samples/browseable/BluetoothLeGatt/res/layout/listitem_device.xml
new file mode 100644
index 0000000..eff44fc
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/layout/listitem_device.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+    <TextView android:id="@+id/device_name"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textSize="24dp"/>
+    <TextView android:id="@+id/device_address"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textSize="12dp"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/BluetoothLeGatt/res/menu/gatt_services.xml b/samples/browseable/BluetoothLeGatt/res/menu/gatt_services.xml
new file mode 100644
index 0000000..464d32f
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/menu/gatt_services.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_refresh"
+          android:checkable="false"
+          android:orderInCategory="1"
+          android:showAsAction="ifRoom"/>
+    <item android:id="@+id/menu_connect"
+          android:title="@string/menu_connect"
+          android:orderInCategory="100"
+          android:showAsAction="ifRoom|withText"/>
+    <item android:id="@+id/menu_disconnect"
+          android:title="@string/menu_disconnect"
+          android:orderInCategory="101"
+          android:showAsAction="ifRoom|withText"/>
+</menu>
diff --git a/samples/browseable/BluetoothLeGatt/res/menu/main.xml b/samples/browseable/BluetoothLeGatt/res/menu/main.xml
new file mode 100644
index 0000000..39dd66a
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/menu/main.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_refresh"
+          android:checkable="false"
+          android:orderInCategory="1"
+          android:showAsAction="ifRoom"/>
+    <item android:id="@+id/menu_scan"
+          android:title="@string/menu_scan"
+          android:orderInCategory="100"
+          android:showAsAction="ifRoom|withText"/>
+    <item android:id="@+id/menu_stop"
+          android:title="@string/menu_stop"
+          android:orderInCategory="101"
+          android:showAsAction="ifRoom|withText"/>
+</menu>
diff --git a/samples/browseable/BluetoothLeGatt/res/values-sw600dp/dimens.xml b/samples/browseable/BluetoothLeGatt/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BluetoothLeGatt/res/values-sw600dp/styles.xml b/samples/browseable/BluetoothLeGatt/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BluetoothLeGatt/res/values/base-strings.xml b/samples/browseable/BluetoothLeGatt/res/values/base-strings.xml
new file mode 100644
index 0000000..58b49a9
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BluetoothLeGatt</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates how to use the Bluetooth LE Generic Attribute Profile (GATT)
+            to transmit arbitrary data between devices.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BluetoothLeGatt/res/values/dimens.xml b/samples/browseable/BluetoothLeGatt/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BluetoothLeGatt/res/values/strings.xml b/samples/browseable/BluetoothLeGatt/res/values/strings.xml
new file mode 100644
index 0000000..19f3dce
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/values/strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <string name="ble_not_supported">BLE is not supported</string>
+    <string name="label_data">Data:</string>
+    <string name="label_device_address">Device address:</string>
+    <string name="label_state">State:</string>
+    <string name="no_data">No data</string>
+    <string name="connected">Connected</string>
+    <string name="disconnected">Disconnected</string>
+    <string name="title_devices">BLE Device Scan</string>
+    <string name="error_bluetooth_not_supported">Bluetooth not supported.</string>
+
+    <string name="unknown_device">Unknown device</string>
+    <string name="unknown_characteristic">Unknown characteristic</string>
+    <string name="unknown_service">Unknown service</string>
+
+    <!-- Menu items -->
+    <string name="menu_connect">Connect</string>
+    <string name="menu_disconnect">Disconnect</string>
+    <string name="menu_scan">Scan</string>
+    <string name="menu_stop">Stop</string>
+</resources>
diff --git a/samples/browseable/BluetoothLeGatt/res/values/styles.xml b/samples/browseable/BluetoothLeGatt/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/BluetoothLeService.java b/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/BluetoothLeService.java
new file mode 100644
index 0000000..694faaf
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/BluetoothLeService.java
@@ -0,0 +1,319 @@
+/*
+ * 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.bluetoothlegatt;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Service for managing connection and data communication with a GATT server hosted on a
+ * given Bluetooth LE device.
+ */
+public class BluetoothLeService extends Service {
+    private final static String TAG = BluetoothLeService.class.getSimpleName();
+
+    private BluetoothManager mBluetoothManager;
+    private BluetoothAdapter mBluetoothAdapter;
+    private String mBluetoothDeviceAddress;
+    private BluetoothGatt mBluetoothGatt;
+    private int mConnectionState = STATE_DISCONNECTED;
+
+    private static final int STATE_DISCONNECTED = 0;
+    private static final int STATE_CONNECTING = 1;
+    private static final int STATE_CONNECTED = 2;
+
+    public final static String ACTION_GATT_CONNECTED =
+            "com.example.bluetooth.le.ACTION_GATT_CONNECTED";
+    public final static String ACTION_GATT_DISCONNECTED =
+            "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
+    public final static String ACTION_GATT_SERVICES_DISCOVERED =
+            "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
+    public final static String ACTION_DATA_AVAILABLE =
+            "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
+    public final static String EXTRA_DATA =
+            "com.example.bluetooth.le.EXTRA_DATA";
+
+    public final static UUID UUID_HEART_RATE_MEASUREMENT =
+            UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
+
+    // Implements callback methods for GATT events that the app cares about.  For example,
+    // connection change and services discovered.
+    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
+        @Override
+        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+            String intentAction;
+            if (newState == BluetoothProfile.STATE_CONNECTED) {
+                intentAction = ACTION_GATT_CONNECTED;
+                mConnectionState = STATE_CONNECTED;
+                broadcastUpdate(intentAction);
+                Log.i(TAG, "Connected to GATT server.");
+                // Attempts to discover services after successful connection.
+                Log.i(TAG, "Attempting to start service discovery:" +
+                        mBluetoothGatt.discoverServices());
+
+            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+                intentAction = ACTION_GATT_DISCONNECTED;
+                mConnectionState = STATE_DISCONNECTED;
+                Log.i(TAG, "Disconnected from GATT server.");
+                broadcastUpdate(intentAction);
+            }
+        }
+
+        @Override
+        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
+            } else {
+                Log.w(TAG, "onServicesDiscovered received: " + status);
+            }
+        }
+
+        @Override
+        public void onCharacteristicRead(BluetoothGatt gatt,
+                                         BluetoothGattCharacteristic characteristic,
+                                         int status) {
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
+            }
+        }
+
+        @Override
+        public void onCharacteristicChanged(BluetoothGatt gatt,
+                                            BluetoothGattCharacteristic characteristic) {
+            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
+        }
+    };
+
+    private void broadcastUpdate(final String action) {
+        final Intent intent = new Intent(action);
+        sendBroadcast(intent);
+    }
+
+    private void broadcastUpdate(final String action,
+                                 final BluetoothGattCharacteristic characteristic) {
+        final Intent intent = new Intent(action);
+
+        // This is special handling for the Heart Rate Measurement profile.  Data parsing is
+        // carried out as per profile specifications:
+        // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
+        if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
+            int flag = characteristic.getProperties();
+            int format = -1;
+            if ((flag & 0x01) != 0) {
+                format = BluetoothGattCharacteristic.FORMAT_UINT16;
+                Log.d(TAG, "Heart rate format UINT16.");
+            } else {
+                format = BluetoothGattCharacteristic.FORMAT_UINT8;
+                Log.d(TAG, "Heart rate format UINT8.");
+            }
+            final int heartRate = characteristic.getIntValue(format, 1);
+            Log.d(TAG, String.format("Received heart rate: %d", heartRate));
+            intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
+        } else {
+            // For all other profiles, writes the data formatted in HEX.
+            final byte[] data = characteristic.getValue();
+            if (data != null && data.length > 0) {
+                final StringBuilder stringBuilder = new StringBuilder(data.length);
+                for(byte byteChar : data)
+                    stringBuilder.append(String.format("%02X ", byteChar));
+                intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
+            }
+        }
+        sendBroadcast(intent);
+    }
+
+    public class LocalBinder extends Binder {
+        BluetoothLeService getService() {
+            return BluetoothLeService.this;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        // After using a given device, you should make sure that BluetoothGatt.close() is called
+        // such that resources are cleaned up properly.  In this particular example, close() is
+        // invoked when the UI is disconnected from the Service.
+        close();
+        return super.onUnbind(intent);
+    }
+
+    private final IBinder mBinder = new LocalBinder();
+
+    /**
+     * Initializes a reference to the local Bluetooth adapter.
+     *
+     * @return Return true if the initialization is successful.
+     */
+    public boolean initialize() {
+        // For API level 18 and above, get a reference to BluetoothAdapter through
+        // BluetoothManager.
+        if (mBluetoothManager == null) {
+            mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+            if (mBluetoothManager == null) {
+                Log.e(TAG, "Unable to initialize BluetoothManager.");
+                return false;
+            }
+        }
+
+        mBluetoothAdapter = mBluetoothManager.getAdapter();
+        if (mBluetoothAdapter == null) {
+            Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Connects to the GATT server hosted on the Bluetooth LE device.
+     *
+     * @param address The device address of the destination device.
+     *
+     * @return Return true if the connection is initiated successfully. The connection result
+     *         is reported asynchronously through the
+     *         {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
+     *         callback.
+     */
+    public boolean connect(final String address) {
+        if (mBluetoothAdapter == null || address == null) {
+            Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
+            return false;
+        }
+
+        // Previously connected device.  Try to reconnect.
+        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
+                && mBluetoothGatt != null) {
+            Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
+            if (mBluetoothGatt.connect()) {
+                mConnectionState = STATE_CONNECTING;
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
+        if (device == null) {
+            Log.w(TAG, "Device not found.  Unable to connect.");
+            return false;
+        }
+        // We want to directly connect to the device, so we are setting the autoConnect
+        // parameter to false.
+        mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
+        Log.d(TAG, "Trying to create a new connection.");
+        mBluetoothDeviceAddress = address;
+        mConnectionState = STATE_CONNECTING;
+        return true;
+    }
+
+    /**
+     * Disconnects an existing connection or cancel a pending connection. The disconnection result
+     * is reported asynchronously through the
+     * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
+     * callback.
+     */
+    public void disconnect() {
+        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
+            Log.w(TAG, "BluetoothAdapter not initialized");
+            return;
+        }
+        mBluetoothGatt.disconnect();
+    }
+
+    /**
+     * After using a given BLE device, the app must call this method to ensure resources are
+     * released properly.
+     */
+    public void close() {
+        if (mBluetoothGatt == null) {
+            return;
+        }
+        mBluetoothGatt.close();
+        mBluetoothGatt = null;
+    }
+
+    /**
+     * Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported
+     * asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
+     * callback.
+     *
+     * @param characteristic The characteristic to read from.
+     */
+    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
+        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
+            Log.w(TAG, "BluetoothAdapter not initialized");
+            return;
+        }
+        mBluetoothGatt.readCharacteristic(characteristic);
+    }
+
+    /**
+     * Enables or disables notification on a give characteristic.
+     *
+     * @param characteristic Characteristic to act on.
+     * @param enabled If true, enable notification.  False otherwise.
+     */
+    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
+                                              boolean enabled) {
+        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
+            Log.w(TAG, "BluetoothAdapter not initialized");
+            return;
+        }
+        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
+
+        // This is specific to Heart Rate Measurement.
+        if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
+            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
+                    UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
+            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
+            mBluetoothGatt.writeDescriptor(descriptor);
+        }
+    }
+
+    /**
+     * Retrieves a list of supported GATT services on the connected device. This should be
+     * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
+     *
+     * @return A {@code List} of supported services.
+     */
+    public List<BluetoothGattService> getSupportedGattServices() {
+        if (mBluetoothGatt == null) return null;
+
+        return mBluetoothGatt.getServices();
+    }
+}
diff --git a/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceControlActivity.java b/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceControlActivity.java
new file mode 100644
index 0000000..dc2f90b
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceControlActivity.java
@@ -0,0 +1,309 @@
+/*
+ * 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.bluetoothlegatt;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattService;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ExpandableListView;
+import android.widget.SimpleExpandableListAdapter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * For a given BLE device, this Activity provides the user interface to connect, display data,
+ * and display GATT services and characteristics supported by the device.  The Activity
+ * communicates with {@code BluetoothLeService}, which in turn interacts with the
+ * Bluetooth LE API.
+ */
+public class DeviceControlActivity extends Activity {
+    private final static String TAG = DeviceControlActivity.class.getSimpleName();
+
+    public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME";
+    public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";
+
+    private TextView mConnectionState;
+    private TextView mDataField;
+    private String mDeviceName;
+    private String mDeviceAddress;
+    private ExpandableListView mGattServicesList;
+    private BluetoothLeService mBluetoothLeService;
+    private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics =
+            new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
+    private boolean mConnected = false;
+    private BluetoothGattCharacteristic mNotifyCharacteristic;
+
+    private final String LIST_NAME = "NAME";
+    private final String LIST_UUID = "UUID";
+
+    // Code to manage Service lifecycle.
+    private final ServiceConnection mServiceConnection = new ServiceConnection() {
+
+        @Override
+        public void onServiceConnected(ComponentName componentName, IBinder service) {
+            mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
+            if (!mBluetoothLeService.initialize()) {
+                Log.e(TAG, "Unable to initialize Bluetooth");
+                finish();
+            }
+            // Automatically connects to the device upon successful start-up initialization.
+            mBluetoothLeService.connect(mDeviceAddress);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName componentName) {
+            mBluetoothLeService = null;
+        }
+    };
+
+    // Handles various events fired by the Service.
+    // ACTION_GATT_CONNECTED: connected to a GATT server.
+    // ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
+    // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.
+    // ACTION_DATA_AVAILABLE: received data from the device.  This can be a result of read
+    //                        or notification operations.
+    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
+                mConnected = true;
+                updateConnectionState(R.string.connected);
+                invalidateOptionsMenu();
+            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
+                mConnected = false;
+                updateConnectionState(R.string.disconnected);
+                invalidateOptionsMenu();
+                clearUI();
+            } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
+                // Show all the supported services and characteristics on the user interface.
+                displayGattServices(mBluetoothLeService.getSupportedGattServices());
+            } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
+                displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
+            }
+        }
+    };
+
+    // If a given GATT characteristic is selected, check for supported features.  This sample
+    // demonstrates 'Read' and 'Notify' features.  See
+    // http://d.android.com/reference/android/bluetooth/BluetoothGatt.html for the complete
+    // list of supported characteristic features.
+    private final ExpandableListView.OnChildClickListener servicesListClickListner =
+            new ExpandableListView.OnChildClickListener() {
+                @Override
+                public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
+                                            int childPosition, long id) {
+                    if (mGattCharacteristics != null) {
+                        final BluetoothGattCharacteristic characteristic =
+                                mGattCharacteristics.get(groupPosition).get(childPosition);
+                        final int charaProp = characteristic.getProperties();
+                        if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
+                            // If there is an active notification on a characteristic, clear
+                            // it first so it doesn't update the data field on the user interface.
+                            if (mNotifyCharacteristic != null) {
+                                mBluetoothLeService.setCharacteristicNotification(
+                                        mNotifyCharacteristic, false);
+                                mNotifyCharacteristic = null;
+                            }
+                            mBluetoothLeService.readCharacteristic(characteristic);
+                        }
+                        if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
+                            mNotifyCharacteristic = characteristic;
+                            mBluetoothLeService.setCharacteristicNotification(
+                                    characteristic, true);
+                        }
+                        return true;
+                    }
+                    return false;
+                }
+    };
+
+    private void clearUI() {
+        mGattServicesList.setAdapter((SimpleExpandableListAdapter) null);
+        mDataField.setText(R.string.no_data);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.gatt_services_characteristics);
+
+        final Intent intent = getIntent();
+        mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
+        mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
+
+        // Sets up UI references.
+        ((TextView) findViewById(R.id.device_address)).setText(mDeviceAddress);
+        mGattServicesList = (ExpandableListView) findViewById(R.id.gatt_services_list);
+        mGattServicesList.setOnChildClickListener(servicesListClickListner);
+        mConnectionState = (TextView) findViewById(R.id.connection_state);
+        mDataField = (TextView) findViewById(R.id.data_value);
+
+        getActionBar().setTitle(mDeviceName);
+        getActionBar().setDisplayHomeAsUpEnabled(true);
+        Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
+        bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
+        if (mBluetoothLeService != null) {
+            final boolean result = mBluetoothLeService.connect(mDeviceAddress);
+            Log.d(TAG, "Connect request result=" + result);
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        unregisterReceiver(mGattUpdateReceiver);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unbindService(mServiceConnection);
+        mBluetoothLeService = null;
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.gatt_services, menu);
+        if (mConnected) {
+            menu.findItem(R.id.menu_connect).setVisible(false);
+            menu.findItem(R.id.menu_disconnect).setVisible(true);
+        } else {
+            menu.findItem(R.id.menu_connect).setVisible(true);
+            menu.findItem(R.id.menu_disconnect).setVisible(false);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch(item.getItemId()) {
+            case R.id.menu_connect:
+                mBluetoothLeService.connect(mDeviceAddress);
+                return true;
+            case R.id.menu_disconnect:
+                mBluetoothLeService.disconnect();
+                return true;
+            case android.R.id.home:
+                onBackPressed();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void updateConnectionState(final int resourceId) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mConnectionState.setText(resourceId);
+            }
+        });
+    }
+
+    private void displayData(String data) {
+        if (data != null) {
+            mDataField.setText(data);
+        }
+    }
+
+    // Demonstrates how to iterate through the supported GATT Services/Characteristics.
+    // In this sample, we populate the data structure that is bound to the ExpandableListView
+    // on the UI.
+    private void displayGattServices(List<BluetoothGattService> gattServices) {
+        if (gattServices == null) return;
+        String uuid = null;
+        String unknownServiceString = getResources().getString(R.string.unknown_service);
+        String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
+        ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>();
+        ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData
+                = new ArrayList<ArrayList<HashMap<String, String>>>();
+        mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
+
+        // Loops through available GATT Services.
+        for (BluetoothGattService gattService : gattServices) {
+            HashMap<String, String> currentServiceData = new HashMap<String, String>();
+            uuid = gattService.getUuid().toString();
+            currentServiceData.put(
+                    LIST_NAME, SampleGattAttributes.lookup(uuid, unknownServiceString));
+            currentServiceData.put(LIST_UUID, uuid);
+            gattServiceData.add(currentServiceData);
+
+            ArrayList<HashMap<String, String>> gattCharacteristicGroupData =
+                    new ArrayList<HashMap<String, String>>();
+            List<BluetoothGattCharacteristic> gattCharacteristics =
+                    gattService.getCharacteristics();
+            ArrayList<BluetoothGattCharacteristic> charas =
+                    new ArrayList<BluetoothGattCharacteristic>();
+
+            // Loops through available Characteristics.
+            for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
+                charas.add(gattCharacteristic);
+                HashMap<String, String> currentCharaData = new HashMap<String, String>();
+                uuid = gattCharacteristic.getUuid().toString();
+                currentCharaData.put(
+                        LIST_NAME, SampleGattAttributes.lookup(uuid, unknownCharaString));
+                currentCharaData.put(LIST_UUID, uuid);
+                gattCharacteristicGroupData.add(currentCharaData);
+            }
+            mGattCharacteristics.add(charas);
+            gattCharacteristicData.add(gattCharacteristicGroupData);
+        }
+
+        SimpleExpandableListAdapter gattServiceAdapter = new SimpleExpandableListAdapter(
+                this,
+                gattServiceData,
+                android.R.layout.simple_expandable_list_item_2,
+                new String[] {LIST_NAME, LIST_UUID},
+                new int[] { android.R.id.text1, android.R.id.text2 },
+                gattCharacteristicData,
+                android.R.layout.simple_expandable_list_item_2,
+                new String[] {LIST_NAME, LIST_UUID},
+                new int[] { android.R.id.text1, android.R.id.text2 }
+        );
+        mGattServicesList.setAdapter(gattServiceAdapter);
+    }
+
+    private static IntentFilter makeGattUpdateIntentFilter() {
+        final IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
+        intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
+        intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
+        intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
+        return intentFilter;
+    }
+}
diff --git a/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.java b/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.java
new file mode 100644
index 0000000..9b86f7a
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.java
@@ -0,0 +1,268 @@
+/*
+ * 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.bluetoothlegatt;
+
+import android.app.Activity;
+import android.app.ListActivity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+
+/**
+ * Activity for scanning and displaying available Bluetooth LE devices.
+ */
+public class DeviceScanActivity extends ListActivity {
+    private LeDeviceListAdapter mLeDeviceListAdapter;
+    private BluetoothAdapter mBluetoothAdapter;
+    private boolean mScanning;
+    private Handler mHandler;
+
+    private static final int REQUEST_ENABLE_BT = 1;
+    // Stops scanning after 10 seconds.
+    private static final long SCAN_PERIOD = 10000;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getActionBar().setTitle(R.string.title_devices);
+        mHandler = new Handler();
+
+        // Use this check to determine whether BLE is supported on the device.  Then you can
+        // selectively disable BLE-related features.
+        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
+            Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
+            finish();
+        }
+
+        // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to
+        // BluetoothAdapter through BluetoothManager.
+        final BluetoothManager bluetoothManager =
+                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        mBluetoothAdapter = bluetoothManager.getAdapter();
+
+        // Checks if Bluetooth is supported on the device.
+        if (mBluetoothAdapter == null) {
+            Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
+            finish();
+            return;
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        if (!mScanning) {
+            menu.findItem(R.id.menu_stop).setVisible(false);
+            menu.findItem(R.id.menu_scan).setVisible(true);
+            menu.findItem(R.id.menu_refresh).setActionView(null);
+        } else {
+            menu.findItem(R.id.menu_stop).setVisible(true);
+            menu.findItem(R.id.menu_scan).setVisible(false);
+            menu.findItem(R.id.menu_refresh).setActionView(
+                    R.layout.actionbar_indeterminate_progress);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.menu_scan:
+                mLeDeviceListAdapter.clear();
+                scanLeDevice(true);
+                break;
+            case R.id.menu_stop:
+                scanLeDevice(false);
+                break;
+        }
+        return true;
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        // Ensures Bluetooth is enabled on the device.  If Bluetooth is not currently enabled,
+        // fire an intent to display a dialog asking the user to grant permission to enable it.
+        if (!mBluetoothAdapter.isEnabled()) {
+            if (!mBluetoothAdapter.isEnabled()) {
+                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+                startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
+            }
+        }
+
+        // Initializes list view adapter.
+        mLeDeviceListAdapter = new LeDeviceListAdapter();
+        setListAdapter(mLeDeviceListAdapter);
+        scanLeDevice(true);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        // User chose not to enable Bluetooth.
+        if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
+            finish();
+            return;
+        }
+        super.onActivityResult(requestCode, resultCode, data);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        scanLeDevice(false);
+        mLeDeviceListAdapter.clear();
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);
+        if (device == null) return;
+        final Intent intent = new Intent(this, DeviceControlActivity.class);
+        intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, device.getName());
+        intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, device.getAddress());
+        if (mScanning) {
+            mBluetoothAdapter.stopLeScan(mLeScanCallback);
+            mScanning = false;
+        }
+        startActivity(intent);
+    }
+
+    private void scanLeDevice(final boolean enable) {
+        if (enable) {
+            // Stops scanning after a pre-defined scan period.
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    mScanning = false;
+                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
+                    invalidateOptionsMenu();
+                }
+            }, SCAN_PERIOD);
+
+            mScanning = true;
+            mBluetoothAdapter.startLeScan(mLeScanCallback);
+        } else {
+            mScanning = false;
+            mBluetoothAdapter.stopLeScan(mLeScanCallback);
+        }
+        invalidateOptionsMenu();
+    }
+
+    // Adapter for holding devices found through scanning.
+    private class LeDeviceListAdapter extends BaseAdapter {
+        private ArrayList<BluetoothDevice> mLeDevices;
+        private LayoutInflater mInflator;
+
+        public LeDeviceListAdapter() {
+            super();
+            mLeDevices = new ArrayList<BluetoothDevice>();
+            mInflator = DeviceScanActivity.this.getLayoutInflater();
+        }
+
+        public void addDevice(BluetoothDevice device) {
+            if(!mLeDevices.contains(device)) {
+                mLeDevices.add(device);
+            }
+        }
+
+        public BluetoothDevice getDevice(int position) {
+            return mLeDevices.get(position);
+        }
+
+        public void clear() {
+            mLeDevices.clear();
+        }
+
+        @Override
+        public int getCount() {
+            return mLeDevices.size();
+        }
+
+        @Override
+        public Object getItem(int i) {
+            return mLeDevices.get(i);
+        }
+
+        @Override
+        public long getItemId(int i) {
+            return i;
+        }
+
+        @Override
+        public View getView(int i, View view, ViewGroup viewGroup) {
+            ViewHolder viewHolder;
+            // General ListView optimization code.
+            if (view == null) {
+                view = mInflator.inflate(R.layout.listitem_device, null);
+                viewHolder = new ViewHolder();
+                viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
+                viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
+                view.setTag(viewHolder);
+            } else {
+                viewHolder = (ViewHolder) view.getTag();
+            }
+
+            BluetoothDevice device = mLeDevices.get(i);
+            final String deviceName = device.getName();
+            if (deviceName != null && deviceName.length() > 0)
+                viewHolder.deviceName.setText(deviceName);
+            else
+                viewHolder.deviceName.setText(R.string.unknown_device);
+            viewHolder.deviceAddress.setText(device.getAddress());
+
+            return view;
+        }
+    }
+
+    // Device scan callback.
+    private BluetoothAdapter.LeScanCallback mLeScanCallback =
+            new BluetoothAdapter.LeScanCallback() {
+
+        @Override
+        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mLeDeviceListAdapter.addDevice(device);
+                    mLeDeviceListAdapter.notifyDataSetChanged();
+                }
+            });
+        }
+    };
+
+    static class ViewHolder {
+        TextView deviceName;
+        TextView deviceAddress;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/SampleGattAttributes.java b/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/SampleGattAttributes.java
new file mode 100644
index 0000000..e8db74c
--- /dev/null
+++ b/samples/browseable/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/SampleGattAttributes.java
@@ -0,0 +1,42 @@
+/*
+ * 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.bluetoothlegatt;
+
+import java.util.HashMap;
+
+/**
+ * This class includes a small subset of standard GATT attributes for demonstration purposes.
+ */
+public class SampleGattAttributes {
+    private static HashMap<String, String> attributes = new HashMap();
+    public static String HEART_RATE_MEASUREMENT = "00002a37-0000-1000-8000-00805f9b34fb";
+    public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
+
+    static {
+        // Sample Services.
+        attributes.put("0000180d-0000-1000-8000-00805f9b34fb", "Heart Rate Service");
+        attributes.put("0000180a-0000-1000-8000-00805f9b34fb", "Device Information Service");
+        // Sample Characteristics.
+        attributes.put(HEART_RATE_MEASUREMENT, "Heart Rate Measurement");
+        attributes.put("00002a29-0000-1000-8000-00805f9b34fb", "Manufacturer Name String");
+    }
+
+    public static String lookup(String uuid, String defaultName) {
+        String name = attributes.get(uuid);
+        return name == null ? defaultName : name;
+    }
+}
diff --git a/samples/browseable/BorderlessButtons/AndroidManifest.xml b/samples/browseable/BorderlessButtons/AndroidManifest.xml
new file mode 100644
index 0000000..34b2898
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.borderlessbuttons"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!--
+      This sample requires API 11 for use of theme attributes such as ?android:buttonBarStyle
+      and ?android:borderlessButtonStyle, as well as LinearLayout's android:showDividers attribute.
+      A similar effect can be achieved by setting a clickable view's background to
+      ?android:selectableItemBackground.
+
+      This sample requires API 14 for use of theme attributes such as
+      ?android:listPreferredItemPaddingLeft.
+    -->
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" />
+
+    <application android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/Theme.Sample"
+        android:allowBackup="true">
+
+        <activity android:name=".MainActivity"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/samples/browseable/BorderlessButtons/_index.jd b/samples/browseable/BorderlessButtons/_index.jd
new file mode 100644
index 0000000..0d43c98
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/_index.jd
@@ -0,0 +1,9 @@
+
+
+
+page.tags="BorderlessButtons"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to apply borderless buttons, bottom button bars
+(OK and Cancel), and dividers to establish visual structure.</p>
diff --git a/samples/browseable/BorderlessButtons/res/drawable-hdpi/ic_action_delete.png b/samples/browseable/BorderlessButtons/res/drawable-hdpi/ic_action_delete.png
new file mode 100644
index 0000000..e9ce89e
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/drawable-hdpi/ic_action_delete.png
Binary files differ
diff --git a/samples/browseable/BorderlessButtons/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BorderlessButtons/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BorderlessButtons/res/drawable-hdpi/tile.9.png b/samples/browseable/BorderlessButtons/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BorderlessButtons/res/drawable-mdpi/ic_action_delete.png b/samples/browseable/BorderlessButtons/res/drawable-mdpi/ic_action_delete.png
new file mode 100644
index 0000000..cedb108
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/drawable-mdpi/ic_action_delete.png
Binary files differ
diff --git a/samples/browseable/BorderlessButtons/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BorderlessButtons/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BorderlessButtons/res/drawable-xhdpi/ic_action_delete.png b/samples/browseable/BorderlessButtons/res/drawable-xhdpi/ic_action_delete.png
new file mode 100644
index 0000000..98c73da
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/drawable-xhdpi/ic_action_delete.png
Binary files differ
diff --git a/samples/browseable/BorderlessButtons/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BorderlessButtons/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BorderlessButtons/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BorderlessButtons/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BorderlessButtons/res/layout/activity_main.xml b/samples/browseable/BorderlessButtons/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BorderlessButtons/res/layout/list_item.xml b/samples/browseable/BorderlessButtons/res/layout/list_item.xml
new file mode 100644
index 0000000..1966be9
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/layout/list_item.xml
@@ -0,0 +1,87 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<!--
+    For list items that contain secondary actions (in this case, 'delete'),
+    it's important to use dividers to distinguish the primary touch target from
+    the secondary action. This is done using android:showDividers and its
+    related attributes.
+
+    The android:dividerPadding attribute insets the divider line by the given
+    amount on each side (in this case, top and bottom). Divider padding helps
+    establish visual hierarchy when several dividers are used in a screen. In
+    this case, the padding helps separate this vertical divider from horizontal
+    list item separators in the main ListView, and establishes a stronger
+    relationship between the delete action and the primary target to its left.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:listPreferredItemHeight"
+    android:divider="?android:dividerVertical"
+    android:dividerPadding="8dp"
+    android:showDividers="middle">
+
+    <!--
+        Any view or view group can become interactive by simply setting the
+        android:clickable and android:focusable attributes to true.
+
+        When doing this, make sure to provide adequate touch feedback by also
+        setting the view background to ?android:selectableItemBackground. When
+        using the Holo theme, this drawable is transparent by default, but
+        changes to a translucent color overlay when the view is pressed or
+        focused.
+    -->
+    <LinearLayout android:id="@+id/primary_target"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingLeft="?android:listPreferredItemPaddingLeft"
+        android:paddingRight="?android:listPreferredItemPaddingRight"
+        android:clickable="true"
+        android:focusable="true"
+        android:gravity="center_vertical"
+        android:background="?android:selectableItemBackground">
+
+        <TextView style="?android:textAppearanceListItemSmall"
+            android:id="@android:id/text1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/dummy_title" />
+
+        <TextView style="?android:textAppearanceSmall"
+            android:id="@android:id/text2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/dummy_subtitle" />
+
+    </LinearLayout>
+
+    <!--
+        When using the Holo theme, setting a Button or ImageButton to
+        ?android:borderlessButtonStyle removes its border and sets the
+        background to ?android:selectableItemBackground, as described above.
+    -->
+    <ImageButton android:id="@+id/secondary_action"
+        style="?android:borderlessButtonStyle"
+        android:layout_width="@dimen/standard_touch_target_size"
+        android:layout_height="match_parent"
+        android:src="@drawable/ic_action_delete"
+        android:contentDescription="@string/delete_content_description" />
+
+</LinearLayout>
diff --git a/samples/browseable/BorderlessButtons/res/layout/sample_main.xml b/samples/browseable/BorderlessButtons/res/layout/sample_main.xml
new file mode 100755
index 0000000..eacbf4b
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/layout/sample_main.xml
@@ -0,0 +1,87 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<!--
+    The top-level LinearLayout uses a horizontal divider to visually
+    distinguish the top description box, list, and bottom button bar.
+
+    android:showDividers="middle" draws dividers between each child view and
+    android:divider="?android:dividerHorizontal" indicates that the standard
+    horizontal system divider (set in the activity's theme) should be used to
+    draw the divider.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:divider="?android:dividerHorizontal"
+    android:showDividers="middle">
+
+    <TextView style="@style/Widget.DescriptionBar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/intro_message" />
+
+    <!--
+        Remember to use padding on your ListViews to adhere to the standard
+        metrics described in the Android Design guidelines. When doing so,
+        you should set the android:scrollbarStyle such that the scrollbar
+        doesn'isn't inset.
+    -->
+    <ListView android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:paddingLeft="@dimen/page_margin"
+        android:paddingRight="@dimen/page_margin"
+        android:scrollbarStyle="outsideOverlay" />
+
+    <!--
+        When using the Holo theme (setting your activity or app theme to
+        Theme.Holo or one of its descendants), a LinearLayout with the
+        ?android:buttonBarStyle will draw dividers (with padding) between
+        buttons.
+    -->
+    <LinearLayout style="?android:buttonBarStyle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <!--
+            Make sure to apply the ?android:buttonBarStyle to each button
+            in the button bar.
+
+            In the Holo theme, this style is very similar to
+            ?android:borderlessButtonStyle, but designed for use specifically
+            in horizontal button bars.
+        -->
+        <Button style="?android:buttonBarButtonStyle"
+            android:id="@+id/cancel_button"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/cancel" />
+
+        <Button style="?android:buttonBarButtonStyle"
+            android:id="@+id/ok_button"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/ok" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/samples/browseable/BorderlessButtons/res/menu/main.xml b/samples/browseable/BorderlessButtons/res/menu/main.xml
new file mode 100644
index 0000000..54f0d3f
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/menu/main.xml
@@ -0,0 +1,22 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/docs_link"
+        android:title="@string/docs_link_title"
+        android:showAsAction="never" />
+</menu>
diff --git a/samples/browseable/BorderlessButtons/res/values-sw600dp/dimens.xml b/samples/browseable/BorderlessButtons/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BorderlessButtons/res/values-sw600dp/styles.xml b/samples/browseable/BorderlessButtons/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BorderlessButtons/res/values/base-strings.xml b/samples/browseable/BorderlessButtons/res/values/base-strings.xml
new file mode 100644
index 0000000..efbd14d
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">BorderlessButtons</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+                This sample demonstrates the use of borderless buttons, bottom button bars
+                (OK and Cancel) and dividers to establish visual structure.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BorderlessButtons/res/values/dimens.xml b/samples/browseable/BorderlessButtons/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BorderlessButtons/res/values/strings.xml b/samples/browseable/BorderlessButtons/res/values/strings.xml
new file mode 100755
index 0000000..fb141d2
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/values/strings.xml
@@ -0,0 +1,30 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="cancel">Cancel</string>
+    <string name="ok">OK</string>
+
+    <string name="dummy_title">Dummy title</string>
+    <string name="dummy_subtitle">Dummy subtitle</string>
+
+    <string name="delete_content_description">Delete</string>
+
+    <string name="touched_primary_message">Touched primary list item target.</string>
+    <string name="touched_secondary_message">Touched secondary list item target (delete).</string>
+
+    <string name="docs_link_title">Design docs: borderless buttons</string>
+</resources>
diff --git a/samples/browseable/BorderlessButtons/res/values/styles.xml b/samples/browseable/BorderlessButtons/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BorderlessButtons/src/com.example.android.borderlessbuttons/MainActivity.java b/samples/browseable/BorderlessButtons/src/com.example.android.borderlessbuttons/MainActivity.java
new file mode 100755
index 0000000..04105f4
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/src/com.example.android.borderlessbuttons/MainActivity.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.borderlessbuttons;
+
+import android.app.ListActivity;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Toast;
+
+/**
+ * This activity demonstrates the <b>borderless button</b> styling from the Holo visual language.
+ * The most interesting bits in this sample are in the layout files (res/layout/).
+ * <p>
+ * See <a href="http://developer.android.com/design/building-blocks/buttons.html#borderless">
+ * borderless buttons</a> at the Android Design guide for a discussion of this visual style.
+ */
+public class MainActivity extends ListActivity {
+    private static final Uri DOCS_URI = Uri.parse(
+            "http://developer.android.com/design/building-blocks/buttons.html#borderless");
+
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+
+        setListAdapter(mListAdapter);
+
+        findViewById(R.id.cancel_button).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                finish();
+            }
+        });
+
+        findViewById(R.id.ok_button).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                finish();
+            }
+        });
+    }
+
+    private BaseAdapter mListAdapter = new BaseAdapter() {
+        @Override
+        public int getCount() {
+            return 10;
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return null;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position + 1;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup container) {
+            if (convertView == null) {
+                convertView = getLayoutInflater().inflate(R.layout.list_item, container, false);
+            }
+
+            // Because the list item contains multiple touch targets, you should not override
+            // onListItemClick. Instead, set a click listener for each target individually.
+
+            convertView.findViewById(R.id.primary_target).setOnClickListener(
+                    new View.OnClickListener() {
+                        @Override
+                        public void onClick(View view) {
+                            Toast.makeText(MainActivity.this,
+                                    R.string.touched_primary_message,
+                                    Toast.LENGTH_SHORT).show();
+                        }
+                    });
+
+            convertView.findViewById(R.id.secondary_action).setOnClickListener(
+                    new View.OnClickListener() {
+                        @Override
+                        public void onClick(View view) {
+                            Toast.makeText(MainActivity.this,
+                                    R.string.touched_secondary_message,
+                                    Toast.LENGTH_SHORT).show();
+                        }
+                    });
+            return convertView;
+        }
+    };
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.docs_link:
+                try {
+                    startActivity(new Intent(Intent.ACTION_VIEW, DOCS_URI));
+                } catch (ActivityNotFoundException ignored) {
+                }
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+}
diff --git a/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/Log.java b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogView.java b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/CustomChoiceList/AndroidManifest.xml b/samples/browseable/CustomChoiceList/AndroidManifest.xml
new file mode 100644
index 0000000..8c194f5
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.customchoicelist"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="17" />
+
+    <application android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/Theme.Sample"
+        android:allowBackup="true">
+
+        <activity android:name=".MainActivity"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/samples/browseable/CustomChoiceList/_index.jd b/samples/browseable/CustomChoiceList/_index.jd
new file mode 100644
index 0000000..67a23cc
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/_index.jd
@@ -0,0 +1,9 @@
+
+
+
+page.tags="CustomChoiceList"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to implement a custom single-choice or
+multi-choice {@link android.widget.ListView} user interface.</p>
diff --git a/samples/browseable/CustomChoiceList/res/color/hideable_text_color.xml b/samples/browseable/CustomChoiceList/res/color/hideable_text_color.xml
new file mode 100644
index 0000000..c48bb38
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/color/hideable_text_color.xml
@@ -0,0 +1,23 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<!--
+    This color state list changes from gray to blue depending on its state (checked or not checked).
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_checked="false" android:color="#6000" />
+    <item android:color="#09c" />
+</selector>
diff --git a/samples/browseable/CustomChoiceList/res/drawable-hdpi/ic_launcher.png b/samples/browseable/CustomChoiceList/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..230b1c3
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CustomChoiceList/res/drawable-hdpi/tile.9.png b/samples/browseable/CustomChoiceList/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/CustomChoiceList/res/drawable-mdpi/ic_launcher.png b/samples/browseable/CustomChoiceList/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..dc56d26
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_checked.png b/samples/browseable/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_checked.png
new file mode 100644
index 0000000..9346d8a
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_checked.png
Binary files differ
diff --git a/samples/browseable/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_unchecked.png b/samples/browseable/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_unchecked.png
new file mode 100644
index 0000000..d45b374
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_unchecked.png
Binary files differ
diff --git a/samples/browseable/CustomChoiceList/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/CustomChoiceList/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..a71e6ca
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CustomChoiceList/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/CustomChoiceList/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..051f1e3
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CustomChoiceList/res/drawable/ic_hideable_item.xml b/samples/browseable/CustomChoiceList/res/drawable/ic_hideable_item.xml
new file mode 100644
index 0000000..bc5ea54
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/drawable/ic_hideable_item.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+  
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<!--
+    This state list drawable changes from an outline of an eye (ic_hideable_item_unchecked) to a
+    blue eye with iris (ic_hideable_item_checked) depending on its state (checked or not checked).
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_checked="false" android:drawable="@drawable/ic_hideable_item_unchecked" />
+    <item android:drawable="@drawable/ic_hideable_item_checked" />
+</selector>
diff --git a/samples/browseable/CustomChoiceList/res/layout/activity_main.xml b/samples/browseable/CustomChoiceList/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/CustomChoiceList/res/layout/list_item.xml b/samples/browseable/CustomChoiceList/res/layout/list_item.xml
new file mode 100644
index 0000000..09a17ed
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/layout/list_item.xml
@@ -0,0 +1,62 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<!--
+    The ListView from sample_main.xml has a choiceMode set, meaning that when a user
+    selects a list item, the ListView will set the state for that item's root view
+    (this CheckableLinearLayout) to "checked". Note that this requires that the root view
+    implements the Checkable interface. Once the root view is checked, any children that
+    have the duplicateParentState attribute set will inherit this "checked" state.
+-->
+<com.example.android.customchoicelist.CheckableLinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingLeft="8dp"
+    android:paddingRight="8dp"
+    android:minHeight="?android:listPreferredItemHeight"
+    android:gravity="center_vertical">
+
+    <!--
+        The duplicateParentState attribute on this TextView, along with the color state list
+        used in the textColor attribute causes its text color to change when its parent
+        is checked or unchecked.
+    -->
+    <TextView android:id="@android:id/text1"
+        android:duplicateParentState="true"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:textAppearanceMedium"
+        android:textColor="@color/hideable_text_color" />
+
+    <!--
+        The duplicateParentState attribute on this ImageView, along with the state list
+        drawable in the src attribute causes its image to change when its parent
+        is checked or unchecked.
+
+        To use the standard radio or checkmark image, set the src to
+        ?android:listChoiceIndicatorMultiple or ?android:listChoiceIndicatorSingle. These
+        are system theme attributes that reference a state list drawable.
+    -->
+    <ImageView android:src="@drawable/ic_hideable_item"
+        android:duplicateParentState="true"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="16dp" />
+
+</com.example.android.customchoicelist.CheckableLinearLayout>
diff --git a/samples/browseable/CustomChoiceList/res/layout/sample_main.xml b/samples/browseable/CustomChoiceList/res/layout/sample_main.xml
new file mode 100755
index 0000000..17a69e4
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/layout/sample_main.xml
@@ -0,0 +1,54 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:showDividers="middle"
+    android:divider="?android:dividerHorizontal">
+
+    <TextView style="@style/Widget.DescriptionBar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/intro_message" />
+
+    <!--
+        When a ListView has a choiceMode set, it will allow users to "choose"
+        one or more items. The framework provides default list item layouts
+        that show standard radio buttons or check boxes next to a
+        single line of text:
+
+        android.R.layout.simple_list_item_single_choice and
+        android.R.layout.simple_list_item_multiple_choice.
+
+        In some cases, you may want to customize this layout. When doing so,
+        the root view must implement the Checkable interface.
+
+        Lastly, remember to use padding on your ListViews to adhere to the standard
+        metrics described in the Android Design guidelines. When doing so,
+        you should set the android:scrollbarStyle such that the scrollbar
+        doesn'isn't inset.
+    -->
+    <ListView android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:paddingLeft="@dimen/page_margin"
+        android:paddingRight="@dimen/page_margin"
+        android:scrollbarStyle="outsideOverlay"
+        android:choiceMode="multipleChoice" />
+</LinearLayout>
diff --git a/samples/browseable/CustomChoiceList/res/values-sw600dp/dimens.xml b/samples/browseable/CustomChoiceList/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/CustomChoiceList/res/values-sw600dp/styles.xml b/samples/browseable/CustomChoiceList/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/CustomChoiceList/res/values/base-strings.xml b/samples/browseable/CustomChoiceList/res/values/base-strings.xml
new file mode 100644
index 0000000..e2890c4
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">CustomChoiceList</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+                This sample demonstrates how to create custom checkable layouts, for use with ListView\'s choiceMode
+                attribute.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/CustomChoiceList/res/values/dimens.xml b/samples/browseable/CustomChoiceList/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/CustomChoiceList/res/values/styles.xml b/samples/browseable/CustomChoiceList/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/Log.java b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogNode.java b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogView.java b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/CheckableLinearLayout.java b/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/CheckableLinearLayout.java
new file mode 100644
index 0000000..a30eb2a
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/CheckableLinearLayout.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.customchoicelist;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.Checkable;
+import android.widget.LinearLayout;
+
+/**
+ * This is a simple wrapper for {@link android.widget.LinearLayout} that implements the {@link android.widget.Checkable}
+ * interface by keeping an internal 'checked' state flag.
+ * <p>
+ * This can be used as the root view for a custom list item layout for
+ * {@link android.widget.AbsListView} elements with a
+ * {@link android.widget.AbsListView#setChoiceMode(int) choiceMode} set.
+ */
+public class CheckableLinearLayout extends LinearLayout implements Checkable {
+    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
+
+    private boolean mChecked = false;
+
+    public CheckableLinearLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public boolean isChecked() {
+        return mChecked;
+    }
+
+    public void setChecked(boolean b) {
+        if (b != mChecked) {
+            mChecked = b;
+            refreshDrawableState();
+        }
+    }
+
+    public void toggle() {
+        setChecked(!mChecked);
+    }
+
+    @Override
+    public int[] onCreateDrawableState(int extraSpace) {
+        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+        if (isChecked()) {
+            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+        }
+        return drawableState;
+    }
+}
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/Cheeses.java b/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/Cheeses.java
new file mode 100644
index 0000000..871ae29
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/Cheeses.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.customchoicelist;
+
+/**
+ * Dummy data.
+ */
+public class Cheeses {
+    public static final String[] CHEESES = {
+            "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
+            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
+            "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
+            "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
+            "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
+            "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
+            "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
+            "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
+            "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
+            "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
+            "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
+            "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
+            "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
+            "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
+            "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
+            "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
+            "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
+            "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
+            "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
+            "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
+            "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
+            "Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
+            "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
+            "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
+            "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
+            "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
+            "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
+            "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
+            "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
+            "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
+            "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
+            "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
+            "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
+            "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
+            "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
+            "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
+            "Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
+            "Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
+            "Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
+            "Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
+            "Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
+            "Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
+            "Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
+            "Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
+            "Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
+            "Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
+            "Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
+            "Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
+            "Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
+            "Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
+            "Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
+            "Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
+            "Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
+            "Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
+            "Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
+            "Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
+            "Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
+            "Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
+            "Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
+            "Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
+            "Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
+            "Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
+            "Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
+            "Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
+            "Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
+            "Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
+            "Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
+            "La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
+            "Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
+            "Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
+            "Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
+            "Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
+            "Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
+            "Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
+            "Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
+            "Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
+            "Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
+            "Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
+            "Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
+            "Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
+            "Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
+            "Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
+            "Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
+            "Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
+            "Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
+            "Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
+            "Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
+            "Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
+            "Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
+            "Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
+            "Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
+            "Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
+            "Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
+            "Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
+            "Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
+            "Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
+            "Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
+            "Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
+            "Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
+            "Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
+            "Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
+            "Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
+            "Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
+            "Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
+            "Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
+            "Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
+            "Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
+            "Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
+            "Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
+            "Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
+            "Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
+            "Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
+            "Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
+            "Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
+            "Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
+            "Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
+            "Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
+            "Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
+            "Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
+            "Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
+            "Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
+            "Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
+            "Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
+            "Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
+            "Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
+            "Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
+            "Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
+            "Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
+            "Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
+            "Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"
+    };
+}
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/MainActivity.java b/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/MainActivity.java
new file mode 100755
index 0000000..e4e89f2
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/MainActivity.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.customchoicelist;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+/**
+ * This sample demonstrates how to create custom single- or multi-choice
+ * {@link android.widget.ListView} UIs. The most interesting bits are in
+ * the <code>res/layout/</code> directory of this sample.
+ */
+public class MainActivity extends ListActivity {
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+        setListAdapter(new MyAdapter());
+    }
+
+    /**
+     * A simple array adapter that creates a list of cheeses.
+     */
+    private class MyAdapter extends BaseAdapter {
+        @Override
+        public int getCount() {
+            return Cheeses.CHEESES.length;
+        }
+
+        @Override
+        public String getItem(int position) {
+            return Cheeses.CHEESES[position];
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return Cheeses.CHEESES[position].hashCode();
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup container) {
+            if (convertView == null) {
+                convertView = getLayoutInflater().inflate(R.layout.list_item, container, false);
+            }
+
+            ((TextView) convertView.findViewById(android.R.id.text1))
+                    .setText(getItem(position));
+            return convertView;
+        }
+    }
+}
diff --git a/samples/browseable/CustomNotifications/AndroidManifest.xml b/samples/browseable/CustomNotifications/AndroidManifest.xml
new file mode 100644
index 0000000..b20a411
--- /dev/null
+++ b/samples/browseable/CustomNotifications/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.customnotifications"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="4"
+        android:targetSdkVersion="18" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="com.example.android.customnotifications.MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/CustomNotifications/_index.jd b/samples/browseable/CustomNotifications/_index.jd
new file mode 100644
index 0000000..ab3499c
--- /dev/null
+++ b/samples/browseable/CustomNotifications/_index.jd
@@ -0,0 +1,9 @@
+
+
+
+page.tags="CustomNotifications"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to implement expanded notifications that
+display custom views.</p>
diff --git a/samples/browseable/CustomNotifications/res/drawable-hdpi-v11/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-hdpi-v11/ic_stat_custom.png
new file mode 100644
index 0000000..db182ce
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-hdpi-v11/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-hdpi-v9/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-hdpi-v9/ic_stat_custom.png
new file mode 100644
index 0000000..c35f570
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-hdpi-v9/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-hdpi/ic_launcher.png b/samples/browseable/CustomNotifications/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..155ac98
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-hdpi/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-hdpi/ic_stat_custom.png
new file mode 100644
index 0000000..b0434fd
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-hdpi/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-hdpi/tile.9.png b/samples/browseable/CustomNotifications/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-ldpi-v11/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-ldpi-v11/ic_stat_custom.png
new file mode 100644
index 0000000..50e1b32
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-ldpi-v11/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-ldpi-v9/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-ldpi-v9/ic_stat_custom.png
new file mode 100644
index 0000000..d4de32a
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-ldpi-v9/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-mdpi-v11/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-mdpi-v11/ic_stat_custom.png
new file mode 100644
index 0000000..a46f47f
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-mdpi-v11/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-mdpi-v9/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-mdpi-v9/ic_stat_custom.png
new file mode 100644
index 0000000..2896b63
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-mdpi-v9/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-mdpi/ic_launcher.png b/samples/browseable/CustomNotifications/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..6e38dc6
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-mdpi/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-mdpi/ic_stat_custom.png
new file mode 100644
index 0000000..304f7e9
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-mdpi/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-xhdpi-v11/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-xhdpi-v11/ic_stat_custom.png
new file mode 100644
index 0000000..52f7df8
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-xhdpi-v11/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-xhdpi-v9/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-xhdpi-v9/ic_stat_custom.png
new file mode 100644
index 0000000..5d2617e
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-xhdpi-v9/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/CustomNotifications/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..638fc67
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-xhdpi/ic_stat_custom.png b/samples/browseable/CustomNotifications/res/drawable-xhdpi/ic_stat_custom.png
new file mode 100644
index 0000000..79c30a8
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-xhdpi/ic_stat_custom.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-xhdpi/robot.png b/samples/browseable/CustomNotifications/res/drawable-xhdpi/robot.png
new file mode 100644
index 0000000..e21ee75
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-xhdpi/robot.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-xhdpi/robot_expanded.png b/samples/browseable/CustomNotifications/res/drawable-xhdpi/robot_expanded.png
new file mode 100644
index 0000000..f9469d4
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-xhdpi/robot_expanded.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/CustomNotifications/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..9a9a60c
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CustomNotifications/res/layout/activity_main.xml b/samples/browseable/CustomNotifications/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/CustomNotifications/res/layout/notification.xml b/samples/browseable/CustomNotifications/res/layout/notification.xml
new file mode 100644
index 0000000..9d977d3
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/layout/notification.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+* Copyright (C) 2013 The Android Open Source Project
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*       http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+-->
+
+<!-- Layout for the collapsed notification. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:gravity="center_horizontal">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="@style/NotificationContent"
+        android:id="@+id/textView"
+        android:gravity="center" />
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/imageView"
+        android:src="@drawable/robot"
+        android:contentDescription="@string/collapsed_image" />
+
+
+</LinearLayout>
diff --git a/samples/browseable/CustomNotifications/res/layout/notification_expanded.xml b/samples/browseable/CustomNotifications/res/layout/notification_expanded.xml
new file mode 100644
index 0000000..9d5a784
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/layout/notification_expanded.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+* Copyright (C) 2013 The Android Open Source Project
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*       http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+-->
+
+<!-- Layout for the expanded notification. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:gravity="right|top">
+
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/NotificationContent"
+            android:text="@string/expanded"
+            android:layout_gravity="center_vertical"
+            android:layout_alignParentTop="false"
+            android:layout_alignParentLeft="true"
+            android:layout_toLeftOf="@+id/imageView"
+            android:gravity="center"
+            android:layout_centerVertical="true" />
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/robot_expanded"
+            android:layout_gravity="right|top"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentRight="true"
+            android:id="@+id/imageView"
+            android:contentDescription="@string/expanded_image" />
+    </RelativeLayout>
+
+
+</LinearLayout>
diff --git a/samples/browseable/CustomNotifications/res/layout/sample_main.xml b/samples/browseable/CustomNotifications/res/layout/sample_main.xml
new file mode 100644
index 0000000..d67477d
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/layout/sample_main.xml
@@ -0,0 +1,43 @@
+<!--
+  * 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.
+  -->
+
+<!-- Layout for MainActivity.
+ Includes an introductory text and a button to show the notification. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:orientation="vertical"
+    tools:context=".MainActivity"
+    android:gravity="center_horizontal">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/intro_text" />
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/show_notification"
+        android:id="@+id/button"
+        android:onClick="showNotificationClicked" />
+
+</LinearLayout>
diff --git a/samples/browseable/CustomNotifications/res/values-sw600dp/dimens.xml b/samples/browseable/CustomNotifications/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/CustomNotifications/res/values-sw600dp/styles.xml b/samples/browseable/CustomNotifications/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/CustomNotifications/res/values-sw720dp-land/dimens.xml b/samples/browseable/CustomNotifications/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..901314a
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,20 @@
+<!--
+  * Copyright (C) 2013 The Android Open Source Project
+  * Licensed under the Apache License, Version 2.0 (the "License");
+  * you may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at
+  *
+  *       http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  -->
+
+<resources>
+    <!-- Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. -->
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+</resources>
diff --git a/samples/browseable/CustomNotifications/res/values-v9/styles.xml b/samples/browseable/CustomNotifications/res/values-v9/styles.xml
new file mode 100644
index 0000000..85010a5
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/values-v9/styles.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <style name="NotificationContent" parent="@android:style/TextAppearance.StatusBar.EventContent">
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/CustomNotifications/res/values/base-strings.xml b/samples/browseable/CustomNotifications/res/values/base-strings.xml
new file mode 100644
index 0000000..7ddbc2d
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/values/base-strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">CustomNotifications</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates notifications with custom content views.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/CustomNotifications/res/values/dimens.xml b/samples/browseable/CustomNotifications/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/CustomNotifications/res/values/strings.xml b/samples/browseable/CustomNotifications/res/values/strings.xml
new file mode 100644
index 0000000..a766441
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/values/strings.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  * Copyright (C) 2013 The Android Open Source Project
+  * Licensed under the Apache License, Version 2.0 (the "License");
+  * you may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at
+  *
+  *       http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  -->
+
+<resources>
+
+    <string name="expanded">I\'m the expanded notification.\nCollapse me!</string>
+    <string name="collapsed">I\'m the collapsed notification.\nCreated at: %s</string>
+    <string name="show_notification">Show Notification</string>
+    <string name="custom_notification">I\'m a custom notification.</string>
+
+    <string name="intro_text">This sample demonstrates how a notification is created using the
+        <b>NotificationCompatBuilder</b>
+        with a custom content view. The layout of the notification is defined as a
+        layout resource and inflated as a <b>RemoteViews</b> object.
+        \n\nOn API level 16 and above, a different layout is inflated and set as
+        the <i>big content view</i>, which is used when the notification is expanded.
+        \n\n<b>Use the button below to create the notification.
+        \n\nIf your device is running Jelly Bean or above, try expanding or collapsing
+        the notification to see the different layouts.</b>
+    </string>
+    <string name="collapsed_image">A single Android robot waving. Symbolises a collapsed
+        notification.
+    </string>
+    <string name="expanded_image">Two Androids on top of each other. Symbolises an expanded
+        notification.
+    </string>
+
+</resources>
diff --git a/samples/browseable/CustomNotifications/res/values/styles.xml b/samples/browseable/CustomNotifications/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/CustomNotifications/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/CustomNotifications/src/com.example.android.customnotifications/MainActivity.java b/samples/browseable/CustomNotifications/src/com.example.android.customnotifications/MainActivity.java
new file mode 100644
index 0000000..57a4315
--- /dev/null
+++ b/samples/browseable/CustomNotifications/src/com.example.android.customnotifications/MainActivity.java
@@ -0,0 +1,125 @@
+/*
+ * 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.customnotifications;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.app.NotificationCompat;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+public class MainActivity extends Activity {
+    /**
+     * This sample demonstrates notifications with custom content views.
+     *
+     * <p>On API level 16 and above a big content view is also defined that is used for the
+     * 'expanded' notification. The notification is created by the NotificationCompat.Builder.
+     * The expanded content view is set directly on the {@link android.app.Notification} once it has been build.
+     * (See {@link android.app.Notification#bigContentView}.) </p>
+     *
+     * <p>The content views are inflated as {@link android.widget.RemoteViews} directly from their XML layout
+     * definitions using {@link android.widget.RemoteViews#RemoteViews(String, int)}.</p>
+     */
+    private void createNotification() {
+        // BEGIN_INCLUDE(notificationCompat)
+        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
+        // END_INCLUDE(notificationCompat)
+
+        // BEGIN_INCLUDE(intent)
+        //Create Intent to launch this Activity again if the notification is clicked.
+        Intent i = new Intent(this, MainActivity.class);
+        i.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+        PendingIntent intent = PendingIntent.getActivity(this, 0, i,
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        builder.setContentIntent(intent);
+        // END_INCLUDE(intent)
+
+        // BEGIN_INCLUDE(ticker)
+        // Sets the ticker text
+        builder.setTicker(getResources().getString(R.string.custom_notification));
+
+        // Sets the small icon for the ticker
+        builder.setSmallIcon(R.drawable.ic_stat_custom);
+        // END_INCLUDE(ticker)
+
+        // BEGIN_INCLUDE(buildNotification)
+        // Cancel the notification when clicked
+        builder.setAutoCancel(true);
+
+        // Build the notification
+        Notification notification = builder.build();
+        // END_INCLUDE(buildNotification)
+
+        // BEGIN_INCLUDE(customLayout)
+        // Inflate the notification layout as RemoteViews
+        RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.notification);
+
+        // Set text on a TextView in the RemoteViews programmatically.
+        final String time = DateFormat.getTimeInstance().format(new Date()).toString();
+        final String text = getResources().getString(R.string.collapsed, time);
+        contentView.setTextViewText(R.id.textView, text);
+
+        /* Workaround: Need to set the content view here directly on the notification.
+         * NotificationCompatBuilder contains a bug that prevents this from working on platform
+         * versions HoneyComb.
+         * See https://code.google.com/p/android/issues/detail?id=30495
+         */
+        notification.contentView = contentView;
+
+        // Add a big content view to the notification if supported.
+        // Support for expanded notifications was added in API level 16.
+        // (The normal contentView is shown when the notification is collapsed, when expanded the
+        // big content view set here is displayed.)
+        if (Build.VERSION.SDK_INT >= 16) {
+            // Inflate and set the layout for the expanded notification view
+            RemoteViews expandedView =
+                    new RemoteViews(getPackageName(), R.layout.notification_expanded);
+            notification.bigContentView = expandedView;
+        }
+        // END_INCLUDE(customLayout)
+
+        // START_INCLUDE(notify)
+        // Use the NotificationManager to show the notification
+        NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+        nm.notify(0, notification);
+        // END_INCLUDE(notify)
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+    }
+
+    /**
+     * Create and show a notification with a custom layout.
+     * This callback is defined through the 'onClick' attribute of the
+     * 'Show Notification' button in the XML layout.
+     *
+     * @param v
+     */
+    public void showNotificationClicked(View v) {
+        createNotification();
+    }
+}
diff --git a/samples/browseable/DoneBar/AndroidManifest.xml b/samples/browseable/DoneBar/AndroidManifest.xml
new file mode 100644
index 0000000..4731114
--- /dev/null
+++ b/samples/browseable/DoneBar/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.donebar"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" />
+
+    <application android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/Theme.Sample"
+        android:allowBackup="true">
+
+        <activity android:name=".MainActivity"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".DoneBarActivity"
+            android:parentActivityName=".MainActivity" />
+
+        <activity android:name=".DoneButtonActivity"
+            android:parentActivityName=".MainActivity" />
+
+    </application>
+
+</manifest>
diff --git a/samples/browseable/DoneBar/_index.jd b/samples/browseable/DoneBar/_index.jd
new file mode 100644
index 0000000..8ef219c
--- /dev/null
+++ b/samples/browseable/DoneBar/_index.jd
@@ -0,0 +1,12 @@
+
+
+
+page.tags="DoneBar"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates a user interface design pattern for simple data
+entry from an {@link android.app.ActionBar}. The sample implements a custom
+<strong>Done/Cancel</strong> bar to provide users with an easy way to directly
+save or cancel their changes. This design pattern is suitable for scenarios
+where no additional view details or actions are needed in the action bar.</p>
diff --git a/samples/browseable/DoneBar/res/drawable-hdpi/ic_action_cancel.png b/samples/browseable/DoneBar/res/drawable-hdpi/ic_action_cancel.png
new file mode 100644
index 0000000..cde36e1
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-hdpi/ic_action_cancel.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-hdpi/ic_action_done.png b/samples/browseable/DoneBar/res/drawable-hdpi/ic_action_done.png
new file mode 100644
index 0000000..58bf972
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-hdpi/ic_action_done.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-hdpi/ic_launcher.png b/samples/browseable/DoneBar/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-hdpi/tile.9.png b/samples/browseable/DoneBar/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-mdpi/ic_action_cancel.png b/samples/browseable/DoneBar/res/drawable-mdpi/ic_action_cancel.png
new file mode 100644
index 0000000..9f4c3d6
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-mdpi/ic_action_cancel.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-mdpi/ic_action_done.png b/samples/browseable/DoneBar/res/drawable-mdpi/ic_action_done.png
new file mode 100644
index 0000000..cf5fab3
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-mdpi/ic_action_done.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-mdpi/ic_launcher.png b/samples/browseable/DoneBar/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-xhdpi/ic_action_cancel.png b/samples/browseable/DoneBar/res/drawable-xhdpi/ic_action_cancel.png
new file mode 100644
index 0000000..ca7d159
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-xhdpi/ic_action_cancel.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-xhdpi/ic_action_done.png b/samples/browseable/DoneBar/res/drawable-xhdpi/ic_action_done.png
new file mode 100644
index 0000000..b891571
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-xhdpi/ic_action_done.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/DoneBar/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-xhdpi/sample_dashboard_item_background.9.png b/samples/browseable/DoneBar/res/drawable-xhdpi/sample_dashboard_item_background.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-xhdpi/sample_dashboard_item_background.9.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/DoneBar/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/DoneBar/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DoneBar/res/layout/actionbar_custom_view_done.xml b/samples/browseable/DoneBar/res/layout/actionbar_custom_view_done.xml
new file mode 100644
index 0000000..44c1d61
--- /dev/null
+++ b/samples/browseable/DoneBar/res/layout/actionbar_custom_view_done.xml
@@ -0,0 +1,26 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:divider="?android:attr/dividerVertical"
+    android:showDividers="end"
+    android:dividerPadding="12dp">
+
+    <include layout="@layout/include_done_button" />
+</LinearLayout>
diff --git a/samples/browseable/DoneBar/res/layout/actionbar_custom_view_done_cancel.xml b/samples/browseable/DoneBar/res/layout/actionbar_custom_view_done_cancel.xml
new file mode 100644
index 0000000..5cecdf0
--- /dev/null
+++ b/samples/browseable/DoneBar/res/layout/actionbar_custom_view_done_cancel.xml
@@ -0,0 +1,27 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:divider="?android:attr/dividerVertical"
+    android:showDividers="middle"
+    android:dividerPadding="12dp">
+
+    <include layout="@layout/include_cancel_button" />
+    <include layout="@layout/include_done_button" />
+</LinearLayout>
diff --git a/samples/browseable/DoneBar/res/layout/activity_done_bar.xml b/samples/browseable/DoneBar/res/layout/activity_done_bar.xml
new file mode 100755
index 0000000..0d0272d
--- /dev/null
+++ b/samples/browseable/DoneBar/res/layout/activity_done_bar.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout style="@style/Widget.SampleContentContainer"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/donebaractivity_description" />
+
+    </LinearLayout>
+</ScrollView>
diff --git a/samples/browseable/DoneBar/res/layout/activity_done_button.xml b/samples/browseable/DoneBar/res/layout/activity_done_button.xml
new file mode 100755
index 0000000..7fc2274
--- /dev/null
+++ b/samples/browseable/DoneBar/res/layout/activity_done_button.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout style="@style/Widget.SampleContentContainer"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/donebuttonactivity_description" />
+
+    </LinearLayout>
+</ScrollView>
diff --git a/samples/browseable/DoneBar/res/layout/activity_main.xml b/samples/browseable/DoneBar/res/layout/activity_main.xml
new file mode 100755
index 0000000..88cdb80
--- /dev/null
+++ b/samples/browseable/DoneBar/res/layout/activity_main.xml
@@ -0,0 +1,41 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView style="@style/Widget.SampleMessage"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/horizontal_page_margin"
+        android:layout_marginRight="@dimen/horizontal_page_margin"
+        android:layout_marginTop="@dimen/vertical_page_margin"
+        android:layout_marginBottom="@dimen/vertical_page_margin"
+        android:text="@string/intro_message" />
+
+    <GridView android:id="@android:id/list"
+        style="@style/Widget.SampleDashboard.Grid"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:paddingLeft="@dimen/horizontal_page_margin"
+        android:paddingRight="@dimen/horizontal_page_margin"
+        android:paddingBottom="@dimen/vertical_page_margin"
+        android:scrollbarStyle="outsideOverlay" />
+
+</LinearLayout>
diff --git a/samples/browseable/DoneBar/res/layout/activity_sample_dashboard.xml b/samples/browseable/DoneBar/res/layout/activity_sample_dashboard.xml
new file mode 100755
index 0000000..88cdb80
--- /dev/null
+++ b/samples/browseable/DoneBar/res/layout/activity_sample_dashboard.xml
@@ -0,0 +1,41 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView style="@style/Widget.SampleMessage"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/horizontal_page_margin"
+        android:layout_marginRight="@dimen/horizontal_page_margin"
+        android:layout_marginTop="@dimen/vertical_page_margin"
+        android:layout_marginBottom="@dimen/vertical_page_margin"
+        android:text="@string/intro_message" />
+
+    <GridView android:id="@android:id/list"
+        style="@style/Widget.SampleDashboard.Grid"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:paddingLeft="@dimen/horizontal_page_margin"
+        android:paddingRight="@dimen/horizontal_page_margin"
+        android:paddingBottom="@dimen/vertical_page_margin"
+        android:scrollbarStyle="outsideOverlay" />
+
+</LinearLayout>
diff --git a/samples/browseable/DoneBar/res/layout/include_cancel_button.xml b/samples/browseable/DoneBar/res/layout/include_cancel_button.xml
new file mode 100644
index 0000000..bffffa6
--- /dev/null
+++ b/samples/browseable/DoneBar/res/layout/include_cancel_button.xml
@@ -0,0 +1,33 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    style="?android:actionButtonStyle"
+    android:id="@+id/actionbar_cancel"
+    android:layout_width="0dp"
+    android:layout_height="match_parent"
+    android:layout_weight="1">
+
+    <TextView style="?android:actionBarTabTextStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:paddingRight="20dp"
+        android:drawableLeft="@drawable/ic_action_cancel"
+        android:drawablePadding="8dp"
+        android:gravity="center_vertical"
+        android:text="@string/cancel" />
+</FrameLayout>
diff --git a/samples/browseable/DoneBar/res/layout/include_done_button.xml b/samples/browseable/DoneBar/res/layout/include_done_button.xml
new file mode 100644
index 0000000..9207733
--- /dev/null
+++ b/samples/browseable/DoneBar/res/layout/include_done_button.xml
@@ -0,0 +1,33 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    style="?android:actionButtonStyle"
+    android:id="@+id/actionbar_done"
+    android:layout_width="0dp"
+    android:layout_height="match_parent"
+    android:layout_weight="1">
+
+    <TextView style="?android:actionBarTabTextStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:paddingRight="20dp"
+        android:drawableLeft="@drawable/ic_action_done"
+        android:drawablePadding="8dp"
+        android:gravity="center_vertical"
+        android:text="@string/done" />
+</FrameLayout>
diff --git a/samples/browseable/DoneBar/res/layout/sample_dashboard_item.xml b/samples/browseable/DoneBar/res/layout/sample_dashboard_item.xml
new file mode 100644
index 0000000..38987ee
--- /dev/null
+++ b/samples/browseable/DoneBar/res/layout/sample_dashboard_item.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/Widget.SampleDashboard.Item"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView android:id="@android:id/text1"
+        style="@style/Widget.SampleDashboard.Item.Title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <TextView android:id="@android:id/text2"
+        style="@style/Widget.SampleDashboard.Item.Description"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/samples/browseable/DoneBar/res/menu/cancel.xml b/samples/browseable/DoneBar/res/menu/cancel.xml
new file mode 100644
index 0000000..18e3eed
--- /dev/null
+++ b/samples/browseable/DoneBar/res/menu/cancel.xml
@@ -0,0 +1,22 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/cancel"
+        android:title="@string/cancel"
+        android:icon="@drawable/ic_action_cancel"
+        android:showAsAction="never" />
+</menu>
diff --git a/samples/browseable/DoneBar/res/values-sw600dp/dimens.xml b/samples/browseable/DoneBar/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/DoneBar/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/DoneBar/res/values-sw600dp/styles.xml b/samples/browseable/DoneBar/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/DoneBar/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/DoneBar/res/values/activitycards-strings.xml b/samples/browseable/DoneBar/res/values/activitycards-strings.xml
new file mode 100644
index 0000000..5c2557c
--- /dev/null
+++ b/samples/browseable/DoneBar/res/values/activitycards-strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+
+<resources>
+    <string name="donebaractivity_title">Done Bar</string>
+    <string name="donebaractivity_description">In this presentation, a done bar replaces the action bar entirely, providing
+            two direct actions to persist or dismiss changes. This is suitable for cases where no
+            additional view details or actions are needed in the action bar.</string>
+    <string name="donebuttonactivity_title">Done Button</string>
+    <string name="donebuttonactivity_description">In this presentation, a done button replaces the action bar\'s "Up" affordance
+            and app icon, while the cancel action is made available in the action overflow. This is
+            well-suited to scenarios where additional view details or
+            actions may be needed in the action bar.</string>
+</resources>
diff --git a/samples/browseable/DoneBar/res/values/base-strings.xml b/samples/browseable/DoneBar/res/values/base-strings.xml
new file mode 100644
index 0000000..22a4fae
--- /dev/null
+++ b/samples/browseable/DoneBar/res/values/base-strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">DoneBar</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+                This sample demonstrates two alternative presentations of the
+                action bar that are well-suited for simple data entry scenarios.
+
+                In this presentation, a done bar replaces the action
+                bar entirely, providing two direct actions to persist or dismiss changes. This is
+                suitable for cases where no additional view details or actions are needed in the
+                action bar.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/DoneBar/res/values/dimens.xml b/samples/browseable/DoneBar/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/DoneBar/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/DoneBar/res/values/strings.xml b/samples/browseable/DoneBar/res/values/strings.xml
new file mode 100755
index 0000000..df66a95
--- /dev/null
+++ b/samples/browseable/DoneBar/res/values/strings.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <!-- Done bar strings -->
+    <string name="done">Done</string>
+    <string name="cancel">Cancel</string>
+</resources>
diff --git a/samples/browseable/DoneBar/res/values/styles.xml b/samples/browseable/DoneBar/res/values/styles.xml
new file mode 100644
index 0000000..cafe531
--- /dev/null
+++ b/samples/browseable/DoneBar/res/values/styles.xml
@@ -0,0 +1,71 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleContentContainer">
+        <item name="android:paddingTop">@dimen/vertical_page_margin</item>
+        <item name="android:paddingBottom">@dimen/vertical_page_margin</item>
+        <item name="android:paddingLeft">@dimen/horizontal_page_margin</item>
+        <item name="android:paddingRight">@dimen/horizontal_page_margin</item>
+    </style>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleDashboard.Grid" parent="Widget">
+        <item name="android:stretchMode">columnWidth</item>
+        <item name="android:columnWidth">200dp</item>
+        <item name="android:numColumns">auto_fit</item>
+        <item name="android:drawSelectorOnTop">true</item>
+        <item name="android:horizontalSpacing">@dimen/margin_medium</item>
+        <item name="android:verticalSpacing">@dimen/margin_medium</item>
+    </style>
+
+    <style name="Widget.SampleDashboard.Item" parent="Widget">
+        <item name="android:background">@drawable/sample_dashboard_item_background</item>
+        <item name="android:paddingTop">@dimen/margin_small</item>
+        <item name="android:paddingLeft">@dimen/margin_medium</item>
+        <item name="android:paddingRight">@dimen/margin_medium</item>
+        <item name="android:paddingBottom">@dimen/margin_medium</item>
+    </style>
+
+    <style name="Widget.SampleDashboard.Item.Title" parent="Widget">
+        <item name="android:layout_marginBottom">@dimen/margin_tiny</item>
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:textColor">#09c</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textSize">24sp</item>
+    </style>
+
+    <style name="Widget.SampleDashboard.Item.Description" parent="Widget">
+        <item name="android:textAppearance">?android:textAppearanceSmall</item>
+        <item name="android:fontFamily">sans-serif-light</item>
+    </style>
+</resources>
diff --git a/samples/browseable/DoneBar/src/com.example.android.donebar/DoneBarActivity.java b/samples/browseable/DoneBar/src/com.example.android.donebar/DoneBarActivity.java
new file mode 100755
index 0000000..f2a2b00
--- /dev/null
+++ b/samples/browseable/DoneBar/src/com.example.android.donebar/DoneBarActivity.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.donebar;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A sample activity demonstrating the "done bar" alternative action bar presentation. For a more
+ * detailed description see {@link R.string.done_bar_description}.
+ */
+public class DoneBarActivity extends Activity {
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // BEGIN_INCLUDE (inflate_set_custom_view)
+        // Inflate a "Done/Cancel" custom action bar view.
+        final LayoutInflater inflater = (LayoutInflater) getActionBar().getThemedContext()
+                .getSystemService(LAYOUT_INFLATER_SERVICE);
+        final View customActionBarView = inflater.inflate(
+                R.layout.actionbar_custom_view_done_cancel, null);
+        customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener(
+                new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        // "Done"
+                        finish();
+                    }
+                });
+        customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener(
+                new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        // "Cancel"
+                        finish();
+                    }
+                });
+
+        // Show the custom action bar view and hide the normal Home icon and title.
+        final ActionBar actionBar = getActionBar();
+        actionBar.setDisplayOptions(
+                ActionBar.DISPLAY_SHOW_CUSTOM,
+                ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME
+                        | ActionBar.DISPLAY_SHOW_TITLE);
+        actionBar.setCustomView(customActionBarView,
+                new ActionBar.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.MATCH_PARENT));
+        // END_INCLUDE (inflate_set_custom_view)
+
+        setContentView(R.layout.activity_done_bar);
+    }
+}
diff --git a/samples/browseable/DoneBar/src/com.example.android.donebar/DoneButtonActivity.java b/samples/browseable/DoneBar/src/com.example.android.donebar/DoneButtonActivity.java
new file mode 100755
index 0000000..3b1e37d
--- /dev/null
+++ b/samples/browseable/DoneBar/src/com.example.android.donebar/DoneButtonActivity.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.donebar;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+/**
+ * A sample activity demonstrating the "done button" alternative action bar presentation. For a more
+ * detailed description see {@link R.string.done_button_description}.
+ */
+public class DoneButtonActivity extends Activity {
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // BEGIN_INCLUDE (inflate_set_custom_view)
+        // Inflate a "Done" custom action bar view to serve as the "Up" affordance.
+        final LayoutInflater inflater = (LayoutInflater) getActionBar().getThemedContext()
+                .getSystemService(LAYOUT_INFLATER_SERVICE);
+        final View customActionBarView = inflater.inflate(
+                R.layout.actionbar_custom_view_done, null);
+        customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener(
+                new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        // "Done"
+                        finish();
+                    }
+                });
+
+        // Show the custom action bar view and hide the normal Home icon and title.
+        final ActionBar actionBar = getActionBar();
+        actionBar.setDisplayOptions(
+                ActionBar.DISPLAY_SHOW_CUSTOM,
+                ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME
+                        | ActionBar.DISPLAY_SHOW_TITLE);
+        actionBar.setCustomView(customActionBarView);
+        // END_INCLUDE (inflate_set_custom_view)
+
+        setContentView(R.layout.activity_done_button);
+    }
+
+    // BEGIN_INCLUDE (handle_cancel)
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        getMenuInflater().inflate(R.menu.cancel, menu);
+        return true;
+    }
+
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.cancel:
+                // "Cancel"
+                finish();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+    // END_INCLUDE (handle_cancel)
+}
diff --git a/samples/browseable/DoneBar/src/com.example.android.donebar/MainActivity.java b/samples/browseable/DoneBar/src/com.example.android.donebar/MainActivity.java
new file mode 100644
index 0000000..8b1e8a4
--- /dev/null
+++ b/samples/browseable/DoneBar/src/com.example.android.donebar/MainActivity.java
@@ -0,0 +1,112 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+
+
+package com.example.android.donebar;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+/**
+ * A simple launcher activity offering access to the individual samples in this project.
+ */
+public class MainActivity extends Activity implements AdapterView.OnItemClickListener {
+    private Sample[] mSamples;
+    private GridView mGridView;
+
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        // Prepare list of samples in this dashboard.
+        mSamples = new Sample[]{
+            new Sample(R.string.donebaractivity_title, R.string.donebaractivity_description,
+                    DoneBarActivity.class),
+            new Sample(R.string.donebuttonactivity_title, R.string.donebuttonactivity_description,
+                    DoneButtonActivity.class),
+        };
+
+        // Prepare the GridView
+        mGridView = (GridView) findViewById(android.R.id.list);
+        mGridView.setAdapter(new SampleAdapter());
+        mGridView.setOnItemClickListener(this);
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> container, View view, int position, long id) {
+        startActivity(mSamples[position].intent);
+    }
+
+    private class SampleAdapter extends BaseAdapter {
+        @Override
+        public int getCount() {
+            return mSamples.length;
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return mSamples[position];
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return mSamples[position].hashCode();
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup container) {
+            if (convertView == null) {
+                convertView = getLayoutInflater().inflate(R.layout.sample_dashboard_item,
+                        container, false);
+            }
+
+            ((TextView) convertView.findViewById(android.R.id.text1)).setText(
+                    mSamples[position].titleResId);
+            ((TextView) convertView.findViewById(android.R.id.text2)).setText(
+                    mSamples[position].descriptionResId);
+            return convertView;
+        }
+    }
+
+    private class Sample {
+        int titleResId;
+        int descriptionResId;
+        Intent intent;
+
+        private Sample(int titleResId, int descriptionResId, Intent intent) {
+            this.intent = intent;
+            this.titleResId = titleResId;
+            this.descriptionResId = descriptionResId;
+        }
+
+        private Sample(int titleResId, int descriptionResId,
+                Class<? extends Activity> activityClass) {
+            this(titleResId, descriptionResId,
+                    new Intent(MainActivity.this, activityClass));
+        }
+    }
+}
diff --git a/samples/browseable/HorizontalPaging/AndroidManifest.xml b/samples/browseable/HorizontalPaging/AndroidManifest.xml
new file mode 100644
index 0000000..33b9e15
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/AndroidManifest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.horizontalpaging"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <!-- While ViewPager will work on API 4 or above, tabs require an ActionBar. ActionBar is only
+         available in API 11 or above. -->
+    <uses-sdk
+        android:minSdkVersion="11"
+        android:targetSdkVersion="16" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <!-- This is a standard Activity invocation for MainActivity. -->
+        <activity
+            android:name="com.example.android.horizontalpaging.MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/HorizontalPaging/_index.jd b/samples/browseable/HorizontalPaging/_index.jd
new file mode 100644
index 0000000..acdc1b1
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/_index.jd
@@ -0,0 +1,10 @@
+
+
+
+page.tags="HorizontalPaging"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to implement horizontal paging between
+fragments in an application that has an {@link android.app.ActionBar}, using a
+{@link android.support.v4.view.ViewPager} widget.</p>
diff --git a/samples/training/bitmapfun/res/drawable-hdpi/ic_launcher.png b/samples/browseable/HorizontalPaging/res/drawable-hdpi/ic_launcher.png
old mode 100644
new mode 100755
similarity index 100%
rename from samples/training/bitmapfun/res/drawable-hdpi/ic_launcher.png
rename to samples/browseable/HorizontalPaging/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/HorizontalPaging/res/drawable-hdpi/tile.9.png b/samples/browseable/HorizontalPaging/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/training/bitmapfun/res/drawable-mdpi/ic_launcher.png b/samples/browseable/HorizontalPaging/res/drawable-mdpi/ic_launcher.png
old mode 100644
new mode 100755
similarity index 100%
rename from samples/training/bitmapfun/res/drawable-mdpi/ic_launcher.png
rename to samples/browseable/HorizontalPaging/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/bitmapfun/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/HorizontalPaging/res/drawable-xhdpi/ic_launcher.png
old mode 100644
new mode 100755
similarity index 100%
rename from samples/training/bitmapfun/res/drawable-xhdpi/ic_launcher.png
rename to samples/browseable/HorizontalPaging/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/HorizontalPaging/res/layout/activity_main.xml b/samples/browseable/HorizontalPaging/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/HorizontalPaging/res/layout/fragment_main_dummy.xml b/samples/browseable/HorizontalPaging/res/layout/fragment_main_dummy.xml
new file mode 100644
index 0000000..6197494
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/layout/fragment_main_dummy.xml
@@ -0,0 +1,16 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    tools:context=".MainActivity$DummySectionFragment">
+
+    <TextView
+        android:id="@+id/section_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</RelativeLayout>
diff --git a/samples/browseable/HorizontalPaging/res/layout/sample_main.xml b/samples/browseable/HorizontalPaging/res/layout/sample_main.xml
new file mode 100644
index 0000000..237372c
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/layout/sample_main.xml
@@ -0,0 +1,8 @@
+<!-- BEGIN_INCLUDE (view_pager_layout) -->
+<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/pager"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity" />
+<!-- END_INCLUDE (view_pager_layout) -->
diff --git a/samples/browseable/HorizontalPaging/res/values-sw600dp/dimens.xml b/samples/browseable/HorizontalPaging/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/HorizontalPaging/res/values-sw600dp/styles.xml b/samples/browseable/HorizontalPaging/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/HorizontalPaging/res/values/base-strings.xml b/samples/browseable/HorizontalPaging/res/values/base-strings.xml
new file mode 100644
index 0000000..70484bc
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">HorizontalPaging</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates how to implement horizontal paging between fragments in
+            applications that use ActionBar, using a ViewPager widget.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/HorizontalPaging/res/values/dimens.xml b/samples/browseable/HorizontalPaging/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/HorizontalPaging/res/values/strings.xml b/samples/browseable/HorizontalPaging/res/values/strings.xml
new file mode 100644
index 0000000..f9b4212
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/values/strings.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="action_settings">Settings</string>
+    <string name="title_section1">Section 1</string>
+    <string name="title_section2">Section 2</string>
+    <string name="title_section3">Section 3</string>
+
+</resources>
diff --git a/samples/browseable/HorizontalPaging/res/values/styles.xml b/samples/browseable/HorizontalPaging/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/HorizontalPaging/res/values/values-sw720dp-land/dimens.xml b/samples/browseable/HorizontalPaging/res/values/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..00059fc
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/res/values/values-sw720dp-land/dimens.xml
@@ -0,0 +1,5 @@
+<resources>
+    <!-- Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. -->
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+</resources>
diff --git a/samples/browseable/HorizontalPaging/src/com.example.android.horizontalpaging/MainActivity.java b/samples/browseable/HorizontalPaging/src/com.example.android.horizontalpaging/MainActivity.java
new file mode 100644
index 0000000..fdd4495
--- /dev/null
+++ b/samples/browseable/HorizontalPaging/src/com.example.android.horizontalpaging/MainActivity.java
@@ -0,0 +1,219 @@
+package com.example.android.horizontalpaging;
+
+import android.app.ActionBar;
+import android.app.FragmentTransaction;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import java.util.Locale;
+
+public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
+
+    /**
+     * The {@link android.support.v4.view.PagerAdapter} that will provide
+     * fragments for each of the sections. We use a
+     * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
+     * will keep every loaded fragment in memory. If this becomes too memory
+     * intensive, it may be best to switch to a
+     * {@link android.support.v4.app.FragmentStatePagerAdapter}.
+     */
+    SectionsPagerAdapter mSectionsPagerAdapter;
+
+    /**
+     * The {@link ViewPager} that will host the section contents.
+     */
+    ViewPager mViewPager;
+
+    /**
+     * Create the activity. Sets up an {@link android.app.ActionBar} with tabs, and then configures the
+     * {@link ViewPager} contained inside R.layout.activity_main.
+     *
+     * <p>A {@link SectionsPagerAdapter} will be instantiated to hold the different pages of
+     * fragments that are to be displayed. A
+     * {@link android.support.v4.view.ViewPager.SimpleOnPageChangeListener} will also be configured
+     * to receive callbacks when the user swipes between pages in the ViewPager.
+     *
+     * @param savedInstanceState
+     */
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // Load the UI from res/layout/activity_main.xml
+        setContentView(R.layout.sample_main);
+
+        // Set up the action bar. The navigation mode is set to NAVIGATION_MODE_TABS, which will
+        // cause the ActionBar to render a set of tabs. Note that these tabs are *not* rendered
+        // by the ViewPager; additional logic is lower in this file to synchronize the ViewPager
+        // state with the tab state. (See mViewPager.setOnPageChangeListener() and onTabSelected().)
+        // BEGIN_INCLUDE (set_navigation_mode)
+        final ActionBar actionBar = getActionBar();
+        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+        // END_INCLUDE (set_navigation_mode)
+
+        // BEGIN_INCLUDE (setup_view_pager)
+        // Create the adapter that will return a fragment for each of the three primary sections
+        // of the app.
+        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
+
+        // Set up the ViewPager with the sections adapter.
+        mViewPager = (ViewPager) findViewById(R.id.pager);
+        mViewPager.setAdapter(mSectionsPagerAdapter);
+        // END_INCLUDE (setup_view_pager)
+
+        // When swiping between different sections, select the corresponding tab. We can also use
+        // ActionBar.Tab#select() to do this if we have a reference to the Tab.
+        // BEGIN_INCLUDE (page_change_listener)
+        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+            @Override
+            public void onPageSelected(int position) {
+                actionBar.setSelectedNavigationItem(position);
+            }
+        });
+        // END_INCLUDE (page_change_listener)
+
+        // BEGIN_INCLUDE (add_tabs)
+        // For each of the sections in the app, add a tab to the action bar.
+        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
+            // Create a tab with text corresponding to the page title defined by the adapter. Also
+            // specify this Activity object, which implements the TabListener interface, as the
+            // callback (listener) for when this tab is selected.
+            actionBar.addTab(
+                    actionBar.newTab()
+                            .setText(mSectionsPagerAdapter.getPageTitle(i))
+                            .setTabListener(this));
+        }
+        // END_INCLUDE (add_tabs)
+    }
+
+    /**
+     * Update {@link ViewPager} after a tab has been selected in the ActionBar.
+     *
+     * @param tab Tab that was selected.
+     * @param fragmentTransaction A {@link android.app.FragmentTransaction} for queuing fragment operations to
+     *                            execute once this method returns. This FragmentTransaction does
+     *                            not support being added to the back stack.
+     */
+    // BEGIN_INCLUDE (on_tab_selected)
+    @Override
+    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+        // When the given tab is selected, tell the ViewPager to switch to the corresponding page.
+        mViewPager.setCurrentItem(tab.getPosition());
+    }
+    // END_INCLUDE (on_tab_selected)
+
+    /**
+     * Unused. Required for {@link android.app.ActionBar.TabListener}.
+     */
+    @Override
+    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+    }
+
+    /**
+     * Unused. Required for {@link android.app.ActionBar.TabListener}.
+     */
+    @Override
+    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+    }
+
+    // BEGIN_INCLUDE (fragment_pager_adapter)
+    /**
+     * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
+     * one of the sections/tabs/pages. This provides the data for the {@link ViewPager}.
+     */
+    public class SectionsPagerAdapter extends FragmentPagerAdapter {
+    // END_INCLUDE (fragment_pager_adapter)
+
+        public SectionsPagerAdapter(FragmentManager fm) {
+            super(fm);
+        }
+
+        // BEGIN_INCLUDE (fragment_pager_adapter_getitem)
+        /**
+         * Get fragment corresponding to a specific position. This will be used to populate the
+         * contents of the {@link ViewPager}.
+         *
+         * @param position Position to fetch fragment for.
+         * @return Fragment for specified position.
+         */
+        @Override
+        public Fragment getItem(int position) {
+            // getItem is called to instantiate the fragment for the given page.
+            // Return a DummySectionFragment (defined as a static inner class
+            // below) with the page number as its lone argument.
+            Fragment fragment = new DummySectionFragment();
+            Bundle args = new Bundle();
+            args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
+            fragment.setArguments(args);
+            return fragment;
+        }
+        // END_INCLUDE (fragment_pager_adapter_getitem)
+
+        // BEGIN_INCLUDE (fragment_pager_adapter_getcount)
+        /**
+         * Get number of pages the {@link ViewPager} should render.
+         *
+         * @return Number of fragments to be rendered as pages.
+         */
+        @Override
+        public int getCount() {
+            // Show 3 total pages.
+            return 3;
+        }
+        // END_INCLUDE (fragment_pager_adapter_getcount)
+
+        // BEGIN_INCLUDE (fragment_pager_adapter_getpagetitle)
+        /**
+         * Get title for each of the pages. This will be displayed on each of the tabs.
+         *
+         * @param position Page to fetch title for.
+         * @return Title for specified page.
+         */
+        @Override
+        public CharSequence getPageTitle(int position) {
+            Locale l = Locale.getDefault();
+            switch (position) {
+                case 0:
+                    return getString(R.string.title_section1).toUpperCase(l);
+                case 1:
+                    return getString(R.string.title_section2).toUpperCase(l);
+                case 2:
+                    return getString(R.string.title_section3).toUpperCase(l);
+            }
+            return null;
+        }
+        // END_INCLUDE (fragment_pager_adapter_getpagetitle)
+    }
+
+    /**
+     * A dummy fragment representing a section of the app, but that simply displays dummy text.
+     * This would be replaced with your application's content.
+     */
+    public static class DummySectionFragment extends Fragment {
+        /**
+         * The fragment argument representing the section number for this
+         * fragment.
+         */
+        public static final String ARG_SECTION_NUMBER = "section_number";
+
+        public DummySectionFragment() {
+        }
+
+        @Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            View rootView = inflater.inflate(R.layout.fragment_main_dummy, container, false);
+            TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
+            dummyTextView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));
+            return rootView;
+        }
+    }
+
+}
diff --git a/samples/browseable/ImmersiveMode/AndroidManifest.xml b/samples/browseable/ImmersiveMode/AndroidManifest.xml
new file mode 100644
index 0000000..72a60ce
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.immersivemode"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="19" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name"
+                  android:uiOptions="splitActionBarWhenNarrow">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+
+</manifest>
diff --git a/samples/browseable/ImmersiveMode/_index.jd b/samples/browseable/ImmersiveMode/_index.jd
new file mode 100644
index 0000000..ab3b718
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/_index.jd
@@ -0,0 +1,12 @@
+
+
+
+page.tags="ImmersiveMode"
+sample.group=UI
+@jd:body
+
+<p>Android 4.4 introduces a way for you to provide a more immersive screen
+experience in your app, by letting users show or hide the status bar and
+navigation bar with a swipe.</p>
+<p>This sample demonstrates how to enable toggling of this feature in a
+{@link android.support.v4.app.Fragment}.</p>
diff --git a/samples/browseable/ImmersiveMode/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ImmersiveMode/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ImmersiveMode/res/drawable-hdpi/tile.9.png b/samples/browseable/ImmersiveMode/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ImmersiveMode/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ImmersiveMode/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ImmersiveMode/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ImmersiveMode/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ImmersiveMode/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ImmersiveMode/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ImmersiveMode/res/layout/activity_main.xml b/samples/browseable/ImmersiveMode/res/layout/activity_main.xml
new file mode 100755
index 0000000..bc5a575
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:id="@+id/sample_main_layout">
+    <TextView android:id="@+id/sample_output"
+              style="@style/Widget.SampleMessage"
+              android:layout_weight="1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:text="@string/intro_message" />
+    <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:background="@android:color/darker_gray"/>
+    <fragment
+            android:name="com.example.android.common.logger.LogFragment"
+            android:id="@+id/log_fragment"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/samples/browseable/ImmersiveMode/res/menu/main.xml b/samples/browseable/ImmersiveMode/res/menu/main.xml
new file mode 100644
index 0000000..2c3515d
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/sample_action"
+          android:showAsAction="ifRoom|withText"
+          android:title="@string/sample_action" />
+</menu>
diff --git a/samples/browseable/ImmersiveMode/res/values-sw600dp/dimens.xml b/samples/browseable/ImmersiveMode/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ImmersiveMode/res/values-sw600dp/styles.xml b/samples/browseable/ImmersiveMode/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/ImmersiveMode/res/values/base-strings.xml b/samples/browseable/ImmersiveMode/res/values/base-strings.xml
new file mode 100644
index 0000000..2092f63
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/values/base-strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">ImmersiveMode</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            One of the features introduced in KitKat is "immersive mode". Immersive mode gives the
+            user the ability to show/hide the status bar and navigation bar with a swipe.  To try,
+            click the "Toggle immersive mode" button, then try swiping the bar in and out!
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/ImmersiveMode/res/values/dimens.xml b/samples/browseable/ImmersiveMode/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ImmersiveMode/res/values/strings.xml b/samples/browseable/ImmersiveMode/res/values/strings.xml
new file mode 100644
index 0000000..8a1e9e1
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+        <string name="sample_action">Toggle immersive mode!</string>
+</resources>
diff --git a/samples/browseable/ImmersiveMode/res/values/styles.xml b/samples/browseable/ImmersiveMode/res/values/styles.xml
new file mode 100644
index 0000000..d3f82ff
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/res/values/styles.xml
@@ -0,0 +1,51 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="AppTheme" parent="Theme.Base" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+
+    <style name="Widget.SampleOutput">
+        <item name="android:padding">@dimen/margin_medium</item>
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Log" parent="Widget.SampleOutput">
+        <item name="android:typeface">monospace</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/ImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/ImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+    public static final String TAG = "SampleActivityBase";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected  void onStart() {
+        super.onStart();
+        initializeLogging();
+    }
+
+    /** Set up targets to receive log data */
+    public void initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/Log.java b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogNode.java b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogView.java b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/ImmersiveMode/src/com.example.android.immersivemode/ImmersiveModeFragment.java b/samples/browseable/ImmersiveMode/src/com.example.android.immersivemode/ImmersiveModeFragment.java
new file mode 100644
index 0000000..8a7255c
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/src/com.example.android.immersivemode/ImmersiveModeFragment.java
@@ -0,0 +1,103 @@
+/*
+* Copyright (C) 2012 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package com.example.android.immersivemode;
+
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.example.android.common.logger.Log;
+
+public class ImmersiveModeFragment extends Fragment {
+
+    public static final String TAG = "ImmersiveModeFragment";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        final View decorView = getActivity().getWindow().getDecorView();
+        decorView.setOnSystemUiVisibilityChangeListener(
+                new View.OnSystemUiVisibilityChangeListener() {
+                    @Override
+                    public void onSystemUiVisibilityChange(int i) {
+                        int height = decorView.getHeight();
+                        Log.i(TAG, "Current height: " + height);
+                    }
+                });
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.sample_action) {
+            toggleHideyBar();
+        }
+        return true;
+    }
+
+    /**
+     * Detects and toggles immersive mode (also known as "hidey bar" mode).
+     */
+    public void toggleHideyBar() {
+
+        // BEGIN_INCLUDE (get_current_ui_flags)
+        // The UI options currently enabled are represented by a bitfield.
+        // getSystemUiVisibility() gives us that bitfield.
+        int uiOptions = getActivity().getWindow().getDecorView().getSystemUiVisibility();
+        int newUiOptions = uiOptions;
+        // END_INCLUDE (get_current_ui_flags)
+        // BEGIN_INCLUDE (toggle_ui_flags)
+        boolean isImmersiveModeEnabled =
+                ((uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) == uiOptions);
+        if (isImmersiveModeEnabled) {
+            Log.i(TAG, "Turning immersive mode mode off. ");
+        } else {
+            Log.i(TAG, "Turning immersive mode mode on.");
+        }
+
+        // Navigation bar hiding:  Backwards compatible to ICS.
+        if (Build.VERSION.SDK_INT >= 14) {
+            newUiOptions ^= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+        }
+
+        // Status bar hiding: Backwards compatible to Jellybean
+        if (Build.VERSION.SDK_INT >= 16) {
+            newUiOptions ^= View.SYSTEM_UI_FLAG_FULLSCREEN;
+        }
+
+        // Immersive mode: Backward compatible to KitKat.
+        // Note that this flag doesn't do anything by itself, it only augments the behavior
+        // of HIDE_NAVIGATION and FLAG_FULLSCREEN.  For the purposes of this sample
+        // all three flags are being toggled together.
+        // Note that there are two immersive mode UI flags, one of which is referred to as "sticky".
+        // Sticky immersive mode differs in that it makes the navigation and status bars
+        // semi-transparent, and the UI flag does not get cleared when the user interacts with
+        // the screen.
+        if (Build.VERSION.SDK_INT >= 18) {
+            newUiOptions ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+        }
+
+        getActivity().getWindow().getDecorView().setSystemUiVisibility(newUiOptions);
+        //END_INCLUDE (set_ui_flags)
+    }
+}
diff --git a/samples/browseable/ImmersiveMode/src/com.example.android.immersivemode/MainActivity.java b/samples/browseable/ImmersiveMode/src/com.example.android.immersivemode/MainActivity.java
new file mode 100644
index 0000000..fd02112
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/src/com.example.android.immersivemode/MainActivity.java
@@ -0,0 +1,80 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+
+
+package com.example.android.immersivemode;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description
+ * and a few action bar buttons.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    public static final String FRAGTAG = "ImmersiveModeFragment";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        if (getSupportFragmentManager().findFragmentByTag(FRAGTAG) == null ) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            ImmersiveModeFragment fragment = new ImmersiveModeFragment();
+            transaction.add(fragment, FRAGTAG);
+            transaction.commit();
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/ListPopupMenu/AndroidManifest.xml b/samples/browseable/ListPopupMenu/AndroidManifest.xml
new file mode 100644
index 0000000..114053e
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.actionbarcompat.listpopupmenu"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!-- ActionBarCompat provides an implementation of Popup Menu from API v7 onwards -->
+    <uses-sdk
+        android:minSdkVersion="7"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/Theme.AppCompat"
+        android:allowBackup="true">
+
+        <activity android:name=".MainActivity">
+            <!-- Launcher Intent filter -->
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/browseable/ListPopupMenu/_index.jd b/samples/browseable/ListPopupMenu/_index.jd
new file mode 100644
index 0000000..36090e0
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/_index.jd
@@ -0,0 +1,14 @@
+
+
+
+page.tags="ListPopupMenu"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to use a backward compatible
+{@link android.support.v7.widget.PopupMenu PopupMenu} to create a list, where
+each list item contains a dropdown menu.</p>
+<p>The activity in this sample extends from
+{@link android.support.v7.app.ActionBarActivity}, which provides the
+functionality necessary to display a compatible action bar on devices
+running Android 2.1 and higher.</p>
diff --git a/samples/browseable/ListPopupMenu/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ListPopupMenu/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a7365b9
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-hdpi/ic_overflow.png b/samples/browseable/ListPopupMenu/res/drawable-hdpi/ic_overflow.png
new file mode 100644
index 0000000..2abc458
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/drawable-hdpi/ic_overflow.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-hdpi/tile.9.png b/samples/browseable/ListPopupMenu/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ListPopupMenu/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..3fd5593
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-mdpi/ic_overflow.png b/samples/browseable/ListPopupMenu/res/drawable-mdpi/ic_overflow.png
new file mode 100644
index 0000000..ba704b6
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/drawable-mdpi/ic_overflow.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ListPopupMenu/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..204f861
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-xhdpi/ic_overflow.png b/samples/browseable/ListPopupMenu/res/drawable-xhdpi/ic_overflow.png
new file mode 100644
index 0000000..a92fb1d
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/drawable-xhdpi/ic_overflow.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ListPopupMenu/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..ada8266
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/layout/activity_main.xml b/samples/browseable/ListPopupMenu/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/ListPopupMenu/res/layout/list_item.xml b/samples/browseable/ListPopupMenu/res/layout/list_item.xml
new file mode 100644
index 0000000..3eabda0
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/layout/list_item.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="?attr/listPreferredItemHeight">
+
+    <TextView
+        android:id="@android:id/text1"
+        android:layout_height="match_parent"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:gravity="center_vertical"
+        android:paddingLeft="8dp"
+        android:paddingRight="8dp"
+        android:maxLines="1"
+        android:ellipsize="end"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <ImageView
+        android:id="@+id/button_popup"
+        android:layout_height="match_parent"
+        android:layout_width="56dip"
+        android:background="?attr/selectableItemBackground"
+        android:src="@drawable/ic_overflow"
+        android:contentDescription="@string/content_open_popup"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/ListPopupMenu/res/layout/sample_main.xml b/samples/browseable/ListPopupMenu/res/layout/sample_main.xml
new file mode 100644
index 0000000..bfc7ad0
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/layout/sample_main.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<fragment xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:name="com.example.android.actionbarcompat.listpopupmenu.PopupListFragment" />
\ No newline at end of file
diff --git a/samples/browseable/ListPopupMenu/res/menu/popup.xml b/samples/browseable/ListPopupMenu/res/menu/popup.xml
new file mode 100644
index 0000000..0329e9e
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/menu/popup.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:id="@+id/menu_remove"
+        android:title="@string/menu_remove" />
+
+</menu>
\ No newline at end of file
diff --git a/samples/browseable/ListPopupMenu/res/values-sw600dp/dimens.xml b/samples/browseable/ListPopupMenu/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ListPopupMenu/res/values-sw600dp/styles.xml b/samples/browseable/ListPopupMenu/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/ListPopupMenu/res/values/base-strings.xml b/samples/browseable/ListPopupMenu/res/values/base-strings.xml
new file mode 100644
index 0000000..a23ed75
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">ListPopupMenu</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample shows you how to use {@link android.support.v7.widget.PopupMenu PopupMenu}
+            from ActionBarCompat to create a list, with each item having a dropdown menu.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/ListPopupMenu/res/values/dimens.xml b/samples/browseable/ListPopupMenu/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ListPopupMenu/res/values/strings.xml b/samples/browseable/ListPopupMenu/res/values/strings.xml
new file mode 100644
index 0000000..e5784a9
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+
+    <string name="menu_remove">Remove</string>
+    <string name="content_open_popup">Open Popup Menu</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/ListPopupMenu/res/values/styles.xml b/samples/browseable/ListPopupMenu/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.java b/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.java
new file mode 100644
index 0000000..5ef1161
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat.listpopupmenu;
+
+/**
+ * Dummy data.
+ */
+public class Cheeses {
+    public static final String[] CHEESES = {
+            "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
+            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
+            "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
+            "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
+            "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
+            "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
+            "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
+            "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
+            "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
+            "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
+            "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
+            "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
+            "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
+            "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
+            "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
+            "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
+            "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
+            "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
+            "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
+            "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
+            "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
+            "Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
+            "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
+            "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
+            "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
+            "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
+            "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
+            "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
+            "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
+            "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
+            "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
+            "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
+            "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
+            "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
+            "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
+            "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
+            "Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
+            "Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
+            "Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
+            "Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
+            "Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
+            "Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
+            "Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
+            "Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
+            "Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
+            "Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
+            "Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
+            "Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
+            "Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
+            "Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
+            "Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
+            "Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
+            "Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
+            "Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
+            "Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
+            "Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
+            "Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
+            "Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
+            "Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
+            "Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
+            "Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
+            "Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
+            "Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
+            "Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
+            "Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
+            "Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
+            "Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
+            "La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
+            "Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
+            "Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
+            "Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
+            "Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
+            "Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
+            "Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
+            "Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
+            "Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
+            "Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
+            "Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
+            "Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
+            "Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
+            "Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
+            "Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
+            "Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
+            "Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
+            "Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
+            "Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
+            "Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
+            "Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
+            "Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
+            "Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
+            "Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
+            "Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
+            "Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
+            "Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
+            "Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
+            "Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
+            "Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
+            "Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
+            "Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
+            "Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
+            "Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
+            "Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
+            "Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
+            "Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
+            "Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
+            "Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
+            "Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
+            "Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
+            "Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
+            "Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
+            "Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
+            "Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
+            "Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
+            "Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
+            "Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
+            "Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
+            "Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
+            "Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
+            "Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
+            "Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
+            "Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
+            "Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
+            "Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
+            "Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
+            "Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
+            "Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
+            "Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
+            "Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
+            "Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
+            "Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"
+    };
+}
\ No newline at end of file
diff --git a/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.java b/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.java
new file mode 100644
index 0000000..13a77f3
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat.listpopupmenu;
+
+import android.os.Bundle;
+import android.support.v7.app.ActionBarActivity;
+
+/**
+ * This sample shows you how to use {@link android.support.v7.widget.PopupMenu PopupMenu} from
+ * ActionBarCompat to create a list, with each item having a dropdown menu.
+ * <p>
+ * The interesting part of this sample is in {@link PopupListFragment}.
+ *
+ * This Activity extends from {@link ActionBarActivity}, which provides all of the function
+ * necessary to display a compatible Action Bar on devices running Android v2.1+.
+ */
+public class MainActivity extends ActionBarActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set content view (which contains a PopupListFragment)
+        setContentView(R.layout.sample_main);
+    }
+
+}
diff --git a/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.java b/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.java
new file mode 100644
index 0000000..754bf22
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.java
@@ -0,0 +1,134 @@
+/*
+ * 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.actionbarcompat.listpopupmenu;
+
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.support.v7.widget.PopupMenu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+
+/**
+ * This ListFragment displays a list of cheeses, with a clickable view on each item whichs displays
+ * a {@link android.support.v7.widget.PopupMenu PopupMenu} when clicked, allowing the user to
+ * remove the item from the list.
+ */
+public class PopupListFragment extends ListFragment implements View.OnClickListener {
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        // We want to allow modifications to the list so copy the dummy data array into an ArrayList
+        ArrayList<String> items = new ArrayList<String>();
+        for (int i = 0, z = Cheeses.CHEESES.length ; i < z ; i++) {
+            items.add(Cheeses.CHEESES[i]);
+        }
+
+        // Set the ListAdapter
+        setListAdapter(new PopupAdapter(items));
+    }
+
+    @Override
+    public void onListItemClick(ListView listView, View v, int position, long id) {
+        String item = (String) listView.getItemAtPosition(position);
+
+        // Show a toast if the user clicks on an item
+        Toast.makeText(getActivity(), "Item Clicked: " + item, Toast.LENGTH_SHORT).show();
+    }
+
+    @Override
+    public void onClick(final View view) {
+        // We need to post a Runnable to show the popup to make sure that the PopupMenu is
+        // correctly positioned. The reason being that the view may change position before the
+        // PopupMenu is shown.
+        view.post(new Runnable() {
+            @Override
+            public void run() {
+                showPopupMenu(view);
+            }
+        });
+    }
+
+    // BEGIN_INCLUDE(show_popup)
+    private void showPopupMenu(View view) {
+        final PopupAdapter adapter = (PopupAdapter) getListAdapter();
+
+        // Retrieve the clicked item from view's tag
+        final String item = (String) view.getTag();
+
+        // Create a PopupMenu, giving it the clicked view for an anchor
+        PopupMenu popup = new PopupMenu(getActivity(), view);
+
+        // Inflate our menu resource into the PopupMenu's Menu
+        popup.getMenuInflater().inflate(R.menu.popup, popup.getMenu());
+
+        // Set a listener so we are notified if a menu item is clicked
+        popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+            @Override
+            public boolean onMenuItemClick(MenuItem menuItem) {
+                switch (menuItem.getItemId()) {
+                    case R.id.menu_remove:
+                        // Remove the item from the adapter
+                        adapter.remove(item);
+                        return true;
+                }
+                return false;
+            }
+        });
+
+        // Finally show the PopupMenu
+        popup.show();
+    }
+    // END_INCLUDE(show_popup)
+
+    /**
+     * A simple array adapter that creates a list of cheeses.
+     */
+    class PopupAdapter extends ArrayAdapter<String> {
+
+        PopupAdapter(ArrayList<String> items) {
+            super(getActivity(), R.layout.list_item, android.R.id.text1, items);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup container) {
+            // Let ArrayAdapter inflate the layout and set the text
+            View view = super.getView(position, convertView, container);
+
+            // BEGIN_INCLUDE(button_popup)
+            // Retrieve the popup button from the inflated view
+            View popupButton = view.findViewById(R.id.button_popup);
+
+            // Set the item as the button's tag so it can be retrieved later
+            popupButton.setTag(getItem(position));
+
+            // Set the fragment instance as the OnClickListener
+            popupButton.setOnClickListener(PopupListFragment.this);
+            // END_INCLUDE(button_popup)
+
+            // Finally return the view to be displayed
+            return view;
+        }
+    }
+
+}
diff --git a/samples/browseable/MediaRecorder/AndroidManifest.xml b/samples/browseable/MediaRecorder/AndroidManifest.xml
new file mode 100644
index 0000000..32f88f6
--- /dev/null
+++ b/samples/browseable/MediaRecorder/AndroidManifest.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.mediarecorder"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="14"
+        android:targetSdkVersion="17" />
+
+    <!-- This app records A/V content from camera and stores it to disk -->
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.RECORD_VIDEO" />
+    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-feature android:name="android.hardware.camera" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme">
+        <!-- Since this sample records video from camera preview, locking the orientation to
+            landscape. Landscape mode offers us more preview space with standard video aspect
+            ratios (width > height) -->
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name"
+            android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/MediaRecorder/_index.jd b/samples/browseable/MediaRecorder/_index.jd
new file mode 100644
index 0000000..dac835a
--- /dev/null
+++ b/samples/browseable/MediaRecorder/_index.jd
@@ -0,0 +1,7 @@
+page.tags="MediaRecorder"
+sample.group=Media
+@jd:body
+
+<p>This sample demonstrates how to use the {@link android.media.MediaRecorder}
+API to record video from a camera or camcorder, and display a preview of the
+recording.</p>
diff --git a/samples/browseable/MediaRecorder/res/drawable-hdpi/ic_launcher.png b/samples/browseable/MediaRecorder/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..13cd1e8
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/MediaRecorder/res/drawable-mdpi/ic_launcher.png b/samples/browseable/MediaRecorder/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..00b2bd9
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/MediaRecorder/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/MediaRecorder/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..953f1cc
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/MediaRecorder/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/MediaRecorder/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f2ccb10
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/MediaRecorder/res/layout/sample_main.xml b/samples/browseable/MediaRecorder/res/layout/sample_main.xml
new file mode 100644
index 0000000..d53b376
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/layout/sample_main.xml
@@ -0,0 +1,24 @@
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:orientation="vertical"
+    tools:context=".MainActivity">
+
+    <TextureView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/surface_view" />
+
+    <Button
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:id="@+id/button_capture"
+            android:layout_gravity="bottom"
+            android:onClick="onCaptureClick"
+            android:text="@string/btnCapture"/>
+</FrameLayout>
diff --git a/samples/browseable/MediaRecorder/res/values-sw720dp-land/dimens.xml b/samples/browseable/MediaRecorder/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..c4aad9b
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+    <!-- Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. -->
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+</resources>
diff --git a/samples/browseable/MediaRecorder/res/values/dimens.xml b/samples/browseable/MediaRecorder/res/values/dimens.xml
new file mode 100644
index 0000000..0353ed6
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/samples/browseable/MediaRecorder/res/values/strings.xml b/samples/browseable/MediaRecorder/res/values/strings.xml
new file mode 100644
index 0000000..b6a2cd2
--- /dev/null
+++ b/samples/browseable/MediaRecorder/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+    <string name="action_settings">Settings</string>
+    <string name="hello_world">Hello world!</string>
+    <string name="btnCapture">capture</string>
+
+</resources>
diff --git a/samples/browseable/MediaRecorder/src/com.example.android.mediarecorder/MainActivity.java b/samples/browseable/MediaRecorder/src/com.example.android.mediarecorder/MainActivity.java
new file mode 100644
index 0000000..8587636
--- /dev/null
+++ b/samples/browseable/MediaRecorder/src/com.example.android.mediarecorder/MainActivity.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.mediarecorder;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.hardware.Camera;
+import android.media.CamcorderProfile;
+import android.media.MediaRecorder;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.TextureView;
+import android.view.View;
+import android.widget.Button;
+
+import com.example.android.common.media.CameraHelper;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ *  This activity uses the camera/camcorder as the A/V source for the {@link android.media.MediaRecorder} API.
+ *  A {@link android.view.TextureView} is used as the camera preview which limits the code to API 14+. This
+ *  can be easily replaced with a {@link android.view.SurfaceView} to run on older devices.
+ */
+public class MainActivity extends Activity {
+
+    private Camera mCamera;
+    private TextureView mPreview;
+    private MediaRecorder mMediaRecorder;
+
+    private boolean isRecording = false;
+    private static final String TAG = "Recorder";
+    private Button captureButton;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+
+        mPreview = (TextureView) findViewById(R.id.surface_view);
+        captureButton = (Button) findViewById(R.id.button_capture);
+    }
+
+    /**
+     * The capture button controls all user interaction. When recording, the button click
+     * stops recording, releases {@link android.media.MediaRecorder} and {@link android.hardware.Camera}. When not recording,
+     * it prepares the {@link android.media.MediaRecorder} and starts recording.
+     *
+     * @param view the view generating the event.
+     */
+    public void onCaptureClick(View view) {
+        if (isRecording) {
+            // BEGIN_INCLUDE(stop_release_media_recorder)
+
+            // stop recording and release camera
+            mMediaRecorder.stop();  // stop the recording
+            releaseMediaRecorder(); // release the MediaRecorder object
+            mCamera.lock();         // take camera access back from MediaRecorder
+
+            // inform the user that recording has stopped
+            setCaptureButtonText("Capture");
+            isRecording = false;
+            releaseCamera();
+            // END_INCLUDE(stop_release_media_recorder)
+
+        } else {
+
+            // BEGIN_INCLUDE(prepare_start_media_recorder)
+
+            new MediaPrepareTask().execute(null, null, null);
+
+            // END_INCLUDE(prepare_start_media_recorder)
+
+        }
+    }
+
+    private void setCaptureButtonText(String title) {
+        captureButton.setText(title);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        // if we are using MediaRecorder, release it first
+        releaseMediaRecorder();
+        // release the camera immediately on pause event
+        releaseCamera();
+    }
+
+    private void releaseMediaRecorder(){
+        if (mMediaRecorder != null) {
+            // clear recorder configuration
+            mMediaRecorder.reset();
+            // release the recorder object
+            mMediaRecorder.release();
+            mMediaRecorder = null;
+            // Lock camera for later use i.e taking it back from MediaRecorder.
+            // MediaRecorder doesn't need it anymore and we will release it if the activity pauses.
+            mCamera.lock();
+        }
+    }
+
+    private void releaseCamera(){
+        if (mCamera != null){
+            // release the camera for other applications
+            mCamera.release();
+            mCamera = null;
+        }
+    }
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    private boolean prepareVideoRecorder(){
+
+        // BEGIN_INCLUDE (configure_preview)
+        mCamera = CameraHelper.getDefaultCameraInstance();
+
+        // We need to make sure that our preview and recording video size are supported by the
+        // camera. Query camera to find all the sizes and choose the optimal size given the
+        // dimensions of our preview surface.
+        Camera.Parameters parameters = mCamera.getParameters();
+        List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
+        Camera.Size optimalSize = CameraHelper.getOptimalPreviewSize(mSupportedPreviewSizes,
+                mPreview.getWidth(), mPreview.getHeight());
+
+        // Use the same size for recording profile.
+        CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
+        profile.videoFrameWidth = optimalSize.width;
+        profile.videoFrameHeight = optimalSize.height;
+
+        // likewise for the camera object itself.
+        parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
+        mCamera.setParameters(parameters);
+        try {
+                // Requires API level 11+, For backward compatibility use {@link setPreviewDisplay}
+                // with {@link SurfaceView}
+                mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
+        } catch (IOException e) {
+            Log.e(TAG, "Surface texture is unavailable or unsuitable" + e.getMessage());
+            return false;
+        }
+        // END_INCLUDE (configure_preview)
+
+
+        // BEGIN_INCLUDE (configure_media_recorder)
+        mMediaRecorder = new MediaRecorder();
+
+        // Step 1: Unlock and set camera to MediaRecorder
+        mCamera.unlock();
+        mMediaRecorder.setCamera(mCamera);
+
+        // Step 2: Set sources
+        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT );
+        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+
+        // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
+        mMediaRecorder.setProfile(profile);
+
+        // Step 4: Set output file
+        mMediaRecorder.setOutputFile(CameraHelper.getOutputMediaFile(
+                CameraHelper.MEDIA_TYPE_VIDEO).toString());
+        // END_INCLUDE (configure_media_recorder)
+
+        // Step 5: Prepare configured MediaRecorder
+        try {
+            mMediaRecorder.prepare();
+        } catch (IllegalStateException e) {
+            Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
+            releaseMediaRecorder();
+            return false;
+        } catch (IOException e) {
+            Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
+            releaseMediaRecorder();
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Asynchronous task for preparing the {@link android.media.MediaRecorder} since it's a long blocking
+     * operation.
+     */
+    class MediaPrepareTask extends AsyncTask<Void, Void, Boolean> {
+
+        @Override
+        protected Boolean doInBackground(Void... voids) {
+            // initialize video camera
+            if (prepareVideoRecorder()) {
+                // Camera is available and unlocked, MediaRecorder is prepared,
+                // now you can start recording
+                mMediaRecorder.start();
+
+                isRecording = true;
+            } else {
+                // prepare didn't work, release the camera
+                releaseMediaRecorder();
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        protected void onPostExecute(Boolean result) {
+            if (!result) {
+                MainActivity.this.finish();
+            }
+            // inform the user that recording has started
+            setCaptureButtonText("Stop");
+
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/samples/browseable/NetworkConnect/AndroidManifest.xml b/samples/browseable/NetworkConnect/AndroidManifest.xml
new file mode 100644
index 0000000..1ae29df
--- /dev/null
+++ b/samples/browseable/NetworkConnect/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.networkconnect"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+    <application
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/Theme.Sample"
+        android:allowBackup="true">
+
+        <activity
+            android:name="com.example.android.networkconnect.MainActivity"
+            android:label="@string/app_name"
+            android:uiOptions="splitActionBarWhenNarrow">
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/samples/browseable/NetworkConnect/_index.jd b/samples/browseable/NetworkConnect/_index.jd
new file mode 100644
index 0000000..eaac884
--- /dev/null
+++ b/samples/browseable/NetworkConnect/_index.jd
@@ -0,0 +1,10 @@
+
+
+
+page.tags="NetworkConnect"
+sample.group=Connectivity
+@jd:body
+
+<p>This sample demonstrates how to connect to the network and fetch raw HTML.
+The sample uses {@link android.os.AsyncTask} to perform the fetch on a
+background thread.</p>
diff --git a/samples/browseable/NetworkConnect/res/drawable-hdpi/ic_launcher.png b/samples/browseable/NetworkConnect/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..22ce606
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/NetworkConnect/res/drawable-hdpi/tile.9.png b/samples/browseable/NetworkConnect/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/NetworkConnect/res/drawable-mdpi/ic_launcher.png b/samples/browseable/NetworkConnect/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..f21e17b
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/NetworkConnect/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/NetworkConnect/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..64b8059
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/NetworkConnect/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/NetworkConnect/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..6b4434a
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/NetworkConnect/res/layout/activity_main.xml b/samples/browseable/NetworkConnect/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/NetworkConnect/res/layout/sample_main.xml b/samples/browseable/NetworkConnect/res/layout/sample_main.xml
new file mode 100755
index 0000000..76fa7d7
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/layout/sample_main.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    <fragment
+        android:name="com.example.android.networkconnect.SimpleTextFragment"
+        android:id="@+id/intro_fragment"
+        android:layout_weight="1"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+    <View
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:background="@android:color/darker_gray"/>
+    <fragment
+        android:name="com.example.android.common.logger.LogFragment"
+        android:id="@+id/log_fragment"
+        android:layout_weight="1"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/samples/browseable/NetworkConnect/res/menu/main.xml b/samples/browseable/NetworkConnect/res/menu/main.xml
new file mode 100644
index 0000000..ef1568f
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/menu/main.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/fetch_action"
+        android:showAsAction="ifRoom|withText"
+        android:title="@string/fetch_text" />
+    <item android:id="@+id/clear_action"
+        android:showAsAction="ifRoom|withText"
+        android:title="@string/clear_text" />
+</menu>
diff --git a/samples/browseable/NetworkConnect/res/values-sw600dp/dimens.xml b/samples/browseable/NetworkConnect/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/NetworkConnect/res/values-sw600dp/styles.xml b/samples/browseable/NetworkConnect/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/NetworkConnect/res/values/base-strings.xml b/samples/browseable/NetworkConnect/res/values/base-strings.xml
new file mode 100644
index 0000000..0248814
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">NetworkConnect</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates how to connect to the network and fetch raw HTML using
+            HttpURLConnection. AsyncTask is used to perform the fetch on a background thread.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/NetworkConnect/res/values/dimens.xml b/samples/browseable/NetworkConnect/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/NetworkConnect/res/values/strings.xml b/samples/browseable/NetworkConnect/res/values/strings.xml
new file mode 100755
index 0000000..1e7915a
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/values/strings.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="welcome_message">Welcome to Network Connect!
+        Click FETCH to fetch the first 500 characters of raw HTML from www.google.com.
+    </string>
+
+    <string name="fetch_text">Fetch</string>
+    <string name="clear_text">Clear</string>
+    <string name="connection_error">Connection error.</string>
+</resources>
diff --git a/samples/browseable/NetworkConnect/res/values/styles.xml b/samples/browseable/NetworkConnect/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/NetworkConnect/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/Log.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogNode.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogView.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/MainActivity.java b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/MainActivity.java
new file mode 100755
index 0000000..3ad4646
--- /dev/null
+++ b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/MainActivity.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.networkconnect;
+
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.util.TypedValue;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+/**
+ * Sample application demonstrating how to connect to the network and fetch raw
+ * HTML. It uses AsyncTask to do the fetch on a background thread. To establish
+ * the network connection, it uses HttpURLConnection.
+ *
+ * This sample uses the logging framework to display log output in the log
+ * fragment (LogFragment).
+ */
+public class MainActivity extends FragmentActivity {
+
+    public static final String TAG = "Network Connect";
+
+    // Reference to the fragment showing events, so we can clear it with a button
+    // as necessary.
+    private LogFragment mLogFragment;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+
+        // Initialize text fragment that displays intro text.
+        SimpleTextFragment introFragment = (SimpleTextFragment)
+                    getSupportFragmentManager().findFragmentById(R.id.intro_fragment);
+        introFragment.setText(R.string.welcome_message);
+        introFragment.getTextView().setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16.0f);
+
+        // Initialize the logging framework.
+        initializeLogging();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            // When the user clicks FETCH, fetch the first 500 characters of
+            // raw HTML from www.google.com.
+            case R.id.fetch_action:
+                new DownloadTask().execute("http://www.google.com");
+                return true;
+            // Clear the log view fragment.
+            case R.id.clear_action:
+              mLogFragment.getLogView().setText("");
+              return true;
+        }
+        return false;
+    }
+
+    /**
+     * Implementation of AsyncTask, to fetch the data in the background away from
+     * the UI thread.
+     */
+    private class DownloadTask extends AsyncTask<String, Void, String> {
+
+        @Override
+        protected String doInBackground(String... urls) {
+            try {
+                return loadFromNetwork(urls[0]);
+            } catch (IOException e) {
+              return getString(R.string.connection_error);
+            }
+        }
+
+        /**
+         * Uses the logging framework to display the output of the fetch
+         * operation in the log fragment.
+         */
+        @Override
+        protected void onPostExecute(String result) {
+          Log.i(TAG, result);
+        }
+    }
+
+    /** Initiates the fetch operation. */
+    private String loadFromNetwork(String urlString) throws IOException {
+        InputStream stream = null;
+        String str ="";
+
+        try {
+            stream = downloadUrl(urlString);
+            str = readIt(stream, 500);
+       } finally {
+           if (stream != null) {
+               stream.close();
+            }
+        }
+        return str;
+    }
+
+    /**
+     * Given a string representation of a URL, sets up a connection and gets
+     * an input stream.
+     * @param urlString A string representation of a URL.
+     * @return An InputStream retrieved from a successful HttpURLConnection.
+     * @throws java.io.IOException
+     */
+    private InputStream downloadUrl(String urlString) throws IOException {
+        // BEGIN_INCLUDE(get_inputstream)
+        URL url = new URL(urlString);
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+        conn.setReadTimeout(10000 /* milliseconds */);
+        conn.setConnectTimeout(15000 /* milliseconds */);
+        conn.setRequestMethod("GET");
+        conn.setDoInput(true);
+        // Start the query
+        conn.connect();
+        InputStream stream = conn.getInputStream();
+        return stream;
+        // END_INCLUDE(get_inputstream)
+    }
+
+    /** Reads an InputStream and converts it to a String.
+     * @param stream InputStream containing HTML from targeted site.
+     * @param len Length of string that this method returns.
+     * @return String concatenated according to len parameter.
+     * @throws java.io.IOException
+     * @throws java.io.UnsupportedEncodingException
+     */
+    private String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
+        Reader reader = null;
+        reader = new InputStreamReader(stream, "UTF-8");
+        char[] buffer = new char[len];
+        reader.read(buffer);
+        return new String(buffer);
+    }
+
+    /** Create a chain of targets that will receive log data */
+    public void initializeLogging() {
+
+        // Using Log, front-end to the logging chain, emulates
+        // android.util.log method signatures.
+
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        // A filter that strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        mLogFragment =
+                (LogFragment) getSupportFragmentManager().findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(mLogFragment.getLogView());
+    }
+}
diff --git a/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.java b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.java
new file mode 100644
index 0000000..3202937
--- /dev/null
+++ b/samples/browseable/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.networkconnect;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Simple fragment containing only a TextView. Used by TextPagerAdapter to create
+ * tutorial-style pages for apps.
+ */
+public class SimpleTextFragment extends Fragment {
+
+    // Contains the text that will be displayed by this Fragment
+    String mText;
+
+    // Contains a resource ID for the text that will be displayed by this fragment.
+    int mTextId = -1;
+
+    // Keys which will be used to store/retrieve text passed in via setArguments.
+    public static final String TEXT_KEY = "text";
+    public static final String TEXT_ID_KEY = "text_id";
+
+    // For situations where the app wants to modify text at Runtime, exposing the TextView.
+    private TextView mTextView;
+
+    public SimpleTextFragment() {
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        // Before initializing the textView, check if any arguments were provided via setArguments.
+        processArguments();
+
+        // Create a new TextView and set its text to whatever was provided.
+        mTextView = new TextView(getActivity());
+        mTextView.setGravity(Gravity.CENTER);
+
+        if (mText != null) {
+            mTextView.setText(mText);
+            Log.i("SimpleTextFragment", mText);
+        }
+        return mTextView;
+    }
+
+    public TextView getTextView() {
+        return mTextView;
+    }
+
+    /**
+     * Changes the text for this TextView, according to the resource ID provided.
+     * @param stringId A resource ID representing the text content for this Fragment's TextView.
+     */
+    public void setText(int stringId) {
+        getTextView().setText(getActivity().getString(stringId));
+    }
+
+    /**
+     * Processes the arguments passed into this Fragment via setArguments method.
+     * Currently the method only looks for text or a textID, nothing else.
+     */
+    public void processArguments() {
+        // For most objects we'd handle the multiple possibilities for initialization variables
+        // as multiple constructors.  For Fragments, however, it's customary to use
+        // setArguments / getArguments.
+        if (getArguments() != null) {
+            Bundle args = getArguments();
+            if (args.containsKey(TEXT_KEY)) {
+                mText = args.getString(TEXT_KEY);
+                Log.d("Constructor", "Added Text.");
+            } else if (args.containsKey(TEXT_ID_KEY)) {
+                mTextId = args.getInt(TEXT_ID_KEY);
+                mText = getString(mTextId);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/ShareActionProvider/AndroidManifest.xml b/samples/browseable/ShareActionProvider/AndroidManifest.xml
new file mode 100644
index 0000000..be1ed49
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.actionbarcompat.shareactionprovider"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!--
+        ActionBarCompat provides an Action Bar from API v7 onwards
+    -->
+    <uses-sdk
+        android:minSdkVersion="7"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/Theme.AppCompat"
+        android:allowBackup="true">
+
+        <activity
+            android:name=".MainActivity">
+            <!-- Launcher Intent filter -->
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <!-- ContentProvider which serves files from this application's asset folder -->
+        <provider
+            android:name=".content.AssetProvider"
+            android:authorities="com.example.android.actionbarcompat.shareactionprovider"
+            android:grantUriPermissions="true"
+            android:exported="true" />
+
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/browseable/ShareActionProvider/_index.jd b/samples/browseable/ShareActionProvider/_index.jd
new file mode 100644
index 0000000..31d855e
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/_index.jd
@@ -0,0 +1,14 @@
+
+
+
+page.tags="ShareActionProvider"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to use a
+context-sensitive {@link android.support.v7.widget.ShareActionProvider} that is
+backward compatible.</p>
+<p>The activity in this sample extends from
+{@link android.support.v7.app.ActionBarActivity}, which provides the
+functionality necessary to display a compatible action bar on devices
+running Android 2.1 and higher.</p>
diff --git a/samples/browseable/ShareActionProvider/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ShareActionProvider/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..48db73f
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ShareActionProvider/res/drawable-hdpi/tile.9.png b/samples/browseable/ShareActionProvider/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ShareActionProvider/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ShareActionProvider/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..674b1ee
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ShareActionProvider/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ShareActionProvider/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e76105d
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..67605d8
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ShareActionProvider/res/layout/activity_main.xml b/samples/browseable/ShareActionProvider/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/ShareActionProvider/res/layout/item_image.xml b/samples/browseable/ShareActionProvider/res/layout/item_image.xml
new file mode 100644
index 0000000..f7940e7
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/layout/item_image.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:scaleType="fitCenter" />
diff --git a/samples/browseable/ShareActionProvider/res/layout/item_text.xml b/samples/browseable/ShareActionProvider/res/layout/item_text.xml
new file mode 100644
index 0000000..00c6a38
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/layout/item_text.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="16dp"
+    android:textAppearance="?android:textAppearanceLarge"
+    android:lineSpacingMultiplier="1.1"
+    android:gravity="center"/>
diff --git a/samples/browseable/ShareActionProvider/res/layout/sample_main.xml b/samples/browseable/ShareActionProvider/res/layout/sample_main.xml
new file mode 100644
index 0000000..902e8ab
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/layout/sample_main.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<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.v4.view.ViewPager
+        android:id="@+id/viewpager"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/intro_message"
+        android:padding="16dp"
+        android:textAppearance="?android:textAppearanceMedium"
+        android:lineSpacingMultiplier="1.1"
+        android:background="#fb3"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/ShareActionProvider/res/menu/main_menu.xml b/samples/browseable/ShareActionProvider/res/menu/main_menu.xml
new file mode 100644
index 0000000..acd2134
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/menu/main_menu.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+  As we're using ActionBarCompat, any action item attributes come from ActionBarCompat's XML
+  namespace instead of the android namespace. Here we've added a new support namespace added to
+  the menu element allowing us to use the 'showAsAction' attribute in a backwards compatible way.
+  Any other action item attributes used should be referenced from this namespace too
+  (actionProviderClass, actionViewClass, actionLayout).
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:support="http://schemas.android.com/apk/res-auto">
+
+    <!--
+      To use ShareActionProvider provided by ActionBarCompat, we reference the class by set the
+      support:actionProviderClass attribute with the full class name of ShareActionProvider.
+    -->
+    <item
+        android:id="@+id/menu_share"
+        android:title="@string/menu_share"
+        support:actionProviderClass="android.support.v7.widget.ShareActionProvider"
+        support:showAsAction="always" />
+
+</menu>
\ No newline at end of file
diff --git a/samples/browseable/ShareActionProvider/res/values-sw600dp/dimens.xml b/samples/browseable/ShareActionProvider/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ShareActionProvider/res/values-sw600dp/styles.xml b/samples/browseable/ShareActionProvider/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/ShareActionProvider/res/values/base-strings.xml b/samples/browseable/ShareActionProvider/res/values/base-strings.xml
new file mode 100644
index 0000000..4ca9558
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">ShareActionProvider</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample shows you how a provide a context-sensitive ShareActionProvider with
+            ActionBarCompat, backwards compatible to API v7.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/ShareActionProvider/res/values/dimens.xml b/samples/browseable/ShareActionProvider/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ShareActionProvider/res/values/strings.xml b/samples/browseable/ShareActionProvider/res/values/strings.xml
new file mode 100644
index 0000000..298596f
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+    <string name="menu_share">Share</string>
+    <string name="quote_1">Expectation is the root of all heartache - William Shakespeare</string>
+    <string name="quote_2">The true sign of intelligence is not knowledge but imagination - Albert
+        Einstein</string>
+    <string name="quote_3">As for me, all I know is that I know nothing - Socrates</string>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/ShareActionProvider/res/values/styles.xml b/samples/browseable/ShareActionProvider/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.java b/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.java
new file mode 100644
index 0000000..b8cc900
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.java
@@ -0,0 +1,202 @@
+/*
+ * 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.actionbarcompat.shareactionprovider;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.widget.ShareActionProvider;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.example.android.actionbarcompat.shareactionprovider.content.ContentItem;
+
+import java.util.ArrayList;
+
+/**
+ * This sample shows you how a provide a {@link ShareActionProvider} with ActionBarCompat,
+ * backwards compatible to API v7.
+ * <p>
+ * The sample contains a {@link ViewPager} which displays content of differing types: image and
+ * text. When a new item is selected in the ViewPager, the ShareActionProvider is updated with
+ * a share intent specific to that content.
+ * <p>
+ * This Activity extends from {@link ActionBarActivity}, which provides all of the function
+ * necessary to display a compatible Action Bar on devices running Android v2.1+.
+ */
+public class MainActivity extends ActionBarActivity {
+
+    // The items to be displayed in the ViewPager
+    private final ArrayList<ContentItem> mItems = getSampleContent();
+
+    // Keep reference to the ShareActionProvider from the menu
+    private ShareActionProvider mShareActionProvider;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set content view (which contains a CheeseListFragment)
+        setContentView(R.layout.sample_main);
+
+        // Retrieve the ViewPager from the content view
+        ViewPager vp = (ViewPager) findViewById(R.id.viewpager);
+
+        // Set an OnPageChangeListener so we are notified when a new item is selected
+        vp.setOnPageChangeListener(mOnPageChangeListener);
+
+        // Finally set the adapter so the ViewPager can display items
+        vp.setAdapter(mPagerAdapter);
+    }
+
+    // BEGIN_INCLUDE(get_sap)
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu resource
+        getMenuInflater().inflate(R.menu.main_menu, menu);
+
+        // Retrieve the share menu item
+        MenuItem shareItem = menu.findItem(R.id.menu_share);
+
+        // Now get the ShareActionProvider from the item
+        mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem);
+
+        return super.onCreateOptionsMenu(menu);
+    }
+    // END_INCLUDE(get_sap)
+
+    /**
+     * A PagerAdapter which instantiates views based on the ContentItem's content type.
+     */
+    private final PagerAdapter mPagerAdapter = new PagerAdapter() {
+        LayoutInflater mInflater;
+
+        @Override
+        public int getCount() {
+            return mItems.size();
+        }
+
+        @Override
+        public boolean isViewFromObject(View view, Object o) {
+            return view == o;
+        }
+
+        @Override
+        public void destroyItem(ViewGroup container, int position, Object object) {
+            // Just remove the view from the ViewPager
+            container.removeView((View) object);
+        }
+
+        @Override
+        public Object instantiateItem(ViewGroup container, int position) {
+            // Ensure that the LayoutInflater is instantiated
+            if (mInflater == null) {
+                mInflater = LayoutInflater.from(MainActivity.this);
+            }
+
+            // Get the item for the requested position
+            final ContentItem item = mItems.get(position);
+
+            // The view we need to inflate changes based on the type of content
+            switch (item.contentType) {
+                case ContentItem.CONTENT_TYPE_TEXT: {
+                    // Inflate item layout for text
+                    TextView tv = (TextView) mInflater
+                            .inflate(R.layout.item_text, container, false);
+
+                    // Set text content using it's resource id
+                    tv.setText(item.contentResourceId);
+
+                    // Add the view to the ViewPager
+                    container.addView(tv);
+                    return tv;
+                }
+                case ContentItem.CONTENT_TYPE_IMAGE: {
+                    // Inflate item layout for images
+                    ImageView iv = (ImageView) mInflater
+                            .inflate(R.layout.item_image, container, false);
+
+                    // Load the image from it's content URI
+                    iv.setImageURI(item.getContentUri());
+
+                    // Add the view to the ViewPager
+                    container.addView(iv);
+                    return iv;
+                }
+            }
+
+            return null;
+        }
+    };
+
+    /**
+     * A OnPageChangeListener used to update the ShareActionProvider's share intent when a new item
+     * is selected in the ViewPager.
+     */
+    private final ViewPager.OnPageChangeListener mOnPageChangeListener
+            = new ViewPager.OnPageChangeListener() {
+
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+            // NO-OP
+        }
+
+        @Override
+        public void onPageSelected(int position) {
+            // BEGIN_INCLUDE(update_sap)
+            if (mShareActionProvider != null) {
+                // Get the currently selected item, and retrieve it's share intent
+                ContentItem item = mItems.get(position);
+                Intent shareIntent = item.getShareIntent(MainActivity.this);
+
+                // Now update the ShareActionProvider with the new share intent
+                mShareActionProvider.setShareIntent(shareIntent);
+            }
+            // END_INCLUDE(update_sap)
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int state) {
+            // NO-OP
+        }
+    };
+
+    /**
+     * @return An ArrayList of ContentItem's to be displayed in this sample
+     */
+    static ArrayList<ContentItem> getSampleContent() {
+        ArrayList<ContentItem> items = new ArrayList<ContentItem>();
+
+        items.add(new ContentItem(ContentItem.CONTENT_TYPE_IMAGE, "photo_1.jpg"));
+        items.add(new ContentItem(ContentItem.CONTENT_TYPE_TEXT, R.string.quote_1));
+        items.add(new ContentItem(ContentItem.CONTENT_TYPE_TEXT, R.string.quote_2));
+        items.add(new ContentItem(ContentItem.CONTENT_TYPE_IMAGE, "photo_2.jpg"));
+        items.add(new ContentItem(ContentItem.CONTENT_TYPE_TEXT, R.string.quote_3));
+        items.add(new ContentItem(ContentItem.CONTENT_TYPE_IMAGE, "photo_3.jpg"));
+
+        return items;
+    }
+
+}
\ No newline at end of file
diff --git a/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.java b/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.java
new file mode 100644
index 0000000..b60f7d7
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.java
@@ -0,0 +1,93 @@
+/*
+ * 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.actionbarcompat.shareactionprovider.content;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * A simple ContentProvider which can serve files from this application's assets. The majority of
+ * functionality is in {@link #openAssetFile(android.net.Uri, String)}.
+ */
+public class AssetProvider extends ContentProvider {
+
+    public static String CONTENT_URI = "com.example.android.actionbarcompat.shareactionprovider";
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        // Do not support delete requests.
+        return 0;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        // Do not support returning the data type
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        // Do not support insert requests.
+        return null;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        // Do not support query requests.
+        return null;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        // Do not support update requests.
+        return 0;
+    }
+
+    @Override
+    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
+        // The asset file name should be the last path segment
+        final String assetName = uri.getLastPathSegment();
+
+        // If the given asset name is empty, throw an exception
+        if (TextUtils.isEmpty(assetName)) {
+            throw new FileNotFoundException();
+        }
+
+        try {
+            // Try and return a file descriptor for the given asset name
+            AssetManager am = getContext().getAssets();
+            return am.openFd(assetName);
+        } catch (IOException e) {
+            e.printStackTrace();
+            return super.openAssetFile(uri, mode);
+        }
+    }
+}
diff --git a/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.java b/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.java
new file mode 100644
index 0000000..756a9e6
--- /dev/null
+++ b/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat.shareactionprovider.content;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.text.TextUtils;
+
+/**
+ * This class encapsulates a content item. Referencing the content's type, and the differing way
+ * to reference the content (asset URI or resource id).
+ */
+public class ContentItem {
+    // Used to signify an image content type
+    public static final int CONTENT_TYPE_IMAGE = 0;
+    // Used to signify a text/string content type
+    public static final int CONTENT_TYPE_TEXT = 1;
+
+    public final int contentType;
+    public final int contentResourceId;
+    public final String contentAssetFilePath;
+
+    /**
+     * Creates a ContentItem with the specified type, referencing a resource id.
+     *
+     * @param type - One of {@link #CONTENT_TYPE_IMAGE} or {@link #CONTENT_TYPE_TEXT}
+     * @param resourceId - Resource ID to use for this item's content
+     */
+    public ContentItem(int type, int resourceId) {
+        contentType = type;
+        contentResourceId = resourceId;
+        contentAssetFilePath = null;
+    }
+
+    /**
+     * Creates a ContentItem with the specified type, referencing an asset file path.
+     *
+     * @param type - One of {@link #CONTENT_TYPE_IMAGE} or {@link #CONTENT_TYPE_TEXT}
+     * @param assetFilePath - File path from the application's asset for this item's content
+     */
+    public ContentItem(int type, String assetFilePath) {
+        contentType = type;
+        contentAssetFilePath = assetFilePath;
+        contentResourceId = 0;
+    }
+
+    /**
+     * @return Uri to the content
+     */
+    public Uri getContentUri() {
+        if (!TextUtils.isEmpty(contentAssetFilePath)) {
+            // If this content has an asset, then return a AssetProvider Uri
+            return Uri.parse("content://" + AssetProvider.CONTENT_URI + "/" + contentAssetFilePath);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns an {@link android.content.Intent} which can be used to share this item's content with other
+     * applications.
+     *
+     * @param context - Context to be used for fetching resources if needed
+     * @return Intent to be given to a ShareActionProvider.
+     */
+    public Intent getShareIntent(Context context) {
+        Intent intent = new Intent(Intent.ACTION_SEND);
+
+        switch (contentType) {
+            case CONTENT_TYPE_IMAGE:
+                intent.setType("image/jpg");
+                // Bundle the asset content uri as the EXTRA_STREAM uri
+                intent.putExtra(Intent.EXTRA_STREAM, getContentUri());
+                break;
+
+            case CONTENT_TYPE_TEXT:
+                intent.setType("text/plain");
+                // Get the string resource and bundle it as an intent extra
+                intent.putExtra(Intent.EXTRA_TEXT, context.getString(contentResourceId));
+                break;
+        }
+
+        return intent;
+    }
+
+}
diff --git a/samples/browseable/StorageClient/AndroidManifest.xml b/samples/browseable/StorageClient/AndroidManifest.xml
new file mode 100644
index 0000000..d35a4ec
--- /dev/null
+++ b/samples/browseable/StorageClient/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.storageclient"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name"
+                  android:uiOptions="splitActionBarWhenNarrow">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+
+</manifest>
diff --git a/samples/browseable/StorageClient/_index.jd b/samples/browseable/StorageClient/_index.jd
new file mode 100644
index 0000000..e81e6b2
--- /dev/null
+++ b/samples/browseable/StorageClient/_index.jd
@@ -0,0 +1,12 @@
+
+
+
+page.tags="StorageClient"
+sample.group=Content
+@jd:body
+
+<p>This sample demonstrates how to use the
+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} intent to let users
+choose a file via the system's file browser. This intent allows a client
+application to access a list of document providers on the device, and choose
+a file from any of them.</p>
diff --git a/samples/browseable/StorageClient/res/drawable-hdpi/ic_launcher.png b/samples/browseable/StorageClient/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/StorageClient/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/StorageClient/res/drawable-hdpi/tile.9.png b/samples/browseable/StorageClient/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/StorageClient/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/StorageClient/res/drawable-mdpi/ic_launcher.png b/samples/browseable/StorageClient/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/StorageClient/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/StorageClient/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/StorageClient/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/StorageClient/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/StorageClient/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/StorageClient/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/StorageClient/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/StorageClient/res/layout/activity_main.xml b/samples/browseable/StorageClient/res/layout/activity_main.xml
new file mode 100755
index 0000000..bc5a575
--- /dev/null
+++ b/samples/browseable/StorageClient/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:id="@+id/sample_main_layout">
+    <TextView android:id="@+id/sample_output"
+              style="@style/Widget.SampleMessage"
+              android:layout_weight="1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:text="@string/intro_message" />
+    <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:background="@android:color/darker_gray"/>
+    <fragment
+            android:name="com.example.android.common.logger.LogFragment"
+            android:id="@+id/log_fragment"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/samples/browseable/StorageClient/res/menu/main.xml b/samples/browseable/StorageClient/res/menu/main.xml
new file mode 100644
index 0000000..2c3515d
--- /dev/null
+++ b/samples/browseable/StorageClient/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/sample_action"
+          android:showAsAction="ifRoom|withText"
+          android:title="@string/sample_action" />
+</menu>
diff --git a/samples/browseable/StorageClient/res/values-sw600dp/dimens.xml b/samples/browseable/StorageClient/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/StorageClient/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/StorageClient/res/values-sw600dp/styles.xml b/samples/browseable/StorageClient/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/StorageClient/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/StorageClient/res/values/base-strings.xml b/samples/browseable/StorageClient/res/values/base-strings.xml
new file mode 100644
index 0000000..9498a2d
--- /dev/null
+++ b/samples/browseable/StorageClient/res/values/base-strings.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">StorageClient</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            Using the OPEN_DOCUMENT intent, a client app can access a list of Document Providers
+            on the device, and choose a file from any of them.
+            \n\nTo demonstrate this, click the button below to open up the Storage Access Framework
+            interface, and choose an image on your device.  It will be displayed in this app.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/StorageClient/res/values/dimens.xml b/samples/browseable/StorageClient/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/StorageClient/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/StorageClient/res/values/strings.xml b/samples/browseable/StorageClient/res/values/strings.xml
new file mode 100644
index 0000000..303776f
--- /dev/null
+++ b/samples/browseable/StorageClient/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+        <string name="sample_action">Show Me The Image</string>
+</resources>
diff --git a/samples/browseable/StorageClient/res/values/styles.xml b/samples/browseable/StorageClient/res/values/styles.xml
new file mode 100644
index 0000000..d3f82ff
--- /dev/null
+++ b/samples/browseable/StorageClient/res/values/styles.xml
@@ -0,0 +1,51 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="AppTheme" parent="Theme.Base" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+
+    <style name="Widget.SampleOutput">
+        <item name="android:padding">@dimen/margin_medium</item>
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Log" parent="Widget.SampleOutput">
+        <item name="android:typeface">monospace</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/StorageClient/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/StorageClient/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/StorageClient/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+    public static final String TAG = "SampleActivityBase";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected  void onStart() {
+        super.onStart();
+        initializeLogging();
+    }
+
+    /** Set up targets to receive log data */
+    public void initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/StorageClient/src/com.example.android.common/logger/Log.java b/samples/browseable/StorageClient/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/StorageClient/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/StorageClient/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/StorageClient/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/StorageClient/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/StorageClient/src/com.example.android.common/logger/LogNode.java b/samples/browseable/StorageClient/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/StorageClient/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/StorageClient/src/com.example.android.common/logger/LogView.java b/samples/browseable/StorageClient/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/StorageClient/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/StorageClient/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/StorageClient/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/StorageClient/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/StorageClient/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/StorageClient/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/StorageClient/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/StorageClient/src/com.example.android.storageclient/MainActivity.java b/samples/browseable/StorageClient/src/com.example.android.storageclient/MainActivity.java
new file mode 100644
index 0000000..69c75eb
--- /dev/null
+++ b/samples/browseable/StorageClient/src/com.example.android.storageclient/MainActivity.java
@@ -0,0 +1,80 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+
+
+package com.example.android.storageclient;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description
+ * and a few action bar buttons.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    public static final String FRAGTAG = "StorageClientFragment";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        if (getSupportFragmentManager().findFragmentByTag(FRAGTAG) == null ) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            StorageClientFragment fragment = new StorageClientFragment();
+            transaction.add(fragment, FRAGTAG);
+            transaction.commit();
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/StorageClient/src/com.example.android.storageclient/StorageClientFragment.java b/samples/browseable/StorageClient/src/com.example.android.storageclient/StorageClientFragment.java
new file mode 100644
index 0000000..7f9f73e
--- /dev/null
+++ b/samples/browseable/StorageClient/src/com.example.android.storageclient/StorageClientFragment.java
@@ -0,0 +1,255 @@
+/*
+* Copyright (C) 2012 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.storageclient;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.provider.OpenableColumns;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.view.MenuItem;
+import android.view.Window;
+import android.widget.ImageView;
+
+import com.example.android.common.logger.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+public class StorageClientFragment extends Fragment {
+
+    // A request code's purpose is to match the result of a "startActivityForResult" with
+    // the type of the original request.  Choose any value.
+    private static final int READ_REQUEST_CODE = 1337;
+
+    public static final String TAG = "StorageClientFragment";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.sample_action) {
+            performFileSearch();
+        }
+        return true;
+    }
+
+    /**
+     * Fires an intent to spin up the "file chooser" UI and select an image.
+     */
+    public void performFileSearch() {
+
+        // BEGIN_INCLUDE (use_open_document_intent)
+        // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file browser.
+        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+
+        // Filter to only show results that can be "opened", such as a file (as opposed to a list
+        // of contacts or timezones)
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+
+        // Filter to show only images, using the image MIME data type.
+        // If one wanted to search for ogg vorbis files, the type would be "audio/ogg".
+        // To search for all documents available via installed storage providers, it would be
+        // "*/*".
+        intent.setType("image/*");
+
+        startActivityForResult(intent, READ_REQUEST_CODE);
+        // END_INCLUDE (use_open_document_intent)
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
+        Log.i(TAG, "Received an \"Activity Result\"");
+        // BEGIN_INCLUDE (parse_open_document_response)
+        // The ACTION_OPEN_DOCUMENT intent was sent with the request code READ_REQUEST_CODE.
+        // If the request code seen here doesn't match, it's the response to some other intent,
+        // and the below code shouldn't run at all.
+
+        if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
+            // The document selected by the user won't be returned in the intent.
+            // Instead, a URI to that document will be contained in the return intent
+            // provided to this method as a parameter.  Pull that uri using "resultData.getData()"
+            Uri uri = null;
+            if (resultData != null) {
+                uri = resultData.getData();
+                Log.i(TAG, "Uri: " + uri.toString());
+                showImage(uri);
+            }
+            // END_INCLUDE (parse_open_document_response)
+        }
+    }
+
+    /**
+     * Given the URI of an image, shows it on the screen using a DialogFragment.
+     *
+     * @param uri the Uri of the image to display.
+     */
+    public void showImage(Uri uri) {
+        // BEGIN_INCLUDE (create_show_image_dialog)
+        if (uri != null) {
+            // Since the URI is to an image, create and show a DialogFragment to display the
+            // image to the user.
+            FragmentManager fm = getActivity().getSupportFragmentManager();
+            ImageDialogFragment imageDialog = new ImageDialogFragment(uri);
+            imageDialog.show(fm, "image_dialog");
+        }
+        // END_INCLUDE (create_show_image_dialog)
+    }
+
+    /**
+     * Grabs metadata for a document specified by URI, logs it to the screen.
+     *
+     * @param uri The uri for the document whose metadata should be printed.
+     */
+    public void dumpImageMetaData(Uri uri) {
+        // BEGIN_INCLUDE (dump_metadata)
+
+        // The query, since it only applies to a single document, will only return one row.
+        // no need to filter, sort, or select fields, since we want all fields for one
+        // document.
+        Cursor cursor = getActivity().getContentResolver()
+                .query(uri, null, null, null, null, null);
+
+        try {
+        // moveToFirst() returns false if the cursor has 0 rows.  Very handy for
+        // "if there's anything to look at, look at it" conditionals.
+            if (cursor != null && cursor.moveToFirst()) {
+
+                // Note it's called "Display Name".  This is provider-specific, and
+                // might not necessarily be the file name.
+                String displayName = cursor.getString(
+                        cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
+                Log.i(TAG, "Display Name: " + displayName);
+
+                int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
+                // If the size is unknown, the value stored is null.  But since an int can't be
+                // null in java, the behavior is implementation-specific, which is just a fancy
+                // term for "unpredictable".  So as a rule, check if it's null before assigning
+                // to an int.  This will happen often:  The storage API allows for remote
+                // files, whose size might not be locally known.
+                String size = null;
+                if (!cursor.isNull(sizeIndex)) {
+                    // Technically the column stores an int, but cursor.getString will do the
+                    // conversion automatically.
+                    size = cursor.getString(sizeIndex);
+                } else {
+                    size = "Unknown";
+                }
+                Log.i(TAG, "Size: " + size);
+            }
+        } finally {
+            cursor.close();
+        }
+        // END_INCLUDE (dump_metadata)
+    }
+
+    /**
+     * DialogFragment which displays an image, given a URI.
+     */
+    private class ImageDialogFragment extends DialogFragment {
+        private Dialog mDialog;
+        private Uri mUri;
+
+        public ImageDialogFragment(Uri uri) {
+            super();
+            mUri = uri;
+        }
+
+        /** Create a Bitmap from the URI for that image and return it.
+         *
+         * @param uri the Uri for the image to return.
+         */
+        private Bitmap getBitmapFromUri(Uri uri) {
+            ParcelFileDescriptor parcelFileDescriptor = null;
+            try {
+                parcelFileDescriptor =
+                        getActivity().getContentResolver().openFileDescriptor(uri, "r");
+                FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
+                Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
+                parcelFileDescriptor.close();
+                return image;
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to load image.", e);
+                return null;
+            } finally {
+                try {
+                    if (parcelFileDescriptor != null) {
+                        parcelFileDescriptor.close();
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    Log.e(TAG, "Error closing ParcelFile Descriptor");
+                }
+            }
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            mDialog = super.onCreateDialog(savedInstanceState);
+            // To optimize for the "lightbox" style layout.  Since we're not actually displaying a
+            // title, remove the bar along the top of the fragment where a dialog title would
+            // normally go.
+            mDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+            final ImageView imageView = new ImageView(getActivity());
+            mDialog.setContentView(imageView);
+
+            // BEGIN_INCLUDE (show_image)
+            // Loading the image is going to require some sort of I/O, which must occur off the UI
+            // thread.  Changing the ImageView to display the image must occur ON the UI thread.
+            // The easiest way to divide up this labor is with an AsyncTask.  The doInBackground
+            // method will run in a separate thread, but onPostExecute will run in the main
+            // UI thread.
+            AsyncTask<Uri, Void, Bitmap> imageLoadAsyncTask = new AsyncTask<Uri, Void, Bitmap>() {
+                @Override
+                protected Bitmap doInBackground(Uri... uris) {
+                    dumpImageMetaData(uris[0]);
+                    return getBitmapFromUri(uris[0]);
+                }
+
+                @Override
+                protected void onPostExecute(Bitmap bitmap) {
+                    imageView.setImageBitmap(bitmap);
+                }
+            };
+            imageLoadAsyncTask.execute(mUri);
+            // END_INCLUDE (show_image)
+
+            return mDialog;
+        }
+
+        @Override
+        public void onStop() {
+            super.onStop();
+            if (getDialog() != null) {
+                getDialog().dismiss();
+            }
+        }
+    }
+}
diff --git a/samples/browseable/StorageProvider/AndroidManifest.xml b/samples/browseable/StorageProvider/AndroidManifest.xml
new file mode 100644
index 0000000..e4704dc
--- /dev/null
+++ b/samples/browseable/StorageProvider/AndroidManifest.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.example.android.storageprovider"
+          android:versionCode="1"
+          android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="19"
+        android:targetSdkVersion="19"/>
+
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+    <application
+        android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/MyAppTheme">
+
+        <activity
+            android:name=".MainActivity"
+            android:uiOptions="splitActionBarWhenNarrow"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
+        <!--BEGIN_INCLUDE(provider_manifest)-->
+        <!--
+        Declare the document provider class MyCloudProvider to the system.  The MANAGE_DOCUMENTS
+        permission belongs only to the Android system, ensuring this provider will never be used
+        directly by another app.  The provider must grant URI permissions in order to expose the
+        specific documents(s) chosen, while not sharing all of its data by default.  It must be
+        exported to be visible outside the application, and it must include a filter with the intent
+        "android.content.action.DOCUMENTS_PROVIDER" in order to be shown in the system document
+        picker UI.
+        -->
+        <provider
+            android:name="com.example.android.storageprovider.MyCloudProvider"
+            android:authorities="com.example.android.storageprovider.documents"
+            android:grantUriPermissions="true"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_DOCUMENTS">
+            <intent-filter>
+                <action android:name="android.content.action.DOCUMENTS_PROVIDER"/>
+            </intent-filter>
+        </provider>
+        <!--END_INCLUDE(provider_manifest)-->
+
+    </application>
+
+</manifest>
diff --git a/samples/browseable/StorageProvider/_index.jd b/samples/browseable/StorageProvider/_index.jd
new file mode 100644
index 0000000..562a832
--- /dev/null
+++ b/samples/browseable/StorageProvider/_index.jd
@@ -0,0 +1,7 @@
+page.tags="Storage access framework", storage, documents
+sample.group=Content
+@jd:body
+
+<p>This sample demonstrates how to use the
+{@link android.provider.DocumentsProvider} API to manage documents and
+expose them to the Android system for sharing.</p>
diff --git a/samples/browseable/StorageProvider/res/drawable-hdpi/ic_launcher.png b/samples/browseable/StorageProvider/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..c5d6972
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/drawable-hdpi/tile.9.png b/samples/browseable/StorageProvider/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/drawable-mdpi/ic_launcher.png b/samples/browseable/StorageProvider/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..59e6bd9
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/StorageProvider/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..5b8b7be
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/StorageProvider/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..474bbd2
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/ic_launcher.png b/samples/browseable/StorageProvider/res/ic_launcher.png
new file mode 100755
index 0000000..c5d6972
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/layout/activity_main.xml b/samples/browseable/StorageProvider/res/layout/activity_main.xml
new file mode 100755
index 0000000..bc5a575
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:id="@+id/sample_main_layout">
+    <TextView android:id="@+id/sample_output"
+              style="@style/Widget.SampleMessage"
+              android:layout_weight="1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:text="@string/intro_message" />
+    <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:background="@android:color/darker_gray"/>
+    <fragment
+            android:name="com.example.android.common.logger.LogFragment"
+            android:id="@+id/log_fragment"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/samples/browseable/StorageProvider/res/menu/main.xml b/samples/browseable/StorageProvider/res/menu/main.xml
new file mode 100644
index 0000000..2c3515d
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/sample_action"
+          android:showAsAction="ifRoom|withText"
+          android:title="@string/sample_action" />
+</menu>
diff --git a/samples/browseable/StorageProvider/res/raw/android_computer_android_studio.jpg b/samples/browseable/StorageProvider/res/raw/android_computer_android_studio.jpg
new file mode 100755
index 0000000..b916136
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/raw/android_computer_android_studio.jpg
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/raw/android_computer_back.jpg b/samples/browseable/StorageProvider/res/raw/android_computer_back.jpg
new file mode 100755
index 0000000..4ba4929
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/raw/android_computer_back.jpg
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/raw/android_dinner.jpg b/samples/browseable/StorageProvider/res/raw/android_dinner.jpg
new file mode 100755
index 0000000..6c5491f
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/raw/android_dinner.jpg
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/raw/android_pumpkins_fall.jpg b/samples/browseable/StorageProvider/res/raw/android_pumpkins_fall.jpg
new file mode 100755
index 0000000..6111f32
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/raw/android_pumpkins_fall.jpg
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/raw/android_rose.jpg b/samples/browseable/StorageProvider/res/raw/android_rose.jpg
new file mode 100755
index 0000000..396eb90
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/raw/android_rose.jpg
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/raw/cat_names.txt b/samples/browseable/StorageProvider/res/raw/cat_names.txt
new file mode 100644
index 0000000..b67570b
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/raw/cat_names.txt
@@ -0,0 +1,17 @@
+Top cat names of 2013
+
+1. Angel
+2. Charlie
+3. Mittens
+4. Milkshake
+5. Oreo
+6. Ella
+7. Lily
+8. Ellie
+9. Pepsi
+10. Amber
+11. Molly
+12. Truffles
+13. Peanut
+14. Tiger Lilly
+15. Snowball
\ No newline at end of file
diff --git a/samples/browseable/StorageProvider/res/raw/dog_names.txt b/samples/browseable/StorageProvider/res/raw/dog_names.txt
new file mode 100644
index 0000000..ca43dd6
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/raw/dog_names.txt
@@ -0,0 +1,17 @@
+Top dog names of 2013
+
+1. Gus
+2. Trapper
+3. Finn
+4. Bailey
+5. Cooper
+6. Hawkeye
+7. Wrigley
+8. Boomer
+9. Ace
+10. Butch
+11. Delgado
+12. Evan
+13. Lucky
+14. Otto
+15. Buddy
\ No newline at end of file
diff --git a/samples/browseable/StorageProvider/res/raw/example.docx b/samples/browseable/StorageProvider/res/raw/example.docx
new file mode 100644
index 0000000..1f6e016
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/raw/example.docx
Binary files differ
diff --git a/samples/browseable/StorageProvider/res/values-sw600dp/template-dimens.xml b/samples/browseable/StorageProvider/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/StorageProvider/res/values-sw600dp/template-styles.xml b/samples/browseable/StorageProvider/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/StorageProvider/res/values/app_strings.xml b/samples/browseable/StorageProvider/res/values/app_strings.xml
new file mode 100644
index 0000000..fa60e14
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/values/app_strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+
+<resources>
+    <string name="log_in">Log in</string>
+    <string name="log_out">Log out</string>
+    <string name="logged_in_info">You are currently logged in, which means the documents in MyCloud are visible to other applications.</string>
+    <string name="logged_out_info">You are currently logged out, so MyCloud is not visible as a document provider.</string>
+    <string name="root_summary">cloudy with a chance of &#8230;</string>
+    <string name="key_logged_in">logged_in</string>
+</resources>
diff --git a/samples/browseable/StorageProvider/res/values/arrays.xml b/samples/browseable/StorageProvider/res/values/arrays.xml
new file mode 100644
index 0000000..b79a5a9
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/values/arrays.xml
@@ -0,0 +1,34 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+    <array name="image_res_ids">
+        <item>@raw/android_dinner</item>
+        <item>@raw/android_rose</item>
+        <item>@raw/android_pumpkins_fall</item>
+        <item>@raw/android_computer_back</item>
+        <item>@raw/android_computer_android_studio</item>
+    </array>
+
+    <array name="text_res_ids">
+        <item>@raw/cat_names</item>
+        <item>@raw/dog_names</item>
+    </array>
+
+    <array name="docx_res_ids">
+        <item>@raw/example</item>
+    </array>
+</resources>
diff --git a/samples/browseable/StorageProvider/res/values/base-strings.xml b/samples/browseable/StorageProvider/res/values/base-strings.xml
new file mode 100644
index 0000000..d3674af
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">MyCloud</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            \nA simple implementation of a documents provider using the storage access framework in
+            Android 4.4.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/StorageProvider/res/values/strings.xml b/samples/browseable/StorageProvider/res/values/strings.xml
new file mode 100644
index 0000000..df03273
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+        <string name="sample_action">Log in</string>
+</resources>
diff --git a/samples/browseable/StorageProvider/res/values/styles.xml b/samples/browseable/StorageProvider/res/values/styles.xml
new file mode 100644
index 0000000..b325e36
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/values/styles.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+    <style name="MyAppTheme" parent="AppTheme">
+        <item name="android:textViewStyle">@style/MyTextViewStyle</item>
+        <item name="android:actionBarStyle">@style/MyActionBarStyle</item>
+        <item name="android:actionMenuTextColor">@android:color/white</item>
+    </style>
+
+    <style name="MyActionBarStyle" parent="android:Widget.Holo.Light.ActionBar.Solid.Inverse">
+        <item name="android:background">#5E2D79</item>
+        <item name="android:backgroundSplit">#5E2D79</item>
+    </style>
+
+    <style name="MyTextViewStyle" parent="android:TextAppearance.Holo.Widget.TextView">
+        <item name="android:textSize">18sp</item>
+        <item name="android:paddingRight">@dimen/margin_medium</item>
+        <item name="android:paddingLeft">@dimen/margin_medium</item>
+        <item name="android:fontFamily">sans-serif-light</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/StorageProvider/res/values/template-dimens.xml b/samples/browseable/StorageProvider/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/StorageProvider/res/values/template-styles.xml b/samples/browseable/StorageProvider/res/values/template-styles.xml
new file mode 100644
index 0000000..d3f82ff
--- /dev/null
+++ b/samples/browseable/StorageProvider/res/values/template-styles.xml
@@ -0,0 +1,51 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="AppTheme" parent="Theme.Base" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+
+    <style name="Widget.SampleOutput">
+        <item name="android:padding">@dimen/margin_medium</item>
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Log" parent="Widget.SampleOutput">
+        <item name="android:typeface">monospace</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/StorageProvider/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/StorageProvider/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/StorageProvider/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+    public static final String TAG = "SampleActivityBase";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected  void onStart() {
+        super.onStart();
+        initializeLogging();
+    }
+
+    /** Set up targets to receive log data */
+    public void initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/StorageProvider/src/com.example.android.common/logger/Log.java b/samples/browseable/StorageProvider/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/StorageProvider/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogNode.java b/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogView.java b/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/StorageProvider/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/StorageProvider/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/StorageProvider/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/StorageProvider/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MainActivity.java b/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MainActivity.java
new file mode 100644
index 0000000..5f04a62
--- /dev/null
+++ b/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MainActivity.java
@@ -0,0 +1,80 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+
+
+package com.example.android.storageprovider;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description
+ * and a few action bar buttons.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    public static final String FRAGTAG = "MyCloudFragment";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        if (getSupportFragmentManager().findFragmentByTag(FRAGTAG) == null ) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            MyCloudFragment fragment = new MyCloudFragment();
+            transaction.add(fragment, FRAGTAG);
+            transaction.commit();
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MyCloudFragment.java b/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MyCloudFragment.java
new file mode 100644
index 0000000..f624e90
--- /dev/null
+++ b/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MyCloudFragment.java
@@ -0,0 +1,105 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+package com.example.android.storageprovider;
+
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.support.v4.app.Fragment;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.example.android.common.logger.Log;
+
+/**
+ * Toggles the user's login status via a login menu option, and enables/disables the cloud storage
+ * content provider.
+ */
+public class MyCloudFragment extends Fragment {
+
+    private static final String TAG = "MyCloudFragment";
+    private static final String AUTHORITY = "com.example.android.storageprovider.documents";
+    private boolean mLoggedIn = false;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mLoggedIn = readLoginValue();
+
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
+        MenuItem item = menu.findItem(R.id.sample_action);
+        item.setTitle(mLoggedIn ? R.string.log_out : R.string.log_in);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.sample_action) {
+            toggleLogin();
+            item.setTitle(mLoggedIn ? R.string.log_out : R.string.log_in);
+
+            // BEGIN_INCLUDE(notify_change)
+            // Notify the system that the status of our roots has changed.  This will trigger
+            // a call to MyCloudProvider.queryRoots() and force a refresh of the system
+            // picker UI.  It's important to call this or stale results may persist.
+            getActivity().getContentResolver().notifyChange(DocumentsContract.buildRootsUri
+                    (AUTHORITY), null, false);
+            // END_INCLUDE(notify_change)
+        }
+        return true;
+    }
+
+    /**
+     * Dummy function to change the user's authorization status.
+     */
+    private void toggleLogin() {
+        // Replace this with your standard method of authentication to determine if your app
+        // should make the user's documents available.
+        mLoggedIn = !mLoggedIn;
+        writeLoginValue(mLoggedIn);
+        Log.i(TAG, getString(mLoggedIn ? R.string.logged_in_info : R.string.logged_out_info));
+    }
+
+    /**
+     * Dummy function to save whether the user is logged in.
+     */
+    private void writeLoginValue(boolean loggedIn) {
+        final SharedPreferences sharedPreferences =
+                getActivity().getSharedPreferences(getString(R.string.app_name),
+                        getActivity().MODE_PRIVATE);
+        sharedPreferences.edit().putBoolean(getString(R.string.key_logged_in), loggedIn).commit();
+    }
+
+    /**
+     * Dummy function to determine whether the user is logged in.
+     */
+    private boolean readLoginValue() {
+        final SharedPreferences sharedPreferences =
+                getActivity().getSharedPreferences(getString(R.string.app_name),
+                        getActivity().MODE_PRIVATE);
+        return sharedPreferences.getBoolean(getString(R.string.key_logged_in), false);
+    }
+
+}
+
+
diff --git a/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MyCloudProvider.java b/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MyCloudProvider.java
new file mode 100644
index 0000000..d8be813
--- /dev/null
+++ b/samples/browseable/StorageProvider/src/com.example.android.storageprovider/MyCloudProvider.java
@@ -0,0 +1,621 @@
+/*
+ * 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.storageprovider;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.TypedArray;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.graphics.Point;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsProvider;
+import android.webkit.MimeTypeMap;
+
+import com.example.android.common.logger.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.PriorityQueue;
+import java.util.Set;
+
+/**
+ * Manages documents and exposes them to the Android system for sharing.
+ */
+public class MyCloudProvider extends DocumentsProvider {
+    private static final String TAG = MyCloudProvider.class.getSimpleName();
+
+    // Use these as the default columns to return information about a root if no specific
+    // columns are requested in a query.
+    private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{
+            Root.COLUMN_ROOT_ID,
+            Root.COLUMN_MIME_TYPES,
+            Root.COLUMN_FLAGS,
+            Root.COLUMN_ICON,
+            Root.COLUMN_TITLE,
+            Root.COLUMN_SUMMARY,
+            Root.COLUMN_DOCUMENT_ID,
+            Root.COLUMN_AVAILABLE_BYTES
+    };
+
+    // Use these as the default columns to return information about a document if no specific
+    // columns are requested in a query.
+    private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[]{
+            Document.COLUMN_DOCUMENT_ID,
+            Document.COLUMN_MIME_TYPE,
+            Document.COLUMN_DISPLAY_NAME,
+            Document.COLUMN_LAST_MODIFIED,
+            Document.COLUMN_FLAGS,
+            Document.COLUMN_SIZE
+    };
+
+    // No official policy on how many to return, but make sure you do limit the number of recent
+    // and search results.
+    private static final int MAX_SEARCH_RESULTS = 20;
+    private static final int MAX_LAST_MODIFIED = 5;
+
+    private static final String ROOT = "root";
+
+    // A file object at the root of the file hierarchy.  Depending on your implementation, the root
+    // does not need to be an existing file system directory.  For example, a tag-based document
+    // provider might return a directory containing all tags, represented as child directories.
+    private File mBaseDir;
+
+    @Override
+    public boolean onCreate() {
+        Log.v(TAG, "onCreate");
+
+        mBaseDir = getContext().getFilesDir();
+
+        writeDummyFilesToStorage();
+
+        return true;
+    }
+
+    // BEGIN_INCLUDE(query_roots)
+    @Override
+    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+        Log.v(TAG, "queryRoots");
+
+        // Create a cursor with either the requested fields, or the default projection.  This
+        // cursor is returned to the Android system picker UI and used to display all roots from
+        // this provider.
+        final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
+
+        // If user is not logged in, return an empty root cursor.  This removes our provider from
+        // the list entirely.
+        if (!isUserLoggedIn()) {
+            return result;
+        }
+
+        // It's possible to have multiple roots (e.g. for multiple accounts in the same app) -
+        // just add multiple cursor rows.
+        // Construct one row for a root called "MyCloud".
+        final MatrixCursor.RowBuilder row = result.newRow();
+
+        row.add(Root.COLUMN_ROOT_ID, ROOT);
+        row.add(Root.COLUMN_SUMMARY, getContext().getString(R.string.root_summary));
+
+        // FLAG_SUPPORTS_CREATE means at least one directory under the root supports creating
+        // documents.  FLAG_SUPPORTS_RECENTS means your application's most recently used
+        // documents will show up in the "Recents" category.  FLAG_SUPPORTS_SEARCH allows users
+        // to search all documents the application shares.
+        row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE |
+                Root.FLAG_SUPPORTS_RECENTS |
+                Root.FLAG_SUPPORTS_SEARCH);
+
+        // COLUMN_TITLE is the root title (e.g. what will be displayed to identify your provider).
+        row.add(Root.COLUMN_TITLE, getContext().getString(R.string.app_name));
+
+        // This document id must be unique within this provider and consistent across time.  The
+        // system picker UI may save it and refer to it later.
+        row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(mBaseDir));
+
+        // The child MIME types are used to filter the roots and only present to the user roots
+        // that contain the desired type somewhere in their file hierarchy.
+        row.add(Root.COLUMN_MIME_TYPES, getChildMimeTypes(mBaseDir));
+        row.add(Root.COLUMN_AVAILABLE_BYTES, mBaseDir.getFreeSpace());
+        row.add(Root.COLUMN_ICON, R.drawable.ic_launcher);
+
+        return result;
+    }
+    // END_INCLUDE(query_roots)
+
+    // BEGIN_INCLUDE(query_recent_documents)
+    @Override
+    public Cursor queryRecentDocuments(String rootId, String[] projection)
+            throws FileNotFoundException {
+        Log.v(TAG, "queryRecentDocuments");
+
+        // This example implementation walks a local file structure to find the most recently
+        // modified files.  Other implementations might include making a network call to query a
+        // server.
+
+        // Create a cursor with the requested projection, or the default projection.
+        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+
+        final File parent = getFileForDocId(rootId);
+
+        // Create a queue to store the most recent documents, which orders by last modified.
+        PriorityQueue<File> lastModifiedFiles = new PriorityQueue<File>(5, new Comparator<File>() {
+            public int compare(File i, File j) {
+                return Long.compare(i.lastModified(), j.lastModified());
+            }
+        });
+
+        // Iterate through all files and directories in the file structure under the root.  If
+        // the file is more recent than the least recently modified, add it to the queue,
+        // limiting the number of results.
+        final LinkedList<File> pending = new LinkedList<File>();
+
+        // Start by adding the parent to the list of files to be processed
+        pending.add(parent);
+
+        // Do while we still have unexamined files
+        while (!pending.isEmpty()) {
+            // Take a file from the list of unprocessed files
+            final File file = pending.removeFirst();
+            if (file.isDirectory()) {
+                // If it's a directory, add all its children to the unprocessed list
+                Collections.addAll(pending, file.listFiles());
+            } else {
+                // If it's a file, add it to the ordered queue.
+                lastModifiedFiles.add(file);
+            }
+        }
+
+        // Add the most recent files to the cursor, not exceeding the max number of results.
+        for (int i = 0; i < Math.min(MAX_LAST_MODIFIED + 1, lastModifiedFiles.size()); i++) {
+            final File file = lastModifiedFiles.remove();
+            includeFile(result, null, file);
+        }
+        return result;
+    }
+    // END_INCLUDE(query_recent_documents)
+
+    // BEGIN_INCLUDE(query_search_documents)
+    @Override
+    public Cursor querySearchDocuments(String rootId, String query, String[] projection)
+            throws FileNotFoundException {
+        Log.v(TAG, "querySearchDocuments");
+
+        // Create a cursor with the requested projection, or the default projection.
+        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+        final File parent = getFileForDocId(rootId);
+
+        // This example implementation searches file names for the query and doesn't rank search
+        // results, so we can stop as soon as we find a sufficient number of matches.  Other
+        // implementations might use other data about files, rather than the file name, to
+        // produce a match; it might also require a network call to query a remote server.
+
+        // Iterate through all files in the file structure under the root until we reach the
+        // desired number of matches.
+        final LinkedList<File> pending = new LinkedList<File>();
+
+        // Start by adding the parent to the list of files to be processed
+        pending.add(parent);
+
+        // Do while we still have unexamined files, and fewer than the max search results
+        while (!pending.isEmpty() && result.getCount() < MAX_SEARCH_RESULTS) {
+            // Take a file from the list of unprocessed files
+            final File file = pending.removeFirst();
+            if (file.isDirectory()) {
+                // If it's a directory, add all its children to the unprocessed list
+                Collections.addAll(pending, file.listFiles());
+            } else {
+                // If it's a file and it matches, add it to the result cursor.
+                if (file.getName().toLowerCase().contains(query)) {
+                    includeFile(result, null, file);
+                }
+            }
+        }
+        return result;
+    }
+    // END_INCLUDE(query_search_documents)
+
+    // BEGIN_INCLUDE(open_document_thumbnail)
+    @Override
+    public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHint,
+                                                     CancellationSignal signal)
+            throws FileNotFoundException {
+        Log.v(TAG, "openDocumentThumbnail");
+
+        final File file = getFileForDocId(documentId);
+        final ParcelFileDescriptor pfd =
+                ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+        return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
+    }
+    // END_INCLUDE(open_document_thumbnail)
+
+    // BEGIN_INCLUDE(query_document)
+    @Override
+    public Cursor queryDocument(String documentId, String[] projection)
+            throws FileNotFoundException {
+        Log.v(TAG, "queryDocument");
+
+        // Create a cursor with the requested projection, or the default projection.
+        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+        includeFile(result, documentId, null);
+        return result;
+    }
+    // END_INCLUDE(query_document)
+
+    // BEGIN_INCLUDE(query_child_documents)
+    @Override
+    public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
+                                      String sortOrder) throws FileNotFoundException {
+        Log.v(TAG, "queryChildDocuments, parentDocumentId: " +
+                parentDocumentId +
+                " sortOrder: " +
+                sortOrder);
+
+        final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+        final File parent = getFileForDocId(parentDocumentId);
+        for (File file : parent.listFiles()) {
+            includeFile(result, null, file);
+        }
+        return result;
+    }
+    // END_INCLUDE(query_child_documents)
+
+
+    // BEGIN_INCLUDE(open_document)
+    @Override
+    public ParcelFileDescriptor openDocument(final String documentId, final String mode,
+                                             CancellationSignal signal)
+            throws FileNotFoundException {
+        Log.v(TAG, "openDocument, mode: " + mode);
+        // It's OK to do network operations in this method to download the document, as long as you
+        // periodically check the CancellationSignal.  If you have an extremely large file to
+        // transfer from the network, a better solution may be pipes or sockets
+        // (see ParcelFileDescriptor for helper methods).
+
+        final File file = getFileForDocId(documentId);
+        final int accessMode = ParcelFileDescriptor.parseMode(mode);
+
+        final boolean isWrite = (mode.indexOf('w') != -1);
+        if (isWrite) {
+            // Attach a close listener if the document is opened in write mode.
+            try {
+                Handler handler = new Handler(getContext().getMainLooper());
+                return ParcelFileDescriptor.open(file, accessMode, handler,
+                        new ParcelFileDescriptor.OnCloseListener() {
+                    @Override
+                    public void onClose(IOException e) {
+
+                        // Update the file with the cloud server.  The client is done writing.
+                        Log.i(TAG, "A file with id " + documentId + " has been closed!  Time to " +
+                                "update the server.");
+                    }
+
+                });
+            } catch (IOException e) {
+                throw new FileNotFoundException("Failed to open document with id " + documentId +
+                        " and mode " + mode);
+            }
+        } else {
+            return ParcelFileDescriptor.open(file, accessMode);
+        }
+    }
+    // END_INCLUDE(open_document)
+
+
+    // BEGIN_INCLUDE(create_document)
+    @Override
+    public String createDocument(String documentId, String mimeType, String displayName)
+            throws FileNotFoundException {
+        Log.v(TAG, "createDocument");
+
+        File parent = getFileForDocId(documentId);
+        File file = new File(parent.getPath(), displayName);
+        try {
+            file.createNewFile();
+            file.setWritable(true);
+            file.setReadable(true);
+        } catch (IOException e) {
+            throw new FileNotFoundException("Failed to create document with name " +
+                    displayName +" and documentId " + documentId);
+        }
+        return getDocIdForFile(file);
+    }
+    // END_INCLUDE(create_document)
+
+    // BEGIN_INCLUDE(delete_document)
+    @Override
+    public void deleteDocument(String documentId) throws FileNotFoundException {
+        Log.v(TAG, "deleteDocument");
+        File file = getFileForDocId(documentId);
+        if (file.delete()) {
+            Log.i(TAG, "Deleted file with id " + documentId);
+        } else {
+            throw new FileNotFoundException("Failed to delete document with id " + documentId);
+        }
+    }
+    // END_INCLUDE(delete_document)
+
+
+    @Override
+    public String getDocumentType(String documentId) throws FileNotFoundException {
+        File file = getFileForDocId(documentId);
+        return getTypeForFile(file);
+    }
+
+    /**
+     * @param projection the requested root column projection
+     * @return either the requested root column projection, or the default projection if the
+     * requested projection is null.
+     */
+    private static String[] resolveRootProjection(String[] projection) {
+        return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
+    }
+
+    private static String[] resolveDocumentProjection(String[] projection) {
+        return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
+    }
+
+    /**
+     * Get a file's MIME type
+     *
+     * @param file the File object whose type we want
+     * @return the MIME type of the file
+     */
+    private static String getTypeForFile(File file) {
+        if (file.isDirectory()) {
+            return Document.MIME_TYPE_DIR;
+        } else {
+            return getTypeForName(file.getName());
+        }
+    }
+
+    /**
+     * Get the MIME data type of a document, given its filename.
+     *
+     * @param name the filename of the document
+     * @return the MIME data type of a document
+     */
+    private static String getTypeForName(String name) {
+        final int lastDot = name.lastIndexOf('.');
+        if (lastDot >= 0) {
+            final String extension = name.substring(lastDot + 1);
+            final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+            if (mime != null) {
+                return mime;
+            }
+        }
+        return "application/octet-stream";
+    }
+
+    /**
+     * Gets a string of unique MIME data types a directory supports, separated by newlines.  This
+     * should not change.
+     *
+     * @param parent the File for the parent directory
+     * @return a string of the unique MIME data types the parent directory supports
+     */
+    private String getChildMimeTypes(File parent) {
+        Set<String> mimeTypes = new HashSet<String>();
+        mimeTypes.add("image/*");
+        mimeTypes.add("text/*");
+        mimeTypes.add("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+
+        // Flatten the list into a string and insert newlines between the MIME type strings.
+        StringBuilder mimeTypesString = new StringBuilder();
+        for (String mimeType : mimeTypes) {
+            mimeTypesString.append(mimeType).append("\n");
+        }
+
+        return mimeTypesString.toString();
+    }
+
+    /**
+     * Get the document ID given a File.  The document id must be consistent across time.  Other
+     * applications may save the ID and use it to reference documents later.
+     * <p/>
+     * This implementation is specific to this demo.  It assumes only one root and is built
+     * directly from the file structure.  However, it is possible for a document to be a child of
+     * multiple directories (for example "android" and "images"), in which case the file must have
+     * the same consistent, unique document ID in both cases.
+     *
+     * @param file the File whose document ID you want
+     * @return the corresponding document ID
+     */
+    private String getDocIdForFile(File file) {
+        String path = file.getAbsolutePath();
+
+        // Start at first char of path under root
+        final String rootPath = mBaseDir.getPath();
+        if (rootPath.equals(path)) {
+            path = "";
+        } else if (rootPath.endsWith("/")) {
+            path = path.substring(rootPath.length());
+        } else {
+            path = path.substring(rootPath.length() + 1);
+        }
+
+        return "root" + ':' + path;
+    }
+
+    /**
+     * Add a representation of a file to a cursor.
+     *
+     * @param result the cursor to modify
+     * @param docId  the document ID representing the desired file (may be null if given file)
+     * @param file   the File object representing the desired file (may be null if given docID)
+     * @throws java.io.FileNotFoundException
+     */
+    private void includeFile(MatrixCursor result, String docId, File file)
+            throws FileNotFoundException {
+        if (docId == null) {
+            docId = getDocIdForFile(file);
+        } else {
+            file = getFileForDocId(docId);
+        }
+
+        int flags = 0;
+
+        if (file.isDirectory()) {
+            // Request the folder to lay out as a grid rather than a list. This also allows a larger
+            // thumbnail to be displayed for each image.
+            //            flags |= Document.FLAG_DIR_PREFERS_GRID;
+
+            // Add FLAG_DIR_SUPPORTS_CREATE if the file is a writable directory.
+            if (file.isDirectory() && file.canWrite()) {
+                flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
+            }
+        } else if (file.canWrite()) {
+            // If the file is writable set FLAG_SUPPORTS_WRITE and
+            // FLAG_SUPPORTS_DELETE
+            flags |= Document.FLAG_SUPPORTS_WRITE;
+            flags |= Document.FLAG_SUPPORTS_DELETE;
+        }
+
+        final String displayName = file.getName();
+        final String mimeType = getTypeForFile(file);
+
+        if (mimeType.startsWith("image/")) {
+            // Allow the image to be represented by a thumbnail rather than an icon
+            flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
+        }
+
+        final MatrixCursor.RowBuilder row = result.newRow();
+        row.add(Document.COLUMN_DOCUMENT_ID, docId);
+        row.add(Document.COLUMN_DISPLAY_NAME, displayName);
+        row.add(Document.COLUMN_SIZE, file.length());
+        row.add(Document.COLUMN_MIME_TYPE, mimeType);
+        row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
+        row.add(Document.COLUMN_FLAGS, flags);
+
+        // Add a custom icon
+        row.add(Document.COLUMN_ICON, R.drawable.ic_launcher);
+    }
+
+    /**
+     * Translate your custom URI scheme into a File object.
+     *
+     * @param docId the document ID representing the desired file
+     * @return a File represented by the given document ID
+     * @throws java.io.FileNotFoundException
+     */
+    private File getFileForDocId(String docId) throws FileNotFoundException {
+        File target = mBaseDir;
+        if (docId.equals(ROOT)) {
+            return target;
+        }
+        final int splitIndex = docId.indexOf(':', 1);
+        if (splitIndex < 0) {
+            throw new FileNotFoundException("Missing root for " + docId);
+        } else {
+            final String path = docId.substring(splitIndex + 1);
+            target = new File(target, path);
+            if (!target.exists()) {
+                throw new FileNotFoundException("Missing file for " + docId + " at " + target);
+            }
+            return target;
+        }
+    }
+
+
+    /**
+     * Preload sample files packaged in the apk into the internal storage directory.  This is a
+     * dummy function specific to this demo.  The MyCloud mock cloud service doesn't actually
+     * have a backend, so it simulates by reading content from the device's internal storage.
+     */
+    private void writeDummyFilesToStorage() {
+        if (mBaseDir.list().length > 0) {
+            return;
+        }
+
+        int[] imageResIds = getResourceIdArray(R.array.image_res_ids);
+        for (int resId : imageResIds) {
+            writeFileToInternalStorage(resId, ".jpeg");
+        }
+
+        int[] textResIds = getResourceIdArray(R.array.text_res_ids);
+        for (int resId : textResIds) {
+            writeFileToInternalStorage(resId, ".txt");
+        }
+
+        int[] docxResIds = getResourceIdArray(R.array.docx_res_ids);
+        for (int resId : docxResIds) {
+            writeFileToInternalStorage(resId, ".docx");
+        }
+    }
+
+    /**
+     * Write a file to internal storage.  Used to set up our dummy "cloud server".
+     *
+     * @param resId     the resource ID of the file to write to internal storage
+     * @param extension the file extension (ex. .png, .mp3)
+     */
+    private void writeFileToInternalStorage(int resId, String extension) {
+        InputStream ins = getContext().getResources().openRawResource(resId);
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        int size;
+        byte[] buffer = new byte[1024];
+        try {
+            while ((size = ins.read(buffer, 0, 1024)) >= 0) {
+                outputStream.write(buffer, 0, size);
+            }
+            ins.close();
+            buffer = outputStream.toByteArray();
+            String filename = getContext().getResources().getResourceEntryName(resId) + extension;
+            FileOutputStream fos = getContext().openFileOutput(filename, Context.MODE_PRIVATE);
+            fos.write(buffer);
+            fos.close();
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private int[] getResourceIdArray(int arrayResId) {
+        TypedArray ar = getContext().getResources().obtainTypedArray(arrayResId);
+        int len = ar.length();
+        int[] resIds = new int[len];
+        for (int i = 0; i < len; i++) {
+            resIds[i] = ar.getResourceId(i, 0);
+        }
+        ar.recycle();
+        return resIds;
+    }
+
+    /**
+     * Dummy function to determine whether the user is logged in.
+     */
+    private boolean isUserLoggedIn() {
+        final SharedPreferences sharedPreferences =
+                getContext().getSharedPreferences(getContext().getString(R.string.app_name),
+                        Context.MODE_PRIVATE);
+        return sharedPreferences.getBoolean(getContext().getString(R.string.key_logged_in), false);
+    }
+
+
+}
diff --git a/samples/browseable/Styled/AndroidManifest.xml b/samples/browseable/Styled/AndroidManifest.xml
new file mode 100644
index 0000000..06394c7
--- /dev/null
+++ b/samples/browseable/Styled/AndroidManifest.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.actionbarcompat.styled"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="7"
+        android:targetSdkVersion="17" />
+
+    <!--
+        Theme is set on the application so that our custom theme is used by
+        default by all Activities
+    -->
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/Theme.Styled" >
+
+        <activity android:name=".MainActivity">
+
+            <!-- Launcher Intent filter -->
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+
+            <!--
+                In this example set the Activity to have a split action bar when the device's
+                display is narrow. In ActionBarCompat this is done by setting the
+                'android.support.UI_OPTIONS' metadata field to 'splitActionBarWhenNarrow'.
+            -->
+            <meta-data
+                android:name="android.support.UI_OPTIONS"
+                android:value="splitActionBarWhenNarrow" />
+
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/Styled/_index.jd b/samples/browseable/Styled/_index.jd
new file mode 100644
index 0000000..0816197
--- /dev/null
+++ b/samples/browseable/Styled/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="Styled ActionBarCompat"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to use a backward compatible
+{@link android.support.v7.app.ActionBar} with a customized theme.</p>
+<p>The activity in this sample extends from
+{@link android.support.v7.app.ActionBarActivity}, which provides the
+functionality necessary to display a compatible action bar on devices
+running Android 2.1 and higher.</p>
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.png
new file mode 100644
index 0000000..f1d56b0
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ab_solid_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/ab_solid_styled.9.png
new file mode 100644
index 0000000..b9790a9
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/ab_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.png
new file mode 100644
index 0000000..caa80ca
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ic_action_location.png b/samples/browseable/Styled/res/drawable-hdpi/ic_action_location.png
new file mode 100644
index 0000000..9d75c31
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ic_action_refresh.png b/samples/browseable/Styled/res/drawable-hdpi/ic_action_refresh.png
new file mode 100644
index 0000000..0216514
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ic_action_settings.png b/samples/browseable/Styled/res/drawable-hdpi/ic_action_settings.png
new file mode 100644
index 0000000..8e30d96
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ic_launcher.png b/samples/browseable/Styled/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..ba841fa
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/list_focused_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/list_focused_styled.9.png
new file mode 100644
index 0000000..1189239
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/list_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.png
new file mode 100644
index 0000000..a114859
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/progress_bg_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/progress_bg_styled.9.png
new file mode 100644
index 0000000..3b183e0
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/progress_bg_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/progress_primary_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/progress_primary_styled.9.png
new file mode 100644
index 0000000..d9879bd
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/progress_primary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/progress_secondary_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/progress_secondary_styled.9.png
new file mode 100644
index 0000000..7a6ee50
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/progress_secondary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_default_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_default_styled.9.png
new file mode 100644
index 0000000..e518eb7
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_default_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.png
new file mode 100644
index 0000000..b6febf9
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.png
new file mode 100644
index 0000000..c631c2f
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.png
new file mode 100644
index 0000000..8e71d1c
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tab_selected_focused_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/tab_selected_focused_styled.9.png
new file mode 100644
index 0000000..f4d6f2f
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/tab_selected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.png
new file mode 100644
index 0000000..2aa7838
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tab_selected_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/tab_selected_styled.9.png
new file mode 100644
index 0000000..e2b390a
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/tab_selected_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.png
new file mode 100644
index 0000000..5b8b928
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.png b/samples/browseable/Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.png
new file mode 100644
index 0000000..18d2053
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tile.9.png b/samples/browseable/Styled/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.png
new file mode 100644
index 0000000..79da2b0
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ab_solid_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/ab_solid_styled.9.png
new file mode 100644
index 0000000..617c08b
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/ab_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.png
new file mode 100644
index 0000000..407382a
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ic_action_location.png b/samples/browseable/Styled/res/drawable-mdpi/ic_action_location.png
new file mode 100644
index 0000000..b637f52
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ic_action_refresh.png b/samples/browseable/Styled/res/drawable-mdpi/ic_action_refresh.png
new file mode 100644
index 0000000..206314b
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ic_action_settings.png b/samples/browseable/Styled/res/drawable-mdpi/ic_action_settings.png
new file mode 100644
index 0000000..0e65c68
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ic_launcher.png b/samples/browseable/Styled/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..2901fa6
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/list_focused_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/list_focused_styled.9.png
new file mode 100644
index 0000000..30095e6
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/list_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.png
new file mode 100644
index 0000000..ea341b5
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/progress_bg_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/progress_bg_styled.9.png
new file mode 100644
index 0000000..71753a4
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/progress_bg_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/progress_primary_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/progress_primary_styled.9.png
new file mode 100644
index 0000000..375aff2
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/progress_primary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/progress_secondary_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/progress_secondary_styled.9.png
new file mode 100644
index 0000000..d1dbb3b
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/progress_secondary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_default_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_default_styled.9.png
new file mode 100644
index 0000000..5e1dd47
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_default_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.png
new file mode 100644
index 0000000..38025ad
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.png
new file mode 100644
index 0000000..37b4576
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.png
new file mode 100644
index 0000000..8b99463
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/tab_selected_focused_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/tab_selected_focused_styled.9.png
new file mode 100644
index 0000000..83daafb
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/tab_selected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.png
new file mode 100644
index 0000000..d50ffaf
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/tab_selected_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/tab_selected_styled.9.png
new file mode 100644
index 0000000..6fdd7f4
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/tab_selected_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.png
new file mode 100644
index 0000000..dc77e6d
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.png b/samples/browseable/Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.png
new file mode 100644
index 0000000..637d22d
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.png
new file mode 100644
index 0000000..64f17a8
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ab_solid_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/ab_solid_styled.9.png
new file mode 100644
index 0000000..c557360
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/ab_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.png
new file mode 100644
index 0000000..0ef2ec0
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ic_action_location.png b/samples/browseable/Styled/res/drawable-xhdpi/ic_action_location.png
new file mode 100644
index 0000000..e9bf9f3
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ic_action_refresh.png b/samples/browseable/Styled/res/drawable-xhdpi/ic_action_refresh.png
new file mode 100644
index 0000000..ccd4b07
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ic_action_settings.png b/samples/browseable/Styled/res/drawable-xhdpi/ic_action_settings.png
new file mode 100644
index 0000000..d0a733e
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/Styled/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..866f146
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/list_focused_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/list_focused_styled.9.png
new file mode 100644
index 0000000..c02fe13
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/list_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.png
new file mode 100644
index 0000000..3d9f614
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/progress_bg_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/progress_bg_styled.9.png
new file mode 100644
index 0000000..5ffc2ac
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/progress_bg_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/progress_primary_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/progress_primary_styled.9.png
new file mode 100644
index 0000000..8f66361
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/progress_primary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/progress_secondary_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/progress_secondary_styled.9.png
new file mode 100644
index 0000000..f28f10b
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/progress_secondary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.png
new file mode 100644
index 0000000..f738a44
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.png
new file mode 100644
index 0000000..79d24c9
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.png
new file mode 100644
index 0000000..8be8d71
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.png
new file mode 100644
index 0000000..774602c
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.png
new file mode 100644
index 0000000..c174424
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.png
new file mode 100644
index 0000000..62cbd04
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_styled.9.png
new file mode 100644
index 0000000..5009ce0
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.png
new file mode 100644
index 0000000..2c2a567
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.png b/samples/browseable/Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.png
new file mode 100644
index 0000000..81eba4c
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/Styled/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..cb301f2
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable/pressed_background.xml b/samples/browseable/Styled/res/drawable/pressed_background.xml
new file mode 100644
index 0000000..9de1ff7
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable/pressed_background.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+  This drawable is used in our custom selected item background drawable: selectable_background.xml.
+  It is required as selector items need to be drawables, and not a raw color value as we are using.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+
+    <solid android:color="@color/pressed_styled"/>
+
+</shape>
\ No newline at end of file
diff --git a/samples/browseable/Styled/res/drawable/progress_horizontal.xml b/samples/browseable/Styled/res/drawable/progress_horizontal.xml
new file mode 100644
index 0000000..bef8c57
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable/progress_horizontal.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+  This drawable is used in our custom horizontal Progress Bar style:
+  Widget.Styled.ProgressBar.Horizontal
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:id="@android:id/background"
+        android:drawable="@drawable/progress_bg_styled" />
+
+    <item android:id="@android:id/secondaryProgress">
+        <scale
+            android:drawable="@drawable/progress_secondary_styled"
+            android:scaleWidth="100%" />
+    </item>
+
+    <item android:id="@android:id/progress">
+        <scale
+            android:drawable="@drawable/progress_primary_styled"
+            android:scaleWidth="100%" />
+    </item>
+
+</layer-list>
\ No newline at end of file
diff --git a/samples/browseable/Styled/res/drawable/selectable_background.xml b/samples/browseable/Styled/res/drawable/selectable_background.xml
new file mode 100644
index 0000000..776dbb7
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable/selectable_background.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+  This drawable is used as the main touch feedback drawable for the Action Bar. By default it is
+  used as the action item button background, amongst other things.
+
+  The different items in this drawable are displayed when their selector state matches the view's
+  state.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/list_focused_styled" android:state_focused="true"
+          android:state_pressed="false"/>
+    <item android:drawable="@drawable/pressed_background" android:state_pressed="true"/>
+    <item android:drawable="@android:color/transparent"/>
+
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/Styled/res/drawable/spinner_background_ab.xml b/samples/browseable/Styled/res/drawable/spinner_background_ab.xml
new file mode 100644
index 0000000..a12db6e
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable/spinner_background_ab.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+  This drawable is used to style the list navigation spinner in our custom Action Bar theme.
+
+  The different items in this drawable are displayed when their selector state matches the view's
+  state.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/spinner_ab_disabled_styled" android:state_enabled="false" />
+    <item android:drawable="@drawable/spinner_ab_pressed_styled" android:state_pressed="true" />
+    <item android:drawable="@drawable/spinner_ab_focused_styled" android:state_focused="true"
+        android:state_pressed="false" />
+    <item android:drawable="@drawable/spinner_ab_default_styled" />
+
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/Styled/res/drawable/tab_indicator_ab.xml b/samples/browseable/Styled/res/drawable/tab_indicator_ab.xml
new file mode 100644
index 0000000..baa6492
--- /dev/null
+++ b/samples/browseable/Styled/res/drawable/tab_indicator_ab.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+  This drawable is used as the background drawable for each tab displayed on the Action Bar.
+
+  The different items in this drawable are displayed when their selector state matches the view's
+  state.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- Non focused states -->
+    <item android:drawable="@android:color/transparent" android:state_focused="false"
+        android:state_pressed="false" android:state_selected="false" />
+    <item android:drawable="@drawable/tab_selected_styled" android:state_focused="false"
+        android:state_pressed="false" android:state_selected="true" />
+
+    <!-- Focused states -->
+    <item android:drawable="@drawable/tab_unselected_focused_styled" android:state_focused="true"
+        android:state_pressed="false" android:state_selected="false" />
+    <item android:drawable="@drawable/tab_selected_focused_styled" android:state_focused="true"
+        android:state_pressed="false" android:state_selected="true" />
+
+    <!-- Pressed & Non-focused -->
+    <item android:drawable="@drawable/tab_unselected_pressed_styled" android:state_focused="false"
+        android:state_pressed="true" android:state_selected="false" />
+    <item android:drawable="@drawable/tab_selected_pressed_styled" android:state_focused="false"
+        android:state_pressed="true" android:state_selected="true" />
+
+    <!-- Pressed & focused states -->
+    <item android:drawable="@drawable/tab_unselected_pressed_styled" android:state_focused="true"
+        android:state_pressed="true" android:state_selected="false" />
+    <item android:drawable="@drawable/tab_selected_pressed_styled" android:state_focused="true"
+        android:state_pressed="true" android:state_selected="true" />
+
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/Styled/res/layout/activity_main.xml b/samples/browseable/Styled/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/Styled/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/Styled/res/layout/sample_main.xml b/samples/browseable/Styled/res/layout/sample_main.xml
new file mode 100644
index 0000000..a162d3f
--- /dev/null
+++ b/samples/browseable/Styled/res/layout/sample_main.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:text="@string/main_description"
+    android:padding="16dp"
+    android:gravity="center"/>
+
diff --git a/samples/browseable/Styled/res/menu/main.xml b/samples/browseable/Styled/res/menu/main.xml
new file mode 100644
index 0000000..778a443
--- /dev/null
+++ b/samples/browseable/Styled/res/menu/main.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+  As we're using ActionBarCompat, any action item attributes come from ActionBarCompat's XML
+  namespace instead of the android namespace. Here we've added a new support namespace added to
+  the menu element allowing us to use the 'showAsAction' attribute in a backwards compatible way.
+  Any other action item attributes used should be referenced from this namespace too
+  (actionProviderClass, actionViewClass, actionLayout).
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:support="http://schemas.android.com/apk/res-auto" >
+
+    <!--
+       Here we create all of the items to be displayed in the menu, setting support:showAsAction to
+       define how the item should be displayed on the compatible Action Bar.
+    -->
+    <item
+        android:id="@+id/menu_refresh"
+        android:icon="@drawable/ic_action_refresh"
+        android:title="@string/menu_refresh"
+        support:showAsAction="ifRoom"/>
+
+    <item
+        android:id="@+id/menu_location"
+        android:icon="@drawable/ic_action_location"
+        android:title="@string/menu_location"
+        support:showAsAction="ifRoom"/>
+
+    <item
+        android:id="@+id/menu_settings"
+        android:icon="@drawable/ic_action_settings"
+        android:title="@string/menu_settings"
+        support:showAsAction="never"/>
+
+</menu>
\ No newline at end of file
diff --git a/samples/browseable/Styled/res/values-sw600dp/dimens.xml b/samples/browseable/Styled/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/Styled/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/Styled/res/values-sw600dp/styles.xml b/samples/browseable/Styled/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/Styled/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/Styled/res/values-v14/styles.xml b/samples/browseable/Styled/res/values-v14/styles.xml
new file mode 100644
index 0000000..4bfec48
--- /dev/null
+++ b/samples/browseable/Styled/res/values-v14/styles.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+    <!--
+        This is the styled theme.
+
+        It extends from Theme.AppCompat.Light, but it could extend from any of
+        the Theme.AppCompat themes depending on your color scheme. This theme can be applied to
+        your application or individual activities in the AndroidManifest.xml. In this sample it is
+        set on the application.
+
+        This differs from the version of this theme in 'res/values', as we revert back to
+        setting the attributes from the android namespace in ICS+.
+    -->
+
+    <style name="Theme.Styled" parent="@style/Theme.AppCompat.Light">
+        <item name="android:actionBarItemBackground">@drawable/selectable_background</item>
+        <item name="android:actionBarTabStyle">@style/Widget.Styled.ActionBar.TabView</item>
+        <item name="android:actionBarStyle">@style/Widget.Styled.ActionBar</item>
+        <item name="android:actionDropDownStyle">
+            @style/Widget.Styled.Spinner.DropDown.ActionBar
+        </item>
+        <item name="android:dropDownListViewStyle">@style/Widget.Styled.ListView.DropDown</item>
+        <item name="android:popupMenuStyle">@style/Widget.Styled.PopupMenu</item>
+    </style>
+
+    <style name="Widget.Styled.ActionBar" parent="@style/Widget.AppCompat.Light.ActionBar.Solid">
+        <item name="android:background">@drawable/ab_solid_styled</item>
+        <item name="android:backgroundStacked">@drawable/ab_stacked_solid_styled</item>
+        <item name="android:backgroundSplit">@drawable/ab_bottom_solid_styled</item>
+        <item name="android:progressBarStyle">@style/Widget.Styled.ProgressBar.Horizontal</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Styled/res/values/base-strings.xml b/samples/browseable/Styled/res/values/base-strings.xml
new file mode 100644
index 0000000..985b433
--- /dev/null
+++ b/samples/browseable/Styled/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">Styled</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample shows you how to use ActionBarCompat with a customized theme. It utilizes a
+            split action bar when running on a device with a narrow display, and show three tabs.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/Styled/res/values/colors.xml b/samples/browseable/Styled/res/values/colors.xml
new file mode 100644
index 0000000..e111f59
--- /dev/null
+++ b/samples/browseable/Styled/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+    <color name="pressed_styled">#CC669900</color>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Styled/res/values/dimens.xml b/samples/browseable/Styled/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/Styled/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/Styled/res/values/strings.xml b/samples/browseable/Styled/res/values/strings.xml
new file mode 100644
index 0000000..de698d4
--- /dev/null
+++ b/samples/browseable/Styled/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+
+    <string name="menu_refresh">Refresh</string>
+    <string name="menu_location">Location</string>
+    <string name="menu_settings">Settings</string>
+    <string name="main_description">This is a basic Activity showing an Action Bar which has been
+        styled.
+    </string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Styled/res/values/styles.xml b/samples/browseable/Styled/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/Styled/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/Styled/src/com.example.android.actionbarcompat.styled/MainActivity.java b/samples/browseable/Styled/src/com.example.android.actionbarcompat.styled/MainActivity.java
new file mode 100644
index 0000000..19fe3a1
--- /dev/null
+++ b/samples/browseable/Styled/src/com.example.android.actionbarcompat.styled/MainActivity.java
@@ -0,0 +1,80 @@
+/*
+ * 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.actionbarcompat.styled;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
+import android.view.Menu;
+
+/**
+ * This sample shows you how to use ActionBarCompat with a customized theme. It utilizes a split
+ * action bar when running on a device with a narrow display, and show three tabs.
+ *
+ * This Activity extends from {@link ActionBarActivity}, which provides all of the function
+ * necessary to display a compatible Action Bar on devices running Android v2.1+.
+ *
+ * The interesting bits of this sample start in the theme files
+ * ('res/values/styles.xml' and 'res/values-v14</styles.xml').
+ *
+ * Many of the drawables used in this sample were generated with the
+ * 'Android Action Bar Style Generator': http://jgilfelt.github.io/android-actionbarstylegenerator
+ */
+public class MainActivity extends ActionBarActivity implements ActionBar.TabListener {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+
+        // Set the Action Bar to use tabs for navigation
+        ActionBar ab = getSupportActionBar();
+        ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+
+        // Add three tabs to the Action Bar for display
+        ab.addTab(ab.newTab().setText("Tab 1").setTabListener(this));
+        ab.addTab(ab.newTab().setText("Tab 2").setTabListener(this));
+        ab.addTab(ab.newTab().setText("Tab 3").setTabListener(this));
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate menu from menu resource (res/menu/main)
+        getMenuInflater().inflate(R.menu.main, menu);
+
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    // Implemented from ActionBar.TabListener
+    @Override
+    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+        // This is called when a tab is selected.
+    }
+
+    // Implemented from ActionBar.TabListener
+    @Override
+    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+        // This is called when a previously selected tab is unselected.
+    }
+
+    // Implemented from ActionBar.TabListener
+    @Override
+    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+        // This is called when a previously selected tab is selected again.
+    }
+}
diff --git a/samples/browseable/TextLinkify/AndroidManifest.xml b/samples/browseable/TextLinkify/AndroidManifest.xml
new file mode 100644
index 0000000..49b4eae
--- /dev/null
+++ b/samples/browseable/TextLinkify/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.textlinkify"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="4"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/TextLinkify/_index.jd b/samples/browseable/TextLinkify/_index.jd
new file mode 100644
index 0000000..9f31930
--- /dev/null
+++ b/samples/browseable/TextLinkify/_index.jd
@@ -0,0 +1,16 @@
+
+
+
+page.tags="TextLinkify"
+sample.group=Views
+@jd:body
+
+<p>This sample demonstrates how to add clickable links to a
+{@link android.widget.TextView}, by using these techniques:
+<ul>
+<li>Setting the {@link android.R.styleable#TextView_autoLink} property
+to automatically convert the text to a link.</li>
+<li>Parsing a String as HTML</li>
+<li>Manually by constructing a {@link android.text.SpannableString}.</li>
+</ul>
+</p>
diff --git a/samples/browseable/TextLinkify/res/drawable-hdpi/ic_launcher.png b/samples/browseable/TextLinkify/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..eae36bc
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/TextLinkify/res/drawable-hdpi/tile.9.png b/samples/browseable/TextLinkify/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/TextLinkify/res/drawable-mdpi/ic_launcher.png b/samples/browseable/TextLinkify/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f727f48
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/TextLinkify/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/TextLinkify/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..51199d3
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/TextLinkify/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/TextLinkify/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..c49ec6a
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/TextLinkify/res/layout/activity_main.xml b/samples/browseable/TextLinkify/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/TextLinkify/res/layout/sample_main.xml b/samples/browseable/TextLinkify/res/layout/sample_main.xml
new file mode 100644
index 0000000..8f35a70
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/layout/sample_main.xml
@@ -0,0 +1,72 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+    <ScrollView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        tools:context=".MainActivity">
+
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:paddingBottom="@dimen/activity_vertical_margin"
+            android:paddingLeft="@dimen/activity_horizontal_margin"
+            android:paddingRight="@dimen/activity_horizontal_margin"
+            android:paddingTop="@dimen/activity_vertical_margin">
+
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/intro" />
+
+            <!-- text_auto_linkify automatically linkifies things like URLs and phone numbers. -->
+            <TextView
+                android:id="@+id/text_auto_linkify"
+                style="@style/LinkText"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:autoLink="all"
+                android:text="@string/link_text_auto" />
+
+            <!--
+                   text_html_resource uses a string resource containing explicit anchor tags (<a>)
+                   to specify links.
+            -->
+            <TextView
+                android:id="@+id/text_html_resource"
+                style="@style/LinkText"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
+            <!-- text_html_program builds the text in the Java code using HTML. -->
+            <TextView
+                android:id="@+id/text_html_program"
+                style="@style/LinkText"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+
+            <!-- text_spannable builds the text in the Java code without using HTML. -->
+            <TextView
+                android:id="@+id/text_spannable"
+                style="@style/LinkText"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+    </ScrollView>
diff --git a/samples/browseable/TextLinkify/res/values-sw600dp/dimens.xml b/samples/browseable/TextLinkify/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/TextLinkify/res/values-sw600dp/styles.xml b/samples/browseable/TextLinkify/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/TextLinkify/res/values-sw720dp-land/dimens.xml b/samples/browseable/TextLinkify/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..560bd44
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+    <!--
+         Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
+    -->
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+
+</resources>
diff --git a/samples/browseable/TextLinkify/res/values/base-strings.xml b/samples/browseable/TextLinkify/res/values/base-strings.xml
new file mode 100644
index 0000000..f2eb104
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">TextLinkify</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample illustrates how links can be added to a TextView. This can be done either
+            automatically by setting the "autoLink" property or explicitly.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/TextLinkify/res/values/dimens.xml b/samples/browseable/TextLinkify/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/TextLinkify/res/values/strings.xml b/samples/browseable/TextLinkify/res/values/strings.xml
new file mode 100644
index 0000000..c50774e
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values/strings.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+    <string name="intro">This sample illustrates how links can be added to a TextView.
+    \nThis can be done either automatically by setting the <i>autoLink</i> property
+    or explicitly.</string>
+    <string name="link_text_auto"><b>text_auto_linkify: Various kinds
+      of data that will be auto-linked.</b>
+      In this text are some things that are actionable.  For instance,
+      you can click on http://www.google.com and it will launch the
+      web browser.  You can click on google.com too.  If you
+      click on (415) 555-1212 it should dial the phone.  Or just write
+      foobar@example.com for an e-mail link.  If you have a URI like
+      http://www.example.com/lala/foobar@example.com you should get the
+      full link not the e-mail address.  Or you can put a location
+      like 1600 Amphitheatre Parkway, Mountain View, CA 94043.  To summarize:
+      https://www.google.com, or 650-253-0000, somebody@example.com,
+      or 9606 North MoPac Expressway, Suite 400, Austin, TX 78759.</string>
+    <string name="link_text_manual"><![CDATA[<b>text_html_resource:
+      Explicit links using &lt;a&gt; markup.</b>
+      This has markup for a <a href="http://www.google.com">link</a> specified
+      via an &lt;a&gt; tag.  Use a \"tel:\" URL
+      to <a href="tel:4155551212">dial a phone number</a>.]]></string>
+
+</resources>
diff --git a/samples/browseable/TextLinkify/res/values/styles.xml b/samples/browseable/TextLinkify/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/TextLinkify/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/TextLinkify/src/com.example.android.common.logger/Log.java b/samples/browseable/TextLinkify/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/TextLinkify/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogNode.java b/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogView.java b/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/TextLinkify/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/TextLinkify/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/TextLinkify/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/TextLinkify/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/TextLinkify/src/com.example.android.textlinkify/MainActivity.java b/samples/browseable/TextLinkify/src/com.example.android.textlinkify/MainActivity.java
new file mode 100644
index 0000000..c9325a9
--- /dev/null
+++ b/samples/browseable/TextLinkify/src/com.example.android.textlinkify/MainActivity.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.textlinkify;
+
+import android.app.Activity;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.text.Html;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.text.style.StyleSpan;
+import android.text.style.URLSpan;
+import android.widget.TextView;
+
+/**
+ * This sample demonstrates how clickable links can be added to a
+ * {@link android.widget.TextView}.
+ *
+ * <p>This can be done in three ways:
+ * <ul>
+ * <li><b>Automatically:</b> Text added to a TextView can automatically be linkified by enabling
+ * autoLinking. In XML, use the android:autoLink property, programatically call
+ * {@link android.widget.TextView#setAutoLinkMask(int)} using an option from
+ * {@link android.text.util.Linkify}</li>
+ *
+ * <li><b>Parsing a String as HTML:</b> See {@link android.text.Html#fromHtml(String)})</li>
+ *
+ * <li><b>Manually by constructing a {@link android.text.SpannableString}:</b> Consisting of
+ * {@link android.text.style.StyleSpan} and {@link android.text.style.URLSpan} objects that
+ * are contained within a {@link android.text.SpannableString}</li>
+ * </ul></p>
+ *
+ */
+public class MainActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.sample_main);
+
+        // BEGIN_INCLUDE(text_auto_linkify)
+        /*
+         *  text_auto_linkify shows the android:autoLink property, which
+         *  automatically linkifies things like URLs and phone numbers
+         *  found in the text. No java code is needed to make this
+         *  work.
+         *  This can also be enabled programmatically by calling
+         *  .setAutoLinkMask(Linkify.ALL) before the text is set on the TextView.
+         *
+         *  See android.text.util.Linkify for other options, for example only
+         *  auto-linking email addresses or phone numbers
+         */
+        // END_INCLUDE(text_auto_linkify)
+
+        // BEGIN_INCLUDE(text_html_resource)
+        /*
+         * text_html_resource has links specified by putting anchor tags (<a>) in the string
+         * resource. By default these links will appear but not
+         * respond to user input. To make them active, you need to
+         * call setMovementMethod() on the TextView object.
+         */
+        TextView textViewResource = (TextView) findViewById(R.id.text_html_resource);
+        textViewResource.setText(
+                Html.fromHtml(getResources().getString(R.string.link_text_manual)));
+        textViewResource.setMovementMethod(LinkMovementMethod.getInstance());
+        // END_INCLUDE(text_html_resource)
+
+        // BEGIN_INCLUDE(text_html_program)
+        /*
+         * text_html_program shows creating text with links from HTML in the Java
+         * code, rather than from a string resource. Note that for a
+         * fixed string, using a (localizable) resource as shown above
+         * is usually a better way to go; this example is intended to
+         * illustrate how you might display text that came from a
+         * dynamic source (eg, the network).
+         */
+        TextView textViewHtml = (TextView) findViewById(R.id.text_html_program);
+        textViewHtml.setText(
+                Html.fromHtml(
+                        "<b>text_html_program: Constructed from HTML programmatically.</b>"
+                                + "  Text with a <a href=\"http://www.google.com\">link</a> "
+                                + "created in the Java source code using HTML."));
+        textViewHtml.setMovementMethod(LinkMovementMethod.getInstance());
+        // END_INCLUDE(text_html_program)
+
+        // BEGIN_INCLUDE(text_spannable)
+        /*
+         * text_spannable illustrates constructing a styled string containing a
+         * link without using HTML at all. Again, for a fixed string
+         * you should probably be using a string resource, not a
+         * hardcoded value.
+         */
+        SpannableString ss = new SpannableString(
+                "text_spannable: Manually created spans. Click here to dial the phone.");
+
+        /*
+         * Make the first 38 characters bold by applying a StyleSpan with bold typeface.
+         *
+         * Characters 45 to 49 (the word "here") is made clickable by applying a URLSpan
+         * pointing to a telephone number. Clicking it opens the "tel:" URL that starts the dialer.
+         *
+         * The SPAN_EXCLUSIVE_EXCLUSIVE flag defines this span as exclusive, which means
+         * that it will not expand to include text inserted on either side of this span.
+         */
+        ss.setSpan(new StyleSpan(Typeface.BOLD), 0, 39,
+                Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        ss.setSpan(new URLSpan("tel:4155551212"), 40 + 6, 40 + 10,
+                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        TextView textViewSpan = (TextView) findViewById(R.id.text_spannable);
+        textViewSpan.setText(ss);
+
+        /*
+         * Set the movement method to move between links in this TextView.
+         * This means that the user traverses through links in this TextView, automatically
+         * handling appropriate scrolling and key commands.
+         */
+        textViewSpan.setMovementMethod(LinkMovementMethod.getInstance());
+        // END_INCLUDE(text_spannable)
+    }
+
+}
diff --git a/samples/browseable/TextSwitcher/AndroidManifest.xml b/samples/browseable/TextSwitcher/AndroidManifest.xml
new file mode 100644
index 0000000..7f512a3
--- /dev/null
+++ b/samples/browseable/TextSwitcher/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.textswitcher"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="4"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/browseable/TextSwitcher/_index.jd b/samples/browseable/TextSwitcher/_index.jd
new file mode 100644
index 0000000..0fc5c32
--- /dev/null
+++ b/samples/browseable/TextSwitcher/_index.jd
@@ -0,0 +1,11 @@
+
+
+
+page.tags="TextSwitcher"
+sample.group=UI
+@jd:body
+
+<p>This sample demonstrates how to use the {@link android.widget.TextSwitcher}
+view with animations. A {@link android.widget.TextSwitcher} is a type of
+{@link android.widget.ViewSwitcher} that animates text transitions on screen
+when {@link android.widget.TextSwitcher#setText(CharSequence)} is called.</p>
diff --git a/samples/browseable/TextSwitcher/res/drawable-hdpi/ic_launcher.png b/samples/browseable/TextSwitcher/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..641bab2
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/TextSwitcher/res/drawable-hdpi/tile.9.png b/samples/browseable/TextSwitcher/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/TextSwitcher/res/drawable-mdpi/ic_launcher.png b/samples/browseable/TextSwitcher/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..e29c59f
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/TextSwitcher/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/TextSwitcher/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..d23193b
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/TextSwitcher/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/TextSwitcher/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..22bfd45
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/TextSwitcher/res/layout/activity_main.xml b/samples/browseable/TextSwitcher/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout style="@style/Widget.SampleMessageTile"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical">
+
+        <TextView style="@style/Widget.SampleMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/horizontal_page_margin"
+            android:layout_marginRight="@dimen/horizontal_page_margin"
+            android:layout_marginTop="@dimen/vertical_page_margin"
+            android:layout_marginBottom="@dimen/vertical_page_margin"
+            android:text="@string/intro_message" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/TextSwitcher/res/layout/sample_main.xml b/samples/browseable/TextSwitcher/res/layout/sample_main.xml
new file mode 100644
index 0000000..a5a7053
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/layout/sample_main.xml
@@ -0,0 +1,47 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/LinearLayout1"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="top|center_horizontal"
+    android:gravity="center_horizontal"
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context=".MainActivity" >
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/intro" />
+
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/next" />
+
+    <TextSwitcher
+        android:id="@+id/switcher"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+
+</LinearLayout>
diff --git a/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml b/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values-sw600dp/styles.xml b/samples/browseable/TextSwitcher/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values-sw720dp-land/dimens.xml b/samples/browseable/TextSwitcher/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..560bd44
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+    <!--
+         Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here.
+    -->
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values-v11/styles.xml b/samples/browseable/TextSwitcher/res/values-v11/styles.xml
new file mode 100644
index 0000000..91f4523
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values-v11/styles.xml
@@ -0,0 +1,27 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+    <!--
+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/styles.xml on API 11+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!-- API 11 theme customizations can go here. -->
+    </style>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values-v14/styles.xml b/samples/browseable/TextSwitcher/res/values-v14/styles.xml
new file mode 100644
index 0000000..c2b6a6b
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values-v14/styles.xml
@@ -0,0 +1,28 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values/base-strings.xml b/samples/browseable/TextSwitcher/res/values/base-strings.xml
new file mode 100644
index 0000000..2497e86
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values/base-strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">TextSwitcher</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+                This sample illustrates the use of a TextSwitcher to display text.
+                \n\nClick the button below to set new text in the TextSwitcher and observe the
+                in and out fade animations.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values/dimens.xml b/samples/browseable/TextSwitcher/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values/strings.xml b/samples/browseable/TextSwitcher/res/values/strings.xml
new file mode 100644
index 0000000..612b6cb
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<resources>
+
+    <string name="intro">This sample illustrates the use of a <b>TextSwitcher</b> to display text.
+\n\n<b>Click the button</b> below to set new text in the TextSwitcher and observe the in and out
+ fade animations.</string>
+    <string name="next">Next</string>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/res/values/styles.xml b/samples/browseable/TextSwitcher/res/values/styles.xml
new file mode 100644
index 0000000..404623e
--- /dev/null
+++ b/samples/browseable/TextSwitcher/res/values/styles.xml
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Sample" parent="Theme.Base" />
+
+    <style name="AppTheme" parent="Theme.Sample" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/TextSwitcher/src/com.example.android.common.logger/Log.java b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogNode.java b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogView.java b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/TextSwitcher/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/TextSwitcher/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/TextSwitcher/src/com.example.android.textswitcher/MainActivity.java b/samples/browseable/TextSwitcher/src/com.example.android.textswitcher/MainActivity.java
new file mode 100644
index 0000000..a8cbb5e
--- /dev/null
+++ b/samples/browseable/TextSwitcher/src/com.example.android.textswitcher/MainActivity.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.textswitcher;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.Button;
+import android.widget.TextSwitcher;
+import android.widget.TextView;
+import android.widget.ViewSwitcher.ViewFactory;
+
+/**
+ * This sample shows the use of the {@link android.widget.TextSwitcher} View with animations. A
+ * {@link android.widget.TextSwitcher} is a special type of {@link android.widget.ViewSwitcher} that animates
+ * the current text out and new text in when
+ * {@link android.widget.TextSwitcher#setText(CharSequence)} is called.
+ */
+public class MainActivity extends Activity {
+    private TextSwitcher mSwitcher;
+    private int mCounter = 0;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.sample_main);
+
+        // Get the TextSwitcher view from the layout
+        mSwitcher = (TextSwitcher) findViewById(R.id.switcher);
+
+        // BEGIN_INCLUDE(setup)
+        // Set the factory used to create TextViews to switch between.
+        mSwitcher.setFactory(mFactory);
+
+        /*
+         * Set the in and out animations. Using the fade_in/out animations
+         * provided by the framework.
+         */
+        Animation in = AnimationUtils.loadAnimation(this,
+                android.R.anim.fade_in);
+        Animation out = AnimationUtils.loadAnimation(this,
+                android.R.anim.fade_out);
+        mSwitcher.setInAnimation(in);
+        mSwitcher.setOutAnimation(out);
+        // END_INCLUDE(setup)
+
+        /*
+         * Setup the 'next' button. The counter is incremented when clicked and
+         * the new value is displayed in the TextSwitcher. The change of text is
+         * automatically animated using the in/out animations set above.
+         */
+        Button nextButton = (Button) findViewById(R.id.button);
+        nextButton.setOnClickListener(new View.OnClickListener() {
+
+            @Override
+            public void onClick(View v) {
+                mCounter++;
+                // BEGIN_INCLUDE(settext)
+                mSwitcher.setText(String.valueOf(mCounter));
+                // END_INCLUDE(settext)
+            }
+        });
+
+        // Set the initial text without an animation
+        mSwitcher.setCurrentText(String.valueOf(mCounter));
+
+    }
+
+    // BEGIN_INCLUDE(factory)
+    /**
+     * The {@link android.widget.ViewSwitcher.ViewFactory} used to create {@link android.widget.TextView}s that the
+     * {@link android.widget.TextSwitcher} will switch between.
+     */
+    private ViewFactory mFactory = new ViewFactory() {
+
+        @Override
+        public View makeView() {
+
+            // Create a new TextView
+            TextView t = new TextView(MainActivity.this);
+            t.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
+            t.setTextAppearance(MainActivity.this, android.R.style.TextAppearance_Large);
+            return t;
+        }
+    };
+    // END_INCLUDE(factory)
+}
diff --git a/samples/browseable/repeatingAlarm/AndroidManifest.xml b/samples/browseable/repeatingAlarm/AndroidManifest.xml
new file mode 100644
index 0000000..b7d02e5
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.repeatingalarm"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name"
+                  android:uiOptions="splitActionBarWhenNarrow">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+
+</manifest>
diff --git a/samples/browseable/repeatingAlarm/_index.jd b/samples/browseable/repeatingAlarm/_index.jd
new file mode 100644
index 0000000..bd77d6c
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/_index.jd
@@ -0,0 +1,9 @@
+
+
+
+page.tags="RepeatingAlarm"
+sample.group=Background
+@jd:body
+
+<p>This sample demonstrates how to implement a repeating alarm using an
+{@link android.app.AlarmManager}.</p>
diff --git a/samples/browseable/repeatingAlarm/res/drawable-hdpi/ic_launcher.png b/samples/browseable/repeatingAlarm/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-hdpi/tile.9.png b/samples/browseable/repeatingAlarm/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-mdpi/ic_launcher.png b/samples/browseable/repeatingAlarm/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/repeatingAlarm/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/layout/activity_main.xml b/samples/browseable/repeatingAlarm/res/layout/activity_main.xml
new file mode 100755
index 0000000..bc5a575
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:id="@+id/sample_main_layout">
+    <TextView android:id="@+id/sample_output"
+              style="@style/Widget.SampleMessage"
+              android:layout_weight="1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:text="@string/intro_message" />
+    <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:background="@android:color/darker_gray"/>
+    <fragment
+            android:name="com.example.android.common.logger.LogFragment"
+            android:id="@+id/log_fragment"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/samples/browseable/repeatingAlarm/res/menu/main.xml b/samples/browseable/repeatingAlarm/res/menu/main.xml
new file mode 100644
index 0000000..2c3515d
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/sample_action"
+          android:showAsAction="ifRoom|withText"
+          android:title="@string/sample_action" />
+</menu>
diff --git a/samples/browseable/repeatingAlarm/res/values-sw600dp/dimens.xml b/samples/browseable/repeatingAlarm/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/values-sw600dp/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values-sw600dp/styles.xml b/samples/browseable/repeatingAlarm/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/values-sw600dp/styles.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceLarge</item>
+        <item name="android:lineSpacingMultiplier">1.2</item>
+        <item name="android:shadowDy">-6.5</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/repeatingAlarm/res/values/base-strings.xml
new file mode 100644
index 0000000..c11b89b
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+    <string name="app_name">repeatingAlarm</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+                Introductory text that explains what the sample is intended to demonstrate. Edit
+                in template-params.xml.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/dimens.xml b/samples/browseable/repeatingAlarm/res/values/dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/values/dimens.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+    <dimen name="margin_tiny">4dp</dimen>
+    <dimen name="margin_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="margin_large">32dp</dimen>
+    <dimen name="margin_huge">64dp</dimen>
+
+    <!-- Semantic definitions -->
+
+    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/strings.xml b/samples/browseable/repeatingAlarm/res/values/strings.xml
new file mode 100644
index 0000000..2013d95
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<resources>
+        <string name="sample_action">Set Alarm</string>
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/styles.xml b/samples/browseable/repeatingAlarm/res/values/styles.xml
new file mode 100644
index 0000000..d3f82ff
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/res/values/styles.xml
@@ -0,0 +1,51 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Activity themes -->
+
+    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+    <style name="AppTheme" parent="Theme.Base" />
+    <!-- Widget styling -->
+
+    <style name="Widget" />
+
+    <style name="Widget.SampleMessage">
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Widget.SampleMessageTile">
+        <item name="android:background">@drawable/tile</item>
+        <item name="android:shadowColor">#7F000000</item>
+        <item name="android:shadowDy">-3.5</item>
+        <item name="android:shadowRadius">2</item>
+    </style>
+
+
+    <style name="Widget.SampleOutput">
+        <item name="android:padding">@dimen/margin_medium</item>
+        <item name="android:textAppearance">?android:textAppearanceMedium</item>
+        <item name="android:lineSpacingMultiplier">1.1</item>
+    </style>
+
+    <style name="Log" parent="Widget.SampleOutput">
+        <item name="android:typeface">monospace</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+    public static final String TAG = "SampleActivityBase";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected  void onStart() {
+        super.onStart();
+        initializeLogging();
+    }
+
+    /** Set up targets to receive log data */
+    public void initializeLogging() {
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        // Wraps Android's native log framework
+        LogWrapper logWrapper = new LogWrapper();
+        Log.setLogNode(logWrapper);
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+    // Grabbing the native values from Android's native logging facilities,
+    // to make for easy migration and interop.
+    public static final int NONE = -1;
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+    public static final int DEBUG = android.util.Log.DEBUG;
+    public static final int INFO = android.util.Log.INFO;
+    public static final int WARN = android.util.Log.WARN;
+    public static final int ERROR = android.util.Log.ERROR;
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    // Stores the beginning of the LogNode topology.
+    private static LogNode mLogNode;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public static LogNode getLogNode() {
+        return mLogNode;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to.
+     */
+    public static void setLogNode(LogNode node) {
+        mLogNode = node;
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void println(int priority, String tag, String msg, Throwable tr) {
+        if (mLogNode != null) {
+            mLogNode.println(priority, tag, msg, tr);
+        }
+    }
+
+    /**
+     * Instructs the LogNode to print the log data provided. Other LogNodes can
+     * be chained to the end of the LogNode as desired.
+     *
+     * @param priority Log level of the data being logged. Verbose, Error, etc.
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     */
+    public static void println(int priority, String tag, String msg) {
+        println(priority, tag, msg, null);
+    }
+
+   /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void v(String tag, String msg, Throwable tr) {
+        println(VERBOSE, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at VERBOSE priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void v(String tag, String msg) {
+        v(tag, msg, null);
+    }
+
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void d(String tag, String msg, Throwable tr) {
+        println(DEBUG, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at DEBUG priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void d(String tag, String msg) {
+        d(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void i(String tag, String msg, Throwable tr) {
+        println(INFO, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at INFO priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void i(String tag, String msg) {
+        i(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, String msg, Throwable tr) {
+        println(WARN, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void w(String tag, String msg) {
+        w(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at WARN priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void w(String tag, Throwable tr) {
+        w(tag, null, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void e(String tag, String msg, Throwable tr) {
+        println(ERROR, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ERROR priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void e(String tag, String msg) {
+        e(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, String msg, Throwable tr) {
+        println(ASSERT, tag, msg, tr);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param msg The actual message to be logged.
+     */
+    public static void wtf(String tag, String msg) {
+        wtf(tag, msg, null);
+    }
+
+    /**
+     * Prints a message at ASSERT priority.
+     *
+     * @param tag Tag for for the log data. Can be used to organize log statements.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public static void wtf(String tag, Throwable tr) {
+        wtf(tag, null, tr);
+    }
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+    private LogView mLogView;
+    private ScrollView mScrollView;
+
+    public LogFragment() {}
+
+    public View inflateViews() {
+        mScrollView = new ScrollView(getActivity());
+        ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mScrollView.setLayoutParams(scrollParams);
+
+        mLogView = new LogView(getActivity());
+        ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+        logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        mLogView.setLayoutParams(logParams);
+        mLogView.setClickable(true);
+        mLogView.setFocusable(true);
+        mLogView.setTypeface(Typeface.MONOSPACE);
+
+        // Want to set padding as 16 dips, setPadding takes pixels.  Hooray math!
+        int paddingDips = 16;
+        double scale = getResources().getDisplayMetrics().density;
+        int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+        mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+        mLogView.setCompoundDrawablePadding(paddingPixels);
+
+        mLogView.setGravity(Gravity.BOTTOM);
+        mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+        mScrollView.addView(mLogView);
+        return mScrollView;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View result = inflateViews();
+
+        mLogView.addTextChangedListener(new TextWatcher() {
+            @Override
+            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+            @Override
+            public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+            @Override
+            public void afterTextChanged(Editable s) {
+                mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+            }
+        });
+        return result;
+    }
+
+    public LogView getLogView() {
+        return mLogView;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+    /**
+     * Instructs first LogNode in the list to print the log data provided.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+    public LogView(Context context) {
+        super(context);
+    }
+
+    public LogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public LogView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Formats the log data and prints it out to the LogView.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+
+        
+        String priorityStr = null;
+
+        // For the purposes of this View, we want to print the priority as readable text.
+        switch(priority) {
+            case android.util.Log.VERBOSE:
+                priorityStr = "VERBOSE";
+                break;
+            case android.util.Log.DEBUG:
+                priorityStr = "DEBUG";
+                break;
+            case android.util.Log.INFO:
+                priorityStr = "INFO";
+                break;
+            case android.util.Log.WARN:
+                priorityStr = "WARN";
+                break;
+            case android.util.Log.ERROR:
+                priorityStr = "ERROR";
+                break;
+            case android.util.Log.ASSERT:
+                priorityStr = "ASSERT";
+                break;
+            default:
+                break;
+        }
+
+        // Handily, the Log class has a facility for converting a stack trace into a usable string.
+        String exceptionStr = null;
+        if (tr != null) {
+            exceptionStr = android.util.Log.getStackTraceString(tr);
+        }
+
+        // Take the priority, tag, message, and exception, and concatenate as necessary
+        // into one usable line of text.
+        final StringBuilder outputBuilder = new StringBuilder();
+
+        String delimiter = "\t";
+        appendIfNotNull(outputBuilder, priorityStr, delimiter);
+        appendIfNotNull(outputBuilder, tag, delimiter);
+        appendIfNotNull(outputBuilder, msg, delimiter);
+        appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+        // In case this was originally called from an AsyncTask or some other off-UI thread,
+        // make sure the update occurs within the UI thread.
+        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+            @Override
+            public void run() {
+                // Display the text we just generated within the LogView.
+                appendToLog(outputBuilder.toString());
+            }
+        })));
+
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+     * the logger takes so many arguments that might be null, this method helps cut out some of the
+     * agonizing tedium of writing the same 3 lines over and over.
+     * @param source StringBuilder containing the text to append to.
+     * @param addStr The String to append
+     * @param delimiter The String to separate the source and appended strings. A tab or comma,
+     *                  for instance.
+     * @return The fully concatenated String as a StringBuilder
+     */
+    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+        if (addStr != null) {
+            if (addStr.length() == 0) {
+                delimiter = "";
+            }
+
+            return source.append(addStr).append(delimiter);
+        }
+        return source;
+    }
+
+    // The next LogNode in the chain.
+    LogNode mNext;
+
+    /** Outputs the string as a new line of log data in the LogView. */
+    public void appendToLog(String s) {
+        append("\n" + s);
+    }
+
+
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface.  This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+    // For piping:  The next node to receive Log data after this one has done its work.
+    private LogNode mNext;
+
+    /**
+     * Returns the next LogNode in the linked list.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+    /**
+     * Prints data out to the console using Android's native log mechanism.
+     * @param priority Log level of the data being logged.  Verbose, Error, etc.
+     * @param tag Tag for for the log data.  Can be used to organize log statements.
+     * @param msg The actual message to be logged. The actual message to be logged.
+     * @param tr If an exception was thrown, this can be sent along for the logging facilities
+     *           to extract and print useful information.
+     */
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        // There actually are log methods that don't take a msg parameter.  For now,
+        // if that's the case, just convert null to the empty string and move on.
+        String useMsg = msg;
+        if (useMsg == null) {
+            useMsg = "";
+        }
+
+        // If an exeption was provided, convert that exception to a usable string and attach
+        // it to the end of the msg method.
+        if (tr != null) {
+            msg += "\n" + Log.getStackTraceString(tr);
+        }
+
+        // This is functionally identical to Log.x(tag, useMsg);
+        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+        Log.println(priority, tag, useMsg);
+
+        // If this isn't the last node in the chain, move things along.
+        if (mNext != null) {
+            mNext.println(priority, tag, msg, tr);
+        }
+    }
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+    LogNode mNext;
+
+    /**
+     * Takes the "next" LogNode as a parameter, to simplify chaining.
+     *
+     * @param next The next LogNode in the pipeline.
+     */
+    public MessageOnlyLogFilter(LogNode next) {
+        mNext = next;
+    }
+
+    public MessageOnlyLogFilter() {
+    }
+
+    @Override
+    public void println(int priority, String tag, String msg, Throwable tr) {
+        if (mNext != null) {
+            getNext().println(Log.NONE, null, msg, null);
+        }
+    }
+
+    /**
+     * Returns the next LogNode in the chain.
+     */
+    public LogNode getNext() {
+        return mNext;
+    }
+
+    /**
+     * Sets the LogNode data will be sent to..
+     */
+    public void setNext(LogNode node) {
+        mNext = node;
+    }
+
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java b/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java
new file mode 100644
index 0000000..2d2a6aa
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java
@@ -0,0 +1,80 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+
+
+package com.example.android.repeatingalarm;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description
+ * and a few action bar buttons.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    public static final String FRAGTAG = "RepeatingAlarmFragment";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        if (getSupportFragmentManager().findFragmentByTag(FRAGTAG) == null ) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            RepeatingAlarmFragment fragment = new RepeatingAlarmFragment();
+            transaction.add(fragment, FRAGTAG);
+            transaction.commit();
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java b/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java
new file mode 100644
index 0000000..81b1e44
--- /dev/null
+++ b/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java
@@ -0,0 +1,96 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.repeatingalarm;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.support.v4.app.Fragment;
+import android.view.MenuItem;
+import com.example.android.common.logger.*;
+
+
+public class RepeatingAlarmFragment extends Fragment {
+
+    // This value is defined and consumed by app code, so any value will work.
+    // There's no significance to this sample using 0.
+    public static final int REQUEST_CODE = 0;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if(item.getItemId() == R.id.sample_action) {
+
+            // BEGIN_INCLUDE (intent_fired_by_alarm)
+            // First create an intent for the alarm to activate.
+            // This code simply starts an Activity, or brings it to the front if it has already
+            // been created.
+            Intent intent = new Intent(getActivity(), MainActivity.class);
+            intent.setAction(Intent.ACTION_MAIN);
+            intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+            // END_INCLUDE (intent_fired_by_alarm)
+
+            // BEGIN_INCLUDE (pending_intent_for_alarm)
+            // Because the intent must be fired by a system service from outside the application,
+            // it's necessary to wrap it in a PendingIntent.  Providing a different process with
+            // a PendingIntent gives that other process permission to fire the intent that this
+            // application has created.
+            // Also, this code creates a PendingIntent to start an Activity.  To create a
+            // BroadcastIntent instead, simply call getBroadcast instead of getIntent.
+            PendingIntent pendingIntent = PendingIntent.getActivity(getActivity(), REQUEST_CODE,
+                    intent, 0);
+
+            // END_INCLUDE (pending_intent_for_alarm)
+
+            // BEGIN_INCLUDE (configure_alarm_manager)
+            // There are two clock types for alarms, ELAPSED_REALTIME and RTC.
+            // ELAPSED_REALTIME uses time since system boot as a reference, and RTC uses UTC (wall
+            // clock) time.  This means ELAPSED_REALTIME is suited to setting an alarm according to
+            // passage of time (every 15 seconds, 15 minutes, etc), since it isn't affected by
+            // timezone/locale.  RTC is better suited for alarms that should be dependant on current
+            // locale.
+
+            // Both types have a WAKEUP version, which says to wake up the device if the screen is
+            // off.  This is useful for situations such as alarm clocks.  Abuse of this flag is an
+            // efficient way to skyrocket the uninstall rate of an application, so use with care.
+            // For most situations, ELAPSED_REALTIME will suffice.
+            int alarmType = AlarmManager.ELAPSED_REALTIME;
+            final int FIFTEEN_SEC_MILLIS = 15000;
+
+            // The AlarmManager, like most system services, isn't created by application code, but
+            // requested from the system.
+            AlarmManager alarmManager = (AlarmManager)
+                    getActivity().getSystemService(getActivity().ALARM_SERVICE);
+
+            // setRepeating takes a start delay and period between alarms as arguments.
+            // The below code fires after 15 seconds, and repeats every 15 seconds.  This is very
+            // useful for demonstration purposes, but horrendous for production.  Don't be that dev.
+            alarmManager.setRepeating(alarmType, SystemClock.elapsedRealtime() + FIFTEEN_SEC_MILLIS,
+                    FIFTEEN_SEC_MILLIS, pendingIntent);
+            // END_INCLUDE (configure_alarm_manager);
+            Log.i("RepeatingAlarmFragment", "Alarm set.");
+        }
+        return true;
+    }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/README b/samples/devbytes/telephony/SmsSampleProject/README
new file mode 100644
index 0000000..a26768c
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/README
@@ -0,0 +1,7 @@
+This is an Android Studio project:
+http://developer.android.com/sdk/installing/studio.html
+
+To build you should first copy local.properties.sample to
+local.properties and set your SDK path.
+
+Then use Android Studio to import the project.
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/build.gradle b/samples/devbytes/telephony/SmsSampleProject/SmsSample/build.gradle
new file mode 100644
index 0000000..d0f9b97
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/build.gradle
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+buildscript {
+    repositories {
+        mavenCentral()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:0.6.+'
+    }
+}
+apply plugin: 'android'
+
+repositories {
+    mavenCentral()
+}
+
+android {
+    compileSdkVersion 19
+    buildToolsVersion "18.1.1"
+
+    defaultConfig {
+        minSdkVersion 10
+        targetSdkVersion 19
+    }
+}
+
+dependencies {
+    compile 'com.android.support:support-v4:18.0.0'
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/AndroidManifest.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d6d4379
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/AndroidManifest.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.smssample"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="10"
+        android:targetSdkVersion="19" />
+
+    <uses-permission android:name="android.permission.WRITE_SMS" />
+    <uses-permission android:name="android.permission.READ_SMS" />
+    <uses-permission android:name="android.permission.SEND_SMS" />
+    <uses-permission android:name="android.permission.RECEIVE_SMS" />
+    <uses-permission android:name="android.permission.RECEIVE_MMS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name"
+            android:windowSoftInputMode="stateHidden">
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+
+            <intent-filter>
+                <action android:name="android.intent.action.SEND" />
+                <action android:name="android.intent.action.SENDTO" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="sms" />
+                <data android:scheme="smsto" />
+                <data android:scheme="mms" />
+                <data android:scheme="mmsto" />
+            </intent-filter>
+
+        </activity>
+
+        <!-- BroadcastReceiver that listens for incoming SMS messages -->
+        <!-- Note the use of android:enabled that is linked to a bool. This will mean this receiver
+             is enabled on KitKat devices and above -->
+        <receiver android:name=".receiver.SmsReceiver"
+                  android:enabled="@bool/hasKitKat"
+                  android:permission="android.permission.BROADCAST_SMS">
+
+            <!-- KitKat+ SMS received action -->
+            <intent-filter>
+                <action android:name="android.provider.Telephony.SMS_DELIVER" />
+            </intent-filter>
+
+        </receiver>
+
+        <!-- BroadcastReceiver that listens for incoming SMS messages -->
+        <!-- Note the use of android:enabled that is linked to a bool. This will mean this receiver
+             is enabled on preKitKat devices -->
+        <receiver android:name=".receiver.SmsReceiverLegacy"
+                  android:enabled="@bool/preKitKat">
+
+            <!-- Pre-KitKat SMS received action -->
+            <intent-filter>
+                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
+            </intent-filter>
+
+        </receiver>
+
+        <!-- BroadcastReceiver that listens for incoming MMS messages -->
+        <!-- Note the use of android:enabled that is linked to a bool. This will mean this receiver
+             is enabled on KitKat devices and above -->
+        <receiver android:name=".receiver.MmsReceiver"
+                  android:enabled="@bool/hasKitKat"
+                  android:permission="android.permission.BROADCAST_WAP_PUSH">
+
+            <!-- KitKat+ MMS received action -->
+            <intent-filter>
+                <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
+                <data android:mimeType="application/vnd.wap.mms-message" />
+            </intent-filter>
+
+        </receiver>
+
+        <!-- BroadcastReceiver that listens for incoming MMS messages -->
+        <!-- Note the use of android:enabled that is linked to a bool. This will mean this receiver
+             is enabled on preKitKat devices -->
+        <receiver android:name=".receiver.MmsReceiverLegacy"
+                  android:enabled="@bool/preKitKat">
+
+            <!-- Pre-KitKat MMS received action -->
+            <intent-filter>
+                <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
+                <data android:mimeType="application/vnd.wap.mms-message" />
+            </intent-filter>
+
+        </receiver>
+
+        <!-- Service that delivers SMS messages received from the phone "quick response" -->
+        <service android:name=".service.RespondService"
+                 android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
+                 android:exported="true" >
+            <intent-filter>
+                <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="sms" />
+                <data android:scheme="smsto" />
+                <data android:scheme="mms" />
+                <data android:scheme="mmsto" />
+            </intent-filter>
+        </service>
+
+        <!-- A service used internally to process incoming SMS/MMS -->
+        <service android:name=".service.MessagingService"
+                 android:exported="false" />
+
+    </application>
+
+</manifest>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/MainActivity.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/MainActivity.java
new file mode 100644
index 0000000..c949397
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/MainActivity.java
@@ -0,0 +1,203 @@
+/*
+ * 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.smssample;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Telephony.Sms.Inbox;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.LoaderManager.LoaderCallbacks;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.support.v4.widget.SimpleCursorAdapter;
+import android.text.TextUtils;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.RelativeLayout;
+import android.widget.Toast;
+
+/**
+ * The main Activity that provides a sample of a few things:
+ *   -detecting if this app is the default SMS app and then showing/hiding UI and enabling/disabling
+ *    functionality. the UI that is shown has a button to prompt the user to set this app as the
+ *    default.
+ *   -a simple query to the SMS content provider to show a list of SMS messages in the inbox. even
+ *    though the query uses KitKat APIs this query should still work on earlier versions of Android
+ *    as the contract class and ContentProvider were still around (with essentially the same
+ *    structure) but were private.
+ *   -being triggered from another application when creating a new SMS. a good example is creating
+ *    a new SMS from the system People application. although nothing is done with the incoming
+ *    Intent in this case (just a Toast is displayed)
+ *
+ *  Obviously this is far from a full implementation and should just be used as a sample of how
+ *  an app could be set up to correctly integrate with the new Android 4.4 KitKat APIs while
+ *  running normally on earlier Android versions.
+ */
+public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {
+    private RelativeLayout mSetDefaultSmsLayout;
+    private Button mSendSmsButton;
+    private EditText mSendSmsEditText;
+    private SimpleCursorAdapter mAdapter;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        // Find some views
+        mSetDefaultSmsLayout = (RelativeLayout) findViewById(R.id.set_default_sms_layout);
+        mSendSmsEditText = (EditText) findViewById(R.id.send_sms_edittext);
+        ListView listView = (ListView) findViewById(android.R.id.list);
+        listView.setEmptyView(findViewById(android.R.id.empty));
+        mSendSmsButton = (Button) findViewById(R.id.send_sms_button);
+        mSendSmsButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                sendSms(mSendSmsEditText.getText().toString());
+            }
+        });
+
+        // Create adapter and set it to our ListView
+        final String[] fromFields = new String[] {
+                SmsQuery.PROJECTION[SmsQuery.ADDRESS], SmsQuery.PROJECTION[SmsQuery.BODY] };
+        final int[] toViews = new int[] { android.R.id.text1, android.R.id.text2 };
+        mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, null,
+                fromFields, toViews, 0);
+        listView.setAdapter(mAdapter);
+
+        // Placeholder to process incoming SEND/SENDTO intents
+        String intentAction = getIntent() == null ? null : getIntent().getAction();
+        if (!TextUtils.isEmpty(intentAction) && (Intent.ACTION_SENDTO.equals(intentAction)
+                || Intent.ACTION_SEND.equals(intentAction))) {
+            // TODO: Handle incoming SEND and SENDTO intents by pre-populating UI components
+            Toast.makeText(this, "Handle SEND and SENDTO intents: " + getIntent().getDataString(),
+                    Toast.LENGTH_SHORT).show();
+        }
+
+        // Simple query to show the most recent SMS messages in the inbox
+        getSupportLoaderManager().initLoader(SmsQuery.TOKEN, null, this);
+    }
+
+    /**
+     * Dummy sendSms method, would need the "to" address to actually send a message :)
+     */
+    private void sendSms(String smsText) {
+        if (!TextUtils.isEmpty(smsText)) {
+            if (Utils.isDefaultSmsApp(this)) {
+                // TODO: Use SmsManager to send SMS and then record the message in the system SMS
+                // ContentProvider
+                Toast.makeText(this, "Sending text message: " + smsText, Toast.LENGTH_SHORT).show();
+            } else {
+                // TODO: Notify the user the app is not default and provide a way to trigger
+                // Utils.setDefaultSmsApp() so they can set it.
+                Toast.makeText(this, "Not default", Toast.LENGTH_SHORT).show();
+            }
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        // Only do these checks/changes on KitKat+, the "mSetDefaultSmsLayout" has its visibility
+        // set to "gone" in the xml layout so it won't show at all on earlier Android versions.
+        if (Utils.hasKitKat()) {
+            if (Utils.isDefaultSmsApp(this)) {
+                // This app is the default, remove the "make this app the default" layout and
+                // enable message sending components.
+                mSetDefaultSmsLayout.setVisibility(View.GONE);
+                mSendSmsEditText.setHint(R.string.sms_send_new_hint);
+                mSendSmsEditText.setEnabled(true);
+                mSendSmsButton.setEnabled(true);
+            } else {
+                // Not the default, show the "make this app the default" layout and disable
+                // message sending components.
+                mSetDefaultSmsLayout.setVisibility(View.VISIBLE);
+                mSendSmsEditText.setText("");
+                mSendSmsEditText.setHint(R.string.sms_send_disabled);
+                mSendSmsEditText.setEnabled(false);
+                mSendSmsButton.setEnabled(false);
+
+                Button button = (Button) findViewById(R.id.set_default_sms_button);
+                button.setOnClickListener(new OnClickListener() {
+                    @Override
+                    public void onClick(View view) {
+                        Utils.setDefaultSmsApp(MainActivity.this);
+                    }
+                });
+            }
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
+        if (i == SmsQuery.TOKEN) {
+            // This will fetch all SMS messages in the inbox, ordered by date desc
+            return new CursorLoader(this, SmsQuery.CONTENT_URI, SmsQuery.PROJECTION, null, null,
+                    SmsQuery.SORT_ORDER);
+        }
+        return null;
+    }
+
+    @Override
+    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
+        if (cursorLoader.getId() == SmsQuery.TOKEN && cursor != null) {
+            // Standard swap cursor in when load is done
+            mAdapter.swapCursor(cursor);
+        }
+    }
+
+    @Override
+    public void onLoaderReset(Loader<Cursor> cursorLoader) {
+        // Standard swap cursor to null when loader is reset
+        mAdapter.swapCursor(null);
+    }
+
+    /**
+     * A basic SmsQuery on android.provider.Telephony.Sms.Inbox
+     */
+    private interface SmsQuery {
+        int TOKEN = 1;
+
+        static final Uri CONTENT_URI = Inbox.CONTENT_URI;
+
+        static final String[] PROJECTION = {
+                Inbox._ID,
+                Inbox.ADDRESS,
+                Inbox.BODY,
+        };
+
+        static final String SORT_ORDER = Inbox.DEFAULT_SORT_ORDER;
+
+        int ID = 0;
+        int ADDRESS = 1;
+        int BODY = 2;
+    }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/Utils.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/Utils.java
new file mode 100644
index 0000000..00dc7d6
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/Utils.java
@@ -0,0 +1,68 @@
+/*
+ * 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.smssample;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.provider.Telephony;
+import android.provider.Telephony.Sms.Intents;
+
+public class Utils {
+
+    /**
+     * Check if the device runs Android 4.3 (JB MR2) or higher.
+     */
+    public static boolean hasJellyBeanMR2() {
+        return Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2;
+    }
+
+    /**
+     * Check if the device runs Android 4.4 (KitKat) or higher.
+     */
+    public static boolean hasKitKat() {
+        return Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT;
+    }
+
+    /**
+     * Check if your app is the default system SMS app.
+     * @param context The Context
+     * @return True if it is default, False otherwise. Pre-KitKat will always return True.
+     */
+    public static boolean isDefaultSmsApp(Context context) {
+        if (hasKitKat()) {
+            return context.getPackageName().equals(Telephony.Sms.getDefaultSmsPackage(context));
+        }
+
+        return true;
+    }
+
+    /**
+     * Trigger the intent to open the system dialog that asks the user to change the default
+     * SMS app.
+     * @param context The Context
+     */
+    public static void setDefaultSmsApp(Context context) {
+        // This is a new intent which only exists on KitKat
+        if (hasKitKat()) {
+            Intent intent = new Intent(Intents.ACTION_CHANGE_DEFAULT);
+            intent.putExtra(Intents.EXTRA_PACKAGE_NAME, context.getPackageName());
+            context.startActivity(intent);
+        }
+    }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MessagingReceiver.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MessagingReceiver.java
new file mode 100644
index 0000000..4dcb055
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MessagingReceiver.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.smssample.receiver;
+
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Telephony.Sms.Intents;
+import android.support.v4.content.WakefulBroadcastReceiver;
+
+import com.example.android.smssample.service.MessagingService;
+import com.example.android.smssample.Utils;
+
+/**
+ * The main messaging receiver class. Note that this is not directly included in
+ * AndroidManifest.xml, instead, subclassed versions of this are included which allows
+ * them to be enabled/disabled independently as they will have a unique component name.
+ */
+public class MessagingReceiver extends WakefulBroadcastReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent == null ? null : intent.getAction();
+
+        // If on KitKat+ and default messaging app then look for new deliver actions actions.
+        if (Utils.hasKitKat() && Utils.isDefaultSmsApp(context)) {
+            if (Intents.SMS_DELIVER_ACTION.equals(action)) {
+                handleIncomingSms(context, intent);
+            } else if (Intents.WAP_PUSH_DELIVER_ACTION.equals(action)) {
+                handleIncomingMms(context, intent);
+            }
+        } else { // Otherwise look for old pre-KitKat actions
+            if (Intents.SMS_RECEIVED_ACTION.equals(action)) {
+                handleIncomingSms(context, intent);
+            } else if (Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) {
+                handleIncomingMms(context, intent);
+            }
+        }
+    }
+
+    private void handleIncomingSms(Context context, Intent intent) {
+        // TODO: Handle SMS here
+        // As an example, we'll start a wakeful service to handle the SMS
+        intent.setAction(MessagingService.ACTION_MY_RECEIVE_SMS);
+        intent.setClass(context, MessagingService.class);
+        startWakefulService(context, intent);
+    }
+
+    private void handleIncomingMms(Context context, Intent intent) {
+        // TODO: Handle MMS here
+        // As an example, we'll start a wakeful service to handle the MMS
+        intent.setAction(MessagingService.ACTION_MY_RECEIVE_MMS);
+        intent.setClass(context, MessagingService.class);
+        startWakefulService(context, intent);
+    }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiver.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiver.java
new file mode 100644
index 0000000..40f04bb
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiver.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.smssample.receiver;
+
+/**
+ * Stub subclass to allow individual receiver components in AndroidManifest to be enabled/disabled.
+ */
+public class MmsReceiver extends MessagingReceiver {
+
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiverLegacy.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiverLegacy.java
new file mode 100644
index 0000000..181fe45
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/MmsReceiverLegacy.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.smssample.receiver;
+
+/**
+ * Stub subclass to allow individual receiver components in AndroidManifest to be enabled/disabled.
+ */
+public class MmsReceiverLegacy extends MessagingReceiver {
+
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiver.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiver.java
new file mode 100644
index 0000000..0c4a2cc
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiver.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.smssample.receiver;
+
+/**
+ * Stub subclass to allow individual receiver components in AndroidManifest to be enabled/disabled.
+ */
+public class SmsReceiver extends MessagingReceiver {
+
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiverLegacy.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiverLegacy.java
new file mode 100644
index 0000000..a02d188
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/receiver/SmsReceiverLegacy.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.smssample.receiver;
+
+/**
+ * Stub subclass to allow individual receiver components in AndroidManifest to be enabled/disabled.
+ */
+public class SmsReceiverLegacy extends MessagingReceiver {
+
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/MessagingService.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/MessagingService.java
new file mode 100644
index 0000000..af191e8
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/MessagingService.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.smssample.service;
+
+import android.app.IntentService;
+import android.content.Intent;
+
+import com.example.android.smssample.receiver.MessagingReceiver;
+
+/**
+ * This service is triggered internally only and is used to process incoming SMS and MMS messages
+ * that the {@link com.example.android.smssample.receiver.MessagingReceiver} passes over. It's
+ * preferable to handle these in a service in case there is significant work to do which may exceed
+ * the time allowed in a receiver.
+ */
+public class MessagingService extends IntentService {
+    private static final String TAG = "MessagingService";
+
+    // These actions are for this app only and are used by MessagingReceiver to start this service
+    public static final String ACTION_MY_RECEIVE_SMS = "com.example.android.smssample.RECEIVE_SMS";
+    public static final String ACTION_MY_RECEIVE_MMS = "com.example.android.smssample.RECEIVE_MMS";
+
+    public MessagingService() {
+        super(TAG);
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        if (intent != null) {
+            String intentAction = intent.getAction();
+            if (ACTION_MY_RECEIVE_SMS.equals(intentAction)) {
+                // TODO: Handle incoming SMS
+
+                // Ensure wakelock is released that was created by the WakefulBroadcastReceiver
+                MessagingReceiver.completeWakefulIntent(intent);
+            } else if (ACTION_MY_RECEIVE_MMS.equals(intentAction)) {
+                // TODO: Handle incoming MMS
+
+                // Ensure wakelock is released that was created by the WakefulBroadcastReceiver
+                MessagingReceiver.completeWakefulIntent(intent);
+            }
+        }
+    }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/RespondService.java b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/RespondService.java
new file mode 100644
index 0000000..d88a762
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/java/com/example/android/smssample/service/RespondService.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.smssample.service;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.telephony.TelephonyManager;
+
+import com.example.android.smssample.Utils;
+
+/**
+ * This service handles the system intent ACTION_RESPOND_VIA_MESSAGE when we are the default SMS
+ * app.
+ */
+public class RespondService extends IntentService {
+    private static final String TAG = "RespondService";
+
+    public RespondService() {
+        super(TAG);
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        if (intent != null) {
+            if (Utils.hasJellyBeanMR2() && Utils.isDefaultSmsApp(this) &&
+                    // ACTION_RESPOND_VIA_MESSAGE was added in JB MR2
+                    TelephonyManager.ACTION_RESPOND_VIA_MESSAGE.equals(intent.getAction())) {
+                // TODO: Handle "respond via message" quick reply
+            }
+        }
+    }
+}
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..98cfcc5
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..6ccb6e0
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..893b1ee
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xxhdpi/ic_launcher.png b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..c51e62f
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/layout/activity_main.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..3005568
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/layout/activity_main.xml
@@ -0,0 +1,93 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".MainActivity">
+
+    <RelativeLayout
+        android:id="@+id/set_default_sms_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        android:background="@color/alert_orange">
+
+        <Button
+            android:id="@+id/set_default_sms_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:layout_margin="@dimen/standard_margin"
+            android:text="@string/choose_sms_app" />
+
+        <TextView
+            android:id="@+id/set_default_sms_textview"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_toLeftOf="@+id/set_default_sms_button"
+            android:layout_centerVertical="true"
+            android:layout_margin="@dimen/standard_margin"
+            android:text="@string/set_default_sms_text" />
+
+    </RelativeLayout>
+
+    <ListView
+        android:id="@android:id/list"
+        android:layout_height="0dp"
+        android:layout_width="match_parent"
+        android:layout_weight="1"
+        android:fastScrollEnabled="true" />
+
+    <TextView
+            android:id="@android:id/empty"
+            android:layout_height="0dp"
+            android:layout_width="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:visibility="gone"
+            android:layout_margin="@dimen/standard_margin"
+            style="?android:textAppearanceMedium"
+            android:text="@string/sms_empty" />
+
+    <RelativeLayout
+            android:id="@+id/send_sms_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="@dimen/standard_margin"
+            android:background="@color/light_gray">
+
+        <Button
+                android:id="@+id/send_sms_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentRight="true"
+                android:layout_centerVertical="true"
+                android:text="@string/sms_send" />
+
+        <EditText
+                android:id="@+id/send_sms_edittext"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_toLeftOf="@+id/send_sms_button"
+                android:layout_centerVertical="true"
+                android:hint="@string/sms_send_new_hint"/>
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/menu/main.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/menu/main.xml
new file mode 100644
index 0000000..e4ee086
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/menu/main.xml
@@ -0,0 +1,23 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:id="@+id/action_default"
+        android:title="@string/action_settings"
+        android:orderInCategory="100"
+        android:showAsAction="never" />
+
+</menu>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v11/styles.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v11/styles.xml
new file mode 100644
index 0000000..425c775
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v11/styles.xml
@@ -0,0 +1,26 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+
+    <!--
+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/styles.xml on API 11+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!-- API 11 theme customizations can go here. -->
+    </style>
+
+</resources>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v19/bools.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v19/bools.xml
new file mode 100644
index 0000000..20c993a
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values-v19/bools.xml
@@ -0,0 +1,19 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+    <bool name="hasKitKat">true</bool>
+    <bool name="preKitKat">false</bool>
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/bools.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/bools.xml
new file mode 100644
index 0000000..1bded92
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/bools.xml
@@ -0,0 +1,19 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+    <bool name="hasKitKat">false</bool>
+    <bool name="preKitKat">true</bool>
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/colors.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/colors.xml
new file mode 100644
index 0000000..7f13ecd
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+    <color name="alert_orange">#FFBB33</color>
+    <color name="light_gray">#F4F4F4</color>
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/dimens.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..020e4d3
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="standard_margin">8dp</dimen>
+</resources>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/strings.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/strings.xml
new file mode 100644
index 0000000..c0f18e3
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+
+    <string name="app_name">SmsDemoApp</string>
+    <string name="action_settings">Settings</string>
+    <string name="choose_sms_app">Set as default</string>
+    <string name="sms_empty">No SMS messages</string>
+    <string name="set_default_sms_text">This app is not the default SMS app</string>
+    <string name="sms_send_new_hint">Send new SMS</string>
+    <string name="sms_send">Send</string>
+    <string name="sms_send_disabled">SMS Sending Disabled</string>
+
+</resources>
diff --git a/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/styles.xml b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/styles.xml
new file mode 100644
index 0000000..848be93
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/SmsSample/src/main/res/values/styles.xml
@@ -0,0 +1,35 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<resources>
+
+    <!--
+        Base application theme, dependent on API level. This theme is replaced
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Light">
+        <!--
+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.
+        -->
+    </style>
+
+    <!-- Application theme. -->
+    <style name="AppTheme" parent="AppBaseTheme">
+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+    </style>
+
+</resources>
diff --git a/samples/devbytes/telephony/SmsSampleProject/build.gradle b/samples/devbytes/telephony/SmsSampleProject/build.gradle
new file mode 100644
index 0000000..495c503
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/build.gradle
@@ -0,0 +1 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
diff --git a/samples/devbytes/telephony/SmsSampleProject/local.properties.sample b/samples/devbytes/telephony/SmsSampleProject/local.properties.sample
new file mode 100644
index 0000000..37317f4
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/local.properties.sample
@@ -0,0 +1,7 @@
+# This file should be copied to local.properties and path set to point
+# to your Android SDK.
+
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/usr/local/lib/android-sdk
\ No newline at end of file
diff --git a/samples/devbytes/telephony/SmsSampleProject/settings.gradle b/samples/devbytes/telephony/SmsSampleProject/settings.gradle
new file mode 100644
index 0000000..e0867f0
--- /dev/null
+++ b/samples/devbytes/telephony/SmsSampleProject/settings.gradle
@@ -0,0 +1 @@
+include ':SmsSample'
\ No newline at end of file
diff --git a/samples/devbytes/ui/ImmersiveMode/build.gradle b/samples/devbytes/ui/ImmersiveMode/build.gradle
new file mode 100644
index 0000000..da6ff35
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/build.gradle
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+buildscript {
+    repositories {
+        mavenCentral()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:0.6.+'
+    }
+}
+apply plugin: 'android'
+
+repositories {
+    mavenCentral()
+}
+
+android {
+    compileSdkVersion 19
+    buildToolsVersion "18.0.1"
+
+    defaultConfig {
+        minSdkVersion 19
+        targetSdkVersion 19
+    }
+}
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/AndroidManifest.xml b/samples/devbytes/ui/ImmersiveMode/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b4a3532
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    android:versionCode="1"
+    android:versionName="1.0"
+    package="com.example.android.immersive">
+
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+
+    <application android:icon="@drawable/ic_launcher"
+        android:label="@string/immersive_mode"
+        android:allowBackup="true">
+
+        <activity android:name=".ImmersiveActivity"
+            android:label="@string/immersive_mode"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:theme="@style/ImmersiveTheme">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".ImmersiveStickyActivity"
+            android:taskAffinity=""
+            android:label="@string/immersive_sticky"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:theme="@style/ImmersiveStickyTheme">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveActivity.java b/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveActivity.java
new file mode 100644
index 0000000..8fdde08
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveActivity.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.immersive;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+
+public class ImmersiveActivity extends Activity {
+    private static final int INITIAL_HIDE_DELAY = 300;
+
+    private View mDecorView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.immersive_activity);
+
+        final View controlsView = findViewById(R.id.fullscreen_content_controls);
+        final View contentView = findViewById(R.id.fullscreen_content);
+
+        mDecorView = getWindow().getDecorView();
+        mDecorView.setOnSystemUiVisibilityChangeListener(
+                new View.OnSystemUiVisibilityChangeListener() {
+                    @Override
+                    public void onSystemUiVisibilityChange(int flags) {
+                        boolean visible = (flags & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+                        controlsView.animate()
+                                .alpha(visible ? 1 : 0)
+                                .translationY(visible ? 0 : controlsView.getHeight());
+                    }
+                });
+        contentView.setClickable(true);
+        final GestureDetector clickDetector = new GestureDetector(this,
+                new GestureDetector.SimpleOnGestureListener() {
+                    @Override
+                    public boolean onSingleTapUp(MotionEvent e) {
+                        boolean visible = (mDecorView.getSystemUiVisibility()
+                                & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+                        if (visible) {
+                            hideSystemUI();
+                        } else {
+                            showSystemUI();
+                        }
+                        return true;
+                    }
+                });
+        contentView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View view, MotionEvent motionEvent) {
+                return clickDetector.onTouchEvent(motionEvent);
+            }
+        });
+
+        showSystemUI();
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+
+        // When the window loses focus (e.g. the action overflow is shown),
+        // cancel any pending hide action. When the window gains focus,
+        // hide the system UI.
+        if (hasFocus) {
+            delayedHide(INITIAL_HIDE_DELAY);
+        } else {
+            mHideHandler.removeMessages(0);
+        }
+    }
+
+    private void hideSystemUI() {
+        mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_LOW_PROFILE
+                | View.SYSTEM_UI_FLAG_IMMERSIVE);
+    }
+
+    private void showSystemUI() {
+        mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+    }
+
+    private final Handler mHideHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            hideSystemUI();
+        }
+    };
+
+    private void delayedHide(int delayMillis) {
+        mHideHandler.removeMessages(0);
+        mHideHandler.sendEmptyMessageDelayed(0, delayMillis);
+    }
+}
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveStickyActivity.java b/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveStickyActivity.java
new file mode 100644
index 0000000..d6dfd36
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/java/com/example/android/immersive/ImmersiveStickyActivity.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.immersive;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+
+public class ImmersiveStickyActivity extends Activity {
+    private View mDecorView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.immersive_sticky_activity);
+        mDecorView = getWindow().getDecorView();
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        if (hasFocus) {
+            mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+        }
+    }
+}
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher.png b/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f47fc32
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher_translucent_actionbar.png b/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher_translucent_actionbar.png
new file mode 100644
index 0000000..bf344ad
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/drawable-xxhdpi/ic_launcher_translucent_actionbar.png
Binary files differ
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_activity.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_activity.xml
new file mode 100644
index 0000000..e4ce455
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_activity.xml
@@ -0,0 +1,50 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <include layout="@layout/include_content" />
+
+    <!-- This FrameLayout insets its children based on system windows using
+         android:fitsSystemWindows. These insets will be stable across system
+         UI visibility changes because we use the SYSTEM_UI_FLAG_LAYOUT_STABLE
+         flag in addition to SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and
+         SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION. -->
+    <FrameLayout android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipToPadding="false"
+        android:fitsSystemWindows="true">
+
+        <LinearLayout android:id="@+id/fullscreen_content_controls"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom|center_horizontal"
+            android:background="@color/fullscreen_control_overlay_color"
+            android:orientation="horizontal">
+
+            <Button android:id="@+id/placeholder_button"
+                android:layout_width="0dp"
+                android:layout_height="48dp"
+                android:layout_weight="1"
+                android:text="@string/placeholder_button"
+                android:background="?android:selectableItemBackground" />
+
+        </LinearLayout>
+    </FrameLayout>
+
+</FrameLayout>
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_sticky_activity.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_sticky_activity.xml
new file mode 100644
index 0000000..b98b923
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/immersive_sticky_activity.xml
@@ -0,0 +1,23 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <include layout="@layout/include_content" />
+
+</FrameLayout>
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/include_content.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/include_content.xml
new file mode 100644
index 0000000..967573b
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/layout/include_content.xml
@@ -0,0 +1,31 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<!-- The primary full-screen view. This can be replaced with whatever view
+     is needed to present your content, e.g. VideoView, SurfaceView,
+     TextureView, etc. -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/fullscreen_content"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:keepScreenOn="true"
+    android:textColor="#fb3"
+    android:fontFamily="sans-serif-condensed"
+    android:textStyle="bold"
+    android:lineSpacingMultiplier="0.8"
+    android:textSize="50sp"
+    android:gravity="center"
+    android:text="@string/placeholder_content" />
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/values/colors.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/colors.xml
new file mode 100644
index 0000000..7e91c50
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/colors.xml
@@ -0,0 +1,20 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <color name="background">#f80</color>
+    <color name="fullscreen_control_overlay_color">#66000000</color>
+</resources>
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/values/strings.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/strings.xml
new file mode 100644
index 0000000..3c520f9
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/strings.xml
@@ -0,0 +1,22 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="immersive_mode">Immersive Mode</string>
+    <string name="immersive_sticky">Immersive/Sticky</string>
+    <string name="placeholder_button">Placeholder Button</string>
+    <string name="placeholder_content">IMMERSIVE\nCONTENT</string>
+</resources>
diff --git a/samples/devbytes/ui/ImmersiveMode/src/main/res/values/styles.xml b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/styles.xml
new file mode 100644
index 0000000..2d7d458
--- /dev/null
+++ b/samples/devbytes/ui/ImmersiveMode/src/main/res/values/styles.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="ImmersiveTheme" parent="android:Theme.Holo">
+        <item name="android:windowBackground">@color/background</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowActionBarOverlay">true</item>
+        <item name="android:actionBarStyle">@style/ImmersiveActionBarStyle</item>
+    </style>
+
+    <style name="ImmersiveStickyTheme" parent="ImmersiveTheme">
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowActionBar">false</item>
+    </style>
+
+    <style name="ImmersiveActionBarStyle" parent="android:Widget.Holo.ActionBar.Solid">
+        <item name="android:background">@color/fullscreen_control_overlay_color</item>
+        <item name="android:icon">@drawable/ic_launcher_translucent_actionbar</item>
+    </style>
+
+</resources>
diff --git a/samples/samples_source.prop_template b/samples/samples_source.prop_template
index d3cdfd5..3d4fac5 100644
--- a/samples/samples_source.prop_template
+++ b/samples/samples_source.prop_template
@@ -1,4 +1,4 @@
 Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=3
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
diff --git a/samples/training/bitmapfun/AndroidManifest.xml b/samples/training/bitmapfun/AndroidManifest.xml
deleted file mode 100644
index bc1c180..0000000
--- a/samples/training/bitmapfun/AndroidManifest.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2012 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.bitmapfun"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-    <uses-sdk
-        android:minSdkVersion="7"
-        android:targetSdkVersion="17" />
-
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-
-    <application
-        android:description="@string/app_description"
-        android:hardwareAccelerated="true"
-        android:icon="@drawable/ic_launcher"
-        android:label="@string/app_name" >
-        <activity
-            android:name=".ui.ImageDetailActivity"
-            android:label="@string/app_name"
-            android:parentActivityName=".ui.ImageGridActivity"
-            android:theme="@style/AppTheme.FullScreen" >
-            <meta-data android:name="android.support.PARENT_ACTIVITY"
-                       android:value=".ui.ImageGridActivity" />
-        </activity>
-        <activity
-            android:name=".ui.ImageGridActivity"
-            android:label="@string/app_name"
-            android:theme="@style/AppTheme" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/samples/training/bitmapfun/BitmapFun/build.gradle b/samples/training/bitmapfun/BitmapFun/build.gradle
new file mode 100644
index 0000000..28bb0d8
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/build.gradle
@@ -0,0 +1,27 @@
+buildscript {
+    repositories {
+        mavenCentral()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:0.6.+'
+    }
+}
+apply plugin: 'android'
+
+repositories {
+    mavenCentral()
+}
+
+android {
+    compileSdkVersion 19
+    buildToolsVersion "18.1.1"
+
+    defaultConfig {
+        minSdkVersion 7
+        targetSdkVersion 19
+    }
+}
+
+dependencies {
+    compile 'com.android.support:support-v4:18.0.0'
+}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/AndroidManifest.xml b/samples/training/bitmapfun/BitmapFun/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..9ca5cf5
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/AndroidManifest.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2012 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.bitmapfun"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="7"
+        android:targetSdkVersion="19" />
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+    <application
+        android:description="@string/app_description"
+        android:hardwareAccelerated="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:allowBackup="false">
+        <activity
+            android:name=".ui.ImageDetailActivity"
+            android:label="@string/app_name"
+            android:parentActivityName=".ui.ImageGridActivity"
+            android:theme="@style/AppTheme.FullScreen" >
+            <meta-data android:name="android.support.PARENT_ACTIVITY"
+                       android:value=".ui.ImageGridActivity" />
+        </activity>
+        <activity
+            android:name=".ui.ImageGridActivity"
+            android:label="@string/app_name"
+            android:theme="@style/AppTheme" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/provider/Images.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/provider/Images.java
new file mode 100644
index 0000000..fcf4496
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/provider/Images.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.bitmapfun.provider;
+
+/**
+ * Some simple test data to use for this sample app.
+ */
+public class Images {
+
+    /**
+     * This are PicasaWeb URLs and could potentially change. Ideally the PicasaWeb API should be
+     * used to fetch the URLs.
+     *
+     * Credit to Romain Guy for the photos:
+     * http://www.curious-creature.org/
+     * https://plus.google.com/109538161516040592207/about
+     * http://www.flickr.com/photos/romainguy
+     */
+    public final static String[] imageUrls = new String[] {
+            "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg",
+            "https://lh4.googleusercontent.com/--dq8niRp7W4/URquVgmXvgI/AAAAAAAAAbs/-gnuLQfNnBA/s1024/A%252520Song%252520of%252520Ice%252520and%252520Fire.jpg",
+            "https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s1024/Another%252520Rockaway%252520Sunset.jpg",
+            "https://lh3.googleusercontent.com/--L0Km39l5J8/URquXHGcdNI/AAAAAAAAAbs/3ZrSJNrSomQ/s1024/Antelope%252520Butte.jpg",
+            "https://lh6.googleusercontent.com/-8HO-4vIFnlw/URquZnsFgtI/AAAAAAAAAbs/WT8jViTF7vw/s1024/Antelope%252520Hallway.jpg",
+            "https://lh4.googleusercontent.com/-WIuWgVcU3Qw/URqubRVcj4I/AAAAAAAAAbs/YvbwgGjwdIQ/s1024/Antelope%252520Walls.jpg",
+            "https://lh6.googleusercontent.com/-UBmLbPELvoQ/URqucCdv0kI/AAAAAAAAAbs/IdNhr2VQoQs/s1024/Apre%2525CC%252580s%252520la%252520Pluie.jpg",
+            "https://lh3.googleusercontent.com/-s-AFpvgSeew/URquc6dF-JI/AAAAAAAAAbs/Mt3xNGRUd68/s1024/Backlit%252520Cloud.jpg",
+            "https://lh5.googleusercontent.com/-bvmif9a9YOQ/URquea3heHI/AAAAAAAAAbs/rcr6wyeQtAo/s1024/Bee%252520and%252520Flower.jpg",
+            "https://lh5.googleusercontent.com/-n7mdm7I7FGs/URqueT_BT-I/AAAAAAAAAbs/9MYmXlmpSAo/s1024/Bonzai%252520Rock%252520Sunset.jpg",
+            "https://lh6.googleusercontent.com/-4CN4X4t0M1k/URqufPozWzI/AAAAAAAAAbs/8wK41lg1KPs/s1024/Caterpillar.jpg",
+            "https://lh3.googleusercontent.com/-rrFnVC8xQEg/URqufdrLBaI/AAAAAAAAAbs/s69WYy_fl1E/s1024/Chess.jpg",
+            "https://lh5.googleusercontent.com/-WVpRptWH8Yw/URqugh-QmDI/AAAAAAAAAbs/E-MgBgtlUWU/s1024/Chihuly.jpg",
+            "https://lh5.googleusercontent.com/-0BDXkYmckbo/URquhKFW84I/AAAAAAAAAbs/ogQtHCTk2JQ/s1024/Closed%252520Door.jpg",
+            "https://lh3.googleusercontent.com/-PyggXXZRykM/URquh-kVvoI/AAAAAAAAAbs/hFtDwhtrHHQ/s1024/Colorado%252520River%252520Sunset.jpg",
+            "https://lh3.googleusercontent.com/-ZAs4dNZtALc/URquikvOCWI/AAAAAAAAAbs/DXz4h3dll1Y/s1024/Colors%252520of%252520Autumn.jpg",
+            "https://lh4.googleusercontent.com/-GztnWEIiMz8/URqukVCU7bI/AAAAAAAAAbs/jo2Hjv6MZ6M/s1024/Countryside.jpg",
+            "https://lh4.googleusercontent.com/-bEg9EZ9QoiM/URquklz3FGI/AAAAAAAAAbs/UUuv8Ac2BaE/s1024/Death%252520Valley%252520-%252520Dunes.jpg",
+            "https://lh6.googleusercontent.com/-ijQJ8W68tEE/URqulGkvFEI/AAAAAAAAAbs/zPXvIwi_rFw/s1024/Delicate%252520Arch.jpg",
+            "https://lh5.googleusercontent.com/-Oh8mMy2ieng/URqullDwehI/AAAAAAAAAbs/TbdeEfsaIZY/s1024/Despair.jpg",
+            "https://lh5.googleusercontent.com/-gl0y4UiAOlk/URqumC_KjBI/AAAAAAAAAbs/PM1eT7dn4oo/s1024/Eagle%252520Fall%252520Sunrise.jpg",
+            "https://lh3.googleusercontent.com/-hYYHd2_vXPQ/URqumtJa9eI/AAAAAAAAAbs/wAalXVkbSh0/s1024/Electric%252520Storm.jpg",
+            "https://lh5.googleusercontent.com/-PyY_yiyjPTo/URqunUOhHFI/AAAAAAAAAbs/azZoULNuJXc/s1024/False%252520Kiva.jpg",
+            "https://lh6.googleusercontent.com/-PYvLVdvXywk/URqunwd8hfI/AAAAAAAAAbs/qiMwgkFvf6I/s1024/Fitzgerald%252520Streaks.jpg",
+            "https://lh4.googleusercontent.com/-KIR_UobIIqY/URquoCZ9SlI/AAAAAAAAAbs/Y4d4q8sXu4c/s1024/Foggy%252520Sunset.jpg",
+            "https://lh6.googleusercontent.com/-9lzOk_OWZH0/URquoo4xYoI/AAAAAAAAAbs/AwgzHtNVCwU/s1024/Frantic.jpg",
+            "https://lh3.googleusercontent.com/-0X3JNaKaz48/URqupH78wpI/AAAAAAAAAbs/lHXxu_zbH8s/s1024/Golden%252520Gate%252520Afternoon.jpg",
+            "https://lh6.googleusercontent.com/-95sb5ag7ABc/URqupl95RDI/AAAAAAAAAbs/g73R20iVTRA/s1024/Golden%252520Gate%252520Fog.jpg",
+            "https://lh3.googleusercontent.com/-JB9v6rtgHhk/URqup21F-zI/AAAAAAAAAbs/64Fb8qMZWXk/s1024/Golden%252520Grass.jpg",
+            "https://lh4.googleusercontent.com/-EIBGfnuLtII/URquqVHwaRI/AAAAAAAAAbs/FA4McV2u8VE/s1024/Grand%252520Teton.jpg",
+            "https://lh4.googleusercontent.com/-WoMxZvmN9nY/URquq1v2AoI/AAAAAAAAAbs/grj5uMhL6NA/s1024/Grass%252520Closeup.jpg",
+            "https://lh3.googleusercontent.com/-6hZiEHXx64Q/URqurxvNdqI/AAAAAAAAAbs/kWMXM3o5OVI/s1024/Green%252520Grass.jpg",
+            "https://lh5.googleusercontent.com/-6LVb9OXtQ60/URquteBFuKI/AAAAAAAAAbs/4F4kRgecwFs/s1024/Hanging%252520Leaf.jpg",
+            "https://lh4.googleusercontent.com/-zAvf__52ONk/URqutT_IuxI/AAAAAAAAAbs/D_bcuc0thoU/s1024/Highway%2525201.jpg",
+            "https://lh6.googleusercontent.com/-H4SrUg615rA/URquuL27fXI/AAAAAAAAAbs/4aEqJfiMsOU/s1024/Horseshoe%252520Bend%252520Sunset.jpg",
+            "https://lh4.googleusercontent.com/-JhFi4fb_Pqw/URquuX-QXbI/AAAAAAAAAbs/IXpYUxuweYM/s1024/Horseshoe%252520Bend.jpg",
+            "https://lh5.googleusercontent.com/-UGgssvFRJ7g/URquueyJzGI/AAAAAAAAAbs/yYIBlLT0toM/s1024/Into%252520the%252520Blue.jpg",
+            "https://lh3.googleusercontent.com/-CH7KoupI7uI/URquu0FF__I/AAAAAAAAAbs/R7GDmI7v_G0/s1024/Jelly%252520Fish%2525202.jpg",
+            "https://lh4.googleusercontent.com/-pwuuw6yhg8U/URquvPxR3FI/AAAAAAAAAbs/VNGk6f-tsGE/s1024/Jelly%252520Fish%2525203.jpg",
+            "https://lh5.googleusercontent.com/-GoUQVw1fnFw/URquv6xbC0I/AAAAAAAAAbs/zEUVTQQ43Zc/s1024/Kauai.jpg",
+            "https://lh6.googleusercontent.com/-8QdYYQEpYjw/URquwvdh88I/AAAAAAAAAbs/cktDy-ysfHo/s1024/Kyoto%252520Sunset.jpg",
+            "https://lh4.googleusercontent.com/-vPeekyDjOE0/URquwzJ28qI/AAAAAAAAAbs/qxcyXULsZrg/s1024/Lake%252520Tahoe%252520Colors.jpg",
+            "https://lh4.googleusercontent.com/-xBPxWpD4yxU/URquxWHk8AI/AAAAAAAAAbs/ARDPeDYPiMY/s1024/Lava%252520from%252520the%252520Sky.jpg",
+            "https://lh3.googleusercontent.com/-897VXrJB6RE/URquxxxd-5I/AAAAAAAAAbs/j-Cz4T4YvIw/s1024/Leica%25252050mm%252520Summilux.jpg",
+            "https://lh5.googleusercontent.com/-qSJ4D4iXzGo/URquyDWiJ1I/AAAAAAAAAbs/k2pBXeWehOA/s1024/Leica%25252050mm%252520Summilux.jpg",
+            "https://lh6.googleusercontent.com/-dwlPg83vzLg/URquylTVuFI/AAAAAAAAAbs/G6SyQ8b4YsI/s1024/Leica%252520M8%252520%252528Front%252529.jpg",
+            "https://lh3.googleusercontent.com/-R3_EYAyJvfk/URquzQBv8eI/AAAAAAAAAbs/b9xhpUM3pEI/s1024/Light%252520to%252520Sand.jpg",
+            "https://lh3.googleusercontent.com/-fHY5h67QPi0/URqu0Cp4J1I/AAAAAAAAAbs/0lG6m94Z6vM/s1024/Little%252520Bit%252520of%252520Paradise.jpg",
+            "https://lh5.googleusercontent.com/-TzF_LwrCnRM/URqu0RddPOI/AAAAAAAAAbs/gaj2dLiuX0s/s1024/Lone%252520Pine%252520Sunset.jpg",
+            "https://lh3.googleusercontent.com/-4HdpJ4_DXU4/URqu046dJ9I/AAAAAAAAAbs/eBOodtk2_uk/s1024/Lonely%252520Rock.jpg",
+            "https://lh6.googleusercontent.com/-erbF--z-W4s/URqu1ajSLkI/AAAAAAAAAbs/xjDCDO1INzM/s1024/Longue%252520Vue.jpg",
+            "https://lh6.googleusercontent.com/-0CXJRdJaqvc/URqu1opNZNI/AAAAAAAAAbs/PFB2oPUU7Lk/s1024/Look%252520Me%252520in%252520the%252520Eye.jpg",
+            "https://lh3.googleusercontent.com/-D_5lNxnDN6g/URqu2Tk7HVI/AAAAAAAAAbs/p0ddca9W__Y/s1024/Lost%252520in%252520a%252520Field.jpg",
+            "https://lh6.googleusercontent.com/-flsqwMrIk2Q/URqu24PcmjI/AAAAAAAAAbs/5ocIH85XofM/s1024/Marshall%252520Beach%252520Sunset.jpg",
+            "https://lh4.googleusercontent.com/-Y4lgryEVTmU/URqu28kG3gI/AAAAAAAAAbs/OjXpekqtbJ4/s1024/Mono%252520Lake%252520Blue.jpg",
+            "https://lh4.googleusercontent.com/-AaHAJPmcGYA/URqu3PIldHI/AAAAAAAAAbs/lcTqk1SIcRs/s1024/Monument%252520Valley%252520Overlook.jpg",
+            "https://lh4.googleusercontent.com/-vKxfdQ83dQA/URqu31Yq_BI/AAAAAAAAAbs/OUoGk_2AyfM/s1024/Moving%252520Rock.jpg",
+            "https://lh5.googleusercontent.com/-CG62QiPpWXg/URqu4ia4vRI/AAAAAAAAAbs/0YOdqLAlcAc/s1024/Napali%252520Coast.jpg",
+            "https://lh6.googleusercontent.com/-wdGrP5PMmJQ/URqu5PZvn7I/AAAAAAAAAbs/m0abEcdPXe4/s1024/One%252520Wheel.jpg",
+            "https://lh6.googleusercontent.com/-6WS5DoCGuOA/URqu5qx1UgI/AAAAAAAAAbs/giMw2ixPvrY/s1024/Open%252520Sky.jpg",
+            "https://lh6.googleusercontent.com/-u8EHKj8G8GQ/URqu55sM6yI/AAAAAAAAAbs/lIXX_GlTdmI/s1024/Orange%252520Sunset.jpg",
+            "https://lh6.googleusercontent.com/-74Z5qj4bTDE/URqu6LSrJrI/AAAAAAAAAbs/XzmVkw90szQ/s1024/Orchid.jpg",
+            "https://lh6.googleusercontent.com/-lEQE4h6TePE/URqu6t_lSkI/AAAAAAAAAbs/zvGYKOea_qY/s1024/Over%252520there.jpg",
+            "https://lh5.googleusercontent.com/-cauH-53JH2M/URqu66v_USI/AAAAAAAAAbs/EucwwqclfKQ/s1024/Plumes.jpg",
+            "https://lh3.googleusercontent.com/-eDLT2jHDoy4/URqu7axzkAI/AAAAAAAAAbs/iVZE-xJ7lZs/s1024/Rainbokeh.jpg",
+            "https://lh5.googleusercontent.com/-j1NLqEFIyco/URqu8L1CGcI/AAAAAAAAAbs/aqZkgX66zlI/s1024/Rainbow.jpg",
+            "https://lh5.googleusercontent.com/-DRnqmK0t4VU/URqu8XYN9yI/AAAAAAAAAbs/LgvF_592WLU/s1024/Rice%252520Fields.jpg",
+            "https://lh3.googleusercontent.com/-hwh1v3EOGcQ/URqu8qOaKwI/AAAAAAAAAbs/IljRJRnbJGw/s1024/Rockaway%252520Fire%252520Sky.jpg",
+            "https://lh5.googleusercontent.com/-wjV6FQk7tlk/URqu9jCQ8sI/AAAAAAAAAbs/RyYUpdo-c9o/s1024/Rockaway%252520Flow.jpg",
+            "https://lh6.googleusercontent.com/-6cAXNfo7D20/URqu-BdzgPI/AAAAAAAAAbs/OmsYllzJqwo/s1024/Rockaway%252520Sunset%252520Sky.jpg",
+            "https://lh3.googleusercontent.com/-sl8fpGPS-RE/URqu_BOkfgI/AAAAAAAAAbs/Dg2Fv-JxOeg/s1024/Russian%252520Ridge%252520Sunset.jpg",
+            "https://lh6.googleusercontent.com/-gVtY36mMBIg/URqu_q91lkI/AAAAAAAAAbs/3CiFMBcy5MA/s1024/Rust%252520Knot.jpg",
+            "https://lh6.googleusercontent.com/-GHeImuHqJBE/URqu_FKfVLI/AAAAAAAAAbs/axuEJeqam7Q/s1024/Sailing%252520Stones.jpg",
+            "https://lh3.googleusercontent.com/-hBbYZjTOwGc/URqu_ycpIrI/AAAAAAAAAbs/nAdJUXnGJYE/s1024/Seahorse.jpg",
+            "https://lh3.googleusercontent.com/-Iwi6-i6IexY/URqvAYZHsVI/AAAAAAAAAbs/5ETWl4qXsFE/s1024/Shinjuku%252520Street.jpg",
+            "https://lh6.googleusercontent.com/-amhnySTM_MY/URqvAlb5KoI/AAAAAAAAAbs/pFCFgzlKsn0/s1024/Sierra%252520Heavens.jpg",
+            "https://lh5.googleusercontent.com/-dJgjepFrYSo/URqvBVJZrAI/AAAAAAAAAbs/v-F5QWpYO6s/s1024/Sierra%252520Sunset.jpg",
+            "https://lh4.googleusercontent.com/-Z4zGiC5nWdc/URqvBdEwivI/AAAAAAAAAbs/ZRZR1VJ84QA/s1024/Sin%252520Lights.jpg",
+            "https://lh4.googleusercontent.com/-_0cYiWW8ccY/URqvBz3iM4I/AAAAAAAAAbs/9N_Wq8MhLTY/s1024/Starry%252520Lake.jpg",
+            "https://lh3.googleusercontent.com/-A9LMoRyuQUA/URqvCYx_JoI/AAAAAAAAAbs/s7sde1Bz9cI/s1024/Starry%252520Night.jpg",
+            "https://lh3.googleusercontent.com/-KtLJ3k858eY/URqvC_2h_bI/AAAAAAAAAbs/zzEBImwDA_g/s1024/Stream.jpg",
+            "https://lh5.googleusercontent.com/-dFB7Lad6RcA/URqvDUftwWI/AAAAAAAAAbs/BrhoUtXTN7o/s1024/Strip%252520Sunset.jpg",
+            "https://lh5.googleusercontent.com/-at6apgFiN20/URqvDyffUZI/AAAAAAAAAbs/clABCx171bE/s1024/Sunset%252520Hills.jpg",
+            "https://lh4.googleusercontent.com/-7-EHhtQthII/URqvEYTk4vI/AAAAAAAAAbs/QSJZoB3YjVg/s1024/Tenaya%252520Lake%2525202.jpg",
+            "https://lh6.googleusercontent.com/-8MrjV_a-Pok/URqvFC5repI/AAAAAAAAAbs/9inKTg9fbCE/s1024/Tenaya%252520Lake.jpg",
+            "https://lh5.googleusercontent.com/-B1HW-z4zwao/URqvFWYRwUI/AAAAAAAAAbs/8Peli53Bs8I/s1024/The%252520Cave%252520BW.jpg",
+            "https://lh3.googleusercontent.com/-PO4E-xZKAnQ/URqvGRqjYkI/AAAAAAAAAbs/42nyADFsXag/s1024/The%252520Fisherman.jpg",
+            "https://lh4.googleusercontent.com/-iLyZlzfdy7s/URqvG0YScdI/AAAAAAAAAbs/1J9eDKmkXtk/s1024/The%252520Night%252520is%252520Coming.jpg",
+            "https://lh6.googleusercontent.com/-G-k7YkkUco0/URqvHhah6fI/AAAAAAAAAbs/_taQQG7t0vo/s1024/The%252520Road.jpg",
+            "https://lh6.googleusercontent.com/-h-ALJt7kSus/URqvIThqYfI/AAAAAAAAAbs/ejiv35olWS8/s1024/Tokyo%252520Heights.jpg",
+            "https://lh5.googleusercontent.com/-Hy9k-TbS7xg/URqvIjQMOxI/AAAAAAAAAbs/RSpmmOATSkg/s1024/Tokyo%252520Highway.jpg",
+            "https://lh6.googleusercontent.com/-83oOvMb4OZs/URqvJL0T7lI/AAAAAAAAAbs/c5TECZ6RONM/s1024/Tokyo%252520Smog.jpg",
+            "https://lh3.googleusercontent.com/-FB-jfgREEfI/URqvJI3EXAI/AAAAAAAAAbs/XfyweiRF4v8/s1024/Tufa%252520at%252520Night.jpg",
+            "https://lh4.googleusercontent.com/-vngKD5Z1U8w/URqvJUCEgPI/AAAAAAAAAbs/ulxCMVcU6EU/s1024/Valley%252520Sunset.jpg",
+            "https://lh6.googleusercontent.com/-DOz5I2E2oMQ/URqvKMND1kI/AAAAAAAAAbs/Iqf0IsInleo/s1024/Windmill%252520Sunrise.jpg",
+            "https://lh5.googleusercontent.com/-biyiyWcJ9MU/URqvKculiAI/AAAAAAAAAbs/jyPsCplJOpE/s1024/Windmill.jpg",
+            "https://lh4.googleusercontent.com/-PDT167_xRdA/URqvK36mLcI/AAAAAAAAAbs/oi2ik9QseMI/s1024/Windmills.jpg",
+            "https://lh5.googleusercontent.com/-kI_QdYx7VlU/URqvLXCB6gI/AAAAAAAAAbs/N31vlZ6u89o/s1024/Yet%252520Another%252520Rockaway%252520Sunset.jpg",
+            "https://lh4.googleusercontent.com/-e9NHZ5k5MSs/URqvMIBZjtI/AAAAAAAAAbs/1fV810rDNfQ/s1024/Yosemite%252520Tree.jpg",
+    };
+
+    /**
+     * This are PicasaWeb thumbnail URLs and could potentially change. Ideally the PicasaWeb API
+     * should be used to fetch the URLs.
+     *
+     * Credit to Romain Guy for the photos:
+     * http://www.curious-creature.org/
+     * https://plus.google.com/109538161516040592207/about
+     * http://www.flickr.com/photos/romainguy
+     */
+    public final static String[] imageThumbUrls = new String[] {
+            "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s240-c/A%252520Photographer.jpg",
+            "https://lh4.googleusercontent.com/--dq8niRp7W4/URquVgmXvgI/AAAAAAAAAbs/-gnuLQfNnBA/s240-c/A%252520Song%252520of%252520Ice%252520and%252520Fire.jpg",
+            "https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s240-c/Another%252520Rockaway%252520Sunset.jpg",
+            "https://lh3.googleusercontent.com/--L0Km39l5J8/URquXHGcdNI/AAAAAAAAAbs/3ZrSJNrSomQ/s240-c/Antelope%252520Butte.jpg",
+            "https://lh6.googleusercontent.com/-8HO-4vIFnlw/URquZnsFgtI/AAAAAAAAAbs/WT8jViTF7vw/s240-c/Antelope%252520Hallway.jpg",
+            "https://lh4.googleusercontent.com/-WIuWgVcU3Qw/URqubRVcj4I/AAAAAAAAAbs/YvbwgGjwdIQ/s240-c/Antelope%252520Walls.jpg",
+            "https://lh6.googleusercontent.com/-UBmLbPELvoQ/URqucCdv0kI/AAAAAAAAAbs/IdNhr2VQoQs/s240-c/Apre%2525CC%252580s%252520la%252520Pluie.jpg",
+            "https://lh3.googleusercontent.com/-s-AFpvgSeew/URquc6dF-JI/AAAAAAAAAbs/Mt3xNGRUd68/s240-c/Backlit%252520Cloud.jpg",
+            "https://lh5.googleusercontent.com/-bvmif9a9YOQ/URquea3heHI/AAAAAAAAAbs/rcr6wyeQtAo/s240-c/Bee%252520and%252520Flower.jpg",
+            "https://lh5.googleusercontent.com/-n7mdm7I7FGs/URqueT_BT-I/AAAAAAAAAbs/9MYmXlmpSAo/s240-c/Bonzai%252520Rock%252520Sunset.jpg",
+            "https://lh6.googleusercontent.com/-4CN4X4t0M1k/URqufPozWzI/AAAAAAAAAbs/8wK41lg1KPs/s240-c/Caterpillar.jpg",
+            "https://lh3.googleusercontent.com/-rrFnVC8xQEg/URqufdrLBaI/AAAAAAAAAbs/s69WYy_fl1E/s240-c/Chess.jpg",
+            "https://lh5.googleusercontent.com/-WVpRptWH8Yw/URqugh-QmDI/AAAAAAAAAbs/E-MgBgtlUWU/s240-c/Chihuly.jpg",
+            "https://lh5.googleusercontent.com/-0BDXkYmckbo/URquhKFW84I/AAAAAAAAAbs/ogQtHCTk2JQ/s240-c/Closed%252520Door.jpg",
+            "https://lh3.googleusercontent.com/-PyggXXZRykM/URquh-kVvoI/AAAAAAAAAbs/hFtDwhtrHHQ/s240-c/Colorado%252520River%252520Sunset.jpg",
+            "https://lh3.googleusercontent.com/-ZAs4dNZtALc/URquikvOCWI/AAAAAAAAAbs/DXz4h3dll1Y/s240-c/Colors%252520of%252520Autumn.jpg",
+            "https://lh4.googleusercontent.com/-GztnWEIiMz8/URqukVCU7bI/AAAAAAAAAbs/jo2Hjv6MZ6M/s240-c/Countryside.jpg",
+            "https://lh4.googleusercontent.com/-bEg9EZ9QoiM/URquklz3FGI/AAAAAAAAAbs/UUuv8Ac2BaE/s240-c/Death%252520Valley%252520-%252520Dunes.jpg",
+            "https://lh6.googleusercontent.com/-ijQJ8W68tEE/URqulGkvFEI/AAAAAAAAAbs/zPXvIwi_rFw/s240-c/Delicate%252520Arch.jpg",
+            "https://lh5.googleusercontent.com/-Oh8mMy2ieng/URqullDwehI/AAAAAAAAAbs/TbdeEfsaIZY/s240-c/Despair.jpg",
+            "https://lh5.googleusercontent.com/-gl0y4UiAOlk/URqumC_KjBI/AAAAAAAAAbs/PM1eT7dn4oo/s240-c/Eagle%252520Fall%252520Sunrise.jpg",
+            "https://lh3.googleusercontent.com/-hYYHd2_vXPQ/URqumtJa9eI/AAAAAAAAAbs/wAalXVkbSh0/s240-c/Electric%252520Storm.jpg",
+            "https://lh5.googleusercontent.com/-PyY_yiyjPTo/URqunUOhHFI/AAAAAAAAAbs/azZoULNuJXc/s240-c/False%252520Kiva.jpg",
+            "https://lh6.googleusercontent.com/-PYvLVdvXywk/URqunwd8hfI/AAAAAAAAAbs/qiMwgkFvf6I/s240-c/Fitzgerald%252520Streaks.jpg",
+            "https://lh4.googleusercontent.com/-KIR_UobIIqY/URquoCZ9SlI/AAAAAAAAAbs/Y4d4q8sXu4c/s240-c/Foggy%252520Sunset.jpg",
+            "https://lh6.googleusercontent.com/-9lzOk_OWZH0/URquoo4xYoI/AAAAAAAAAbs/AwgzHtNVCwU/s240-c/Frantic.jpg",
+            "https://lh3.googleusercontent.com/-0X3JNaKaz48/URqupH78wpI/AAAAAAAAAbs/lHXxu_zbH8s/s240-c/Golden%252520Gate%252520Afternoon.jpg",
+            "https://lh6.googleusercontent.com/-95sb5ag7ABc/URqupl95RDI/AAAAAAAAAbs/g73R20iVTRA/s240-c/Golden%252520Gate%252520Fog.jpg",
+            "https://lh3.googleusercontent.com/-JB9v6rtgHhk/URqup21F-zI/AAAAAAAAAbs/64Fb8qMZWXk/s240-c/Golden%252520Grass.jpg",
+            "https://lh4.googleusercontent.com/-EIBGfnuLtII/URquqVHwaRI/AAAAAAAAAbs/FA4McV2u8VE/s240-c/Grand%252520Teton.jpg",
+            "https://lh4.googleusercontent.com/-WoMxZvmN9nY/URquq1v2AoI/AAAAAAAAAbs/grj5uMhL6NA/s240-c/Grass%252520Closeup.jpg",
+            "https://lh3.googleusercontent.com/-6hZiEHXx64Q/URqurxvNdqI/AAAAAAAAAbs/kWMXM3o5OVI/s240-c/Green%252520Grass.jpg",
+            "https://lh5.googleusercontent.com/-6LVb9OXtQ60/URquteBFuKI/AAAAAAAAAbs/4F4kRgecwFs/s240-c/Hanging%252520Leaf.jpg",
+            "https://lh4.googleusercontent.com/-zAvf__52ONk/URqutT_IuxI/AAAAAAAAAbs/D_bcuc0thoU/s240-c/Highway%2525201.jpg",
+            "https://lh6.googleusercontent.com/-H4SrUg615rA/URquuL27fXI/AAAAAAAAAbs/4aEqJfiMsOU/s240-c/Horseshoe%252520Bend%252520Sunset.jpg",
+            "https://lh4.googleusercontent.com/-JhFi4fb_Pqw/URquuX-QXbI/AAAAAAAAAbs/IXpYUxuweYM/s240-c/Horseshoe%252520Bend.jpg",
+            "https://lh5.googleusercontent.com/-UGgssvFRJ7g/URquueyJzGI/AAAAAAAAAbs/yYIBlLT0toM/s240-c/Into%252520the%252520Blue.jpg",
+            "https://lh3.googleusercontent.com/-CH7KoupI7uI/URquu0FF__I/AAAAAAAAAbs/R7GDmI7v_G0/s240-c/Jelly%252520Fish%2525202.jpg",
+            "https://lh4.googleusercontent.com/-pwuuw6yhg8U/URquvPxR3FI/AAAAAAAAAbs/VNGk6f-tsGE/s240-c/Jelly%252520Fish%2525203.jpg",
+            "https://lh5.googleusercontent.com/-GoUQVw1fnFw/URquv6xbC0I/AAAAAAAAAbs/zEUVTQQ43Zc/s240-c/Kauai.jpg",
+            "https://lh6.googleusercontent.com/-8QdYYQEpYjw/URquwvdh88I/AAAAAAAAAbs/cktDy-ysfHo/s240-c/Kyoto%252520Sunset.jpg",
+            "https://lh4.googleusercontent.com/-vPeekyDjOE0/URquwzJ28qI/AAAAAAAAAbs/qxcyXULsZrg/s240-c/Lake%252520Tahoe%252520Colors.jpg",
+            "https://lh4.googleusercontent.com/-xBPxWpD4yxU/URquxWHk8AI/AAAAAAAAAbs/ARDPeDYPiMY/s240-c/Lava%252520from%252520the%252520Sky.jpg",
+            "https://lh3.googleusercontent.com/-897VXrJB6RE/URquxxxd-5I/AAAAAAAAAbs/j-Cz4T4YvIw/s240-c/Leica%25252050mm%252520Summilux.jpg",
+            "https://lh5.googleusercontent.com/-qSJ4D4iXzGo/URquyDWiJ1I/AAAAAAAAAbs/k2pBXeWehOA/s240-c/Leica%25252050mm%252520Summilux.jpg",
+            "https://lh6.googleusercontent.com/-dwlPg83vzLg/URquylTVuFI/AAAAAAAAAbs/G6SyQ8b4YsI/s240-c/Leica%252520M8%252520%252528Front%252529.jpg",
+            "https://lh3.googleusercontent.com/-R3_EYAyJvfk/URquzQBv8eI/AAAAAAAAAbs/b9xhpUM3pEI/s240-c/Light%252520to%252520Sand.jpg",
+            "https://lh3.googleusercontent.com/-fHY5h67QPi0/URqu0Cp4J1I/AAAAAAAAAbs/0lG6m94Z6vM/s240-c/Little%252520Bit%252520of%252520Paradise.jpg",
+            "https://lh5.googleusercontent.com/-TzF_LwrCnRM/URqu0RddPOI/AAAAAAAAAbs/gaj2dLiuX0s/s240-c/Lone%252520Pine%252520Sunset.jpg",
+            "https://lh3.googleusercontent.com/-4HdpJ4_DXU4/URqu046dJ9I/AAAAAAAAAbs/eBOodtk2_uk/s240-c/Lonely%252520Rock.jpg",
+            "https://lh6.googleusercontent.com/-erbF--z-W4s/URqu1ajSLkI/AAAAAAAAAbs/xjDCDO1INzM/s240-c/Longue%252520Vue.jpg",
+            "https://lh6.googleusercontent.com/-0CXJRdJaqvc/URqu1opNZNI/AAAAAAAAAbs/PFB2oPUU7Lk/s240-c/Look%252520Me%252520in%252520the%252520Eye.jpg",
+            "https://lh3.googleusercontent.com/-D_5lNxnDN6g/URqu2Tk7HVI/AAAAAAAAAbs/p0ddca9W__Y/s240-c/Lost%252520in%252520a%252520Field.jpg",
+            "https://lh6.googleusercontent.com/-flsqwMrIk2Q/URqu24PcmjI/AAAAAAAAAbs/5ocIH85XofM/s240-c/Marshall%252520Beach%252520Sunset.jpg",
+            "https://lh4.googleusercontent.com/-Y4lgryEVTmU/URqu28kG3gI/AAAAAAAAAbs/OjXpekqtbJ4/s240-c/Mono%252520Lake%252520Blue.jpg",
+            "https://lh4.googleusercontent.com/-AaHAJPmcGYA/URqu3PIldHI/AAAAAAAAAbs/lcTqk1SIcRs/s240-c/Monument%252520Valley%252520Overlook.jpg",
+            "https://lh4.googleusercontent.com/-vKxfdQ83dQA/URqu31Yq_BI/AAAAAAAAAbs/OUoGk_2AyfM/s240-c/Moving%252520Rock.jpg",
+            "https://lh5.googleusercontent.com/-CG62QiPpWXg/URqu4ia4vRI/AAAAAAAAAbs/0YOdqLAlcAc/s240-c/Napali%252520Coast.jpg",
+            "https://lh6.googleusercontent.com/-wdGrP5PMmJQ/URqu5PZvn7I/AAAAAAAAAbs/m0abEcdPXe4/s240-c/One%252520Wheel.jpg",
+            "https://lh6.googleusercontent.com/-6WS5DoCGuOA/URqu5qx1UgI/AAAAAAAAAbs/giMw2ixPvrY/s240-c/Open%252520Sky.jpg",
+            "https://lh6.googleusercontent.com/-u8EHKj8G8GQ/URqu55sM6yI/AAAAAAAAAbs/lIXX_GlTdmI/s240-c/Orange%252520Sunset.jpg",
+            "https://lh6.googleusercontent.com/-74Z5qj4bTDE/URqu6LSrJrI/AAAAAAAAAbs/XzmVkw90szQ/s240-c/Orchid.jpg",
+            "https://lh6.googleusercontent.com/-lEQE4h6TePE/URqu6t_lSkI/AAAAAAAAAbs/zvGYKOea_qY/s240-c/Over%252520there.jpg",
+            "https://lh5.googleusercontent.com/-cauH-53JH2M/URqu66v_USI/AAAAAAAAAbs/EucwwqclfKQ/s240-c/Plumes.jpg",
+            "https://lh3.googleusercontent.com/-eDLT2jHDoy4/URqu7axzkAI/AAAAAAAAAbs/iVZE-xJ7lZs/s240-c/Rainbokeh.jpg",
+            "https://lh5.googleusercontent.com/-j1NLqEFIyco/URqu8L1CGcI/AAAAAAAAAbs/aqZkgX66zlI/s240-c/Rainbow.jpg",
+            "https://lh5.googleusercontent.com/-DRnqmK0t4VU/URqu8XYN9yI/AAAAAAAAAbs/LgvF_592WLU/s240-c/Rice%252520Fields.jpg",
+            "https://lh3.googleusercontent.com/-hwh1v3EOGcQ/URqu8qOaKwI/AAAAAAAAAbs/IljRJRnbJGw/s240-c/Rockaway%252520Fire%252520Sky.jpg",
+            "https://lh5.googleusercontent.com/-wjV6FQk7tlk/URqu9jCQ8sI/AAAAAAAAAbs/RyYUpdo-c9o/s240-c/Rockaway%252520Flow.jpg",
+            "https://lh6.googleusercontent.com/-6cAXNfo7D20/URqu-BdzgPI/AAAAAAAAAbs/OmsYllzJqwo/s240-c/Rockaway%252520Sunset%252520Sky.jpg",
+            "https://lh3.googleusercontent.com/-sl8fpGPS-RE/URqu_BOkfgI/AAAAAAAAAbs/Dg2Fv-JxOeg/s240-c/Russian%252520Ridge%252520Sunset.jpg",
+            "https://lh6.googleusercontent.com/-gVtY36mMBIg/URqu_q91lkI/AAAAAAAAAbs/3CiFMBcy5MA/s240-c/Rust%252520Knot.jpg",
+            "https://lh6.googleusercontent.com/-GHeImuHqJBE/URqu_FKfVLI/AAAAAAAAAbs/axuEJeqam7Q/s240-c/Sailing%252520Stones.jpg",
+            "https://lh3.googleusercontent.com/-hBbYZjTOwGc/URqu_ycpIrI/AAAAAAAAAbs/nAdJUXnGJYE/s240-c/Seahorse.jpg",
+            "https://lh3.googleusercontent.com/-Iwi6-i6IexY/URqvAYZHsVI/AAAAAAAAAbs/5ETWl4qXsFE/s240-c/Shinjuku%252520Street.jpg",
+            "https://lh6.googleusercontent.com/-amhnySTM_MY/URqvAlb5KoI/AAAAAAAAAbs/pFCFgzlKsn0/s240-c/Sierra%252520Heavens.jpg",
+            "https://lh5.googleusercontent.com/-dJgjepFrYSo/URqvBVJZrAI/AAAAAAAAAbs/v-F5QWpYO6s/s240-c/Sierra%252520Sunset.jpg",
+            "https://lh4.googleusercontent.com/-Z4zGiC5nWdc/URqvBdEwivI/AAAAAAAAAbs/ZRZR1VJ84QA/s240-c/Sin%252520Lights.jpg",
+            "https://lh4.googleusercontent.com/-_0cYiWW8ccY/URqvBz3iM4I/AAAAAAAAAbs/9N_Wq8MhLTY/s240-c/Starry%252520Lake.jpg",
+            "https://lh3.googleusercontent.com/-A9LMoRyuQUA/URqvCYx_JoI/AAAAAAAAAbs/s7sde1Bz9cI/s240-c/Starry%252520Night.jpg",
+            "https://lh3.googleusercontent.com/-KtLJ3k858eY/URqvC_2h_bI/AAAAAAAAAbs/zzEBImwDA_g/s240-c/Stream.jpg",
+            "https://lh5.googleusercontent.com/-dFB7Lad6RcA/URqvDUftwWI/AAAAAAAAAbs/BrhoUtXTN7o/s240-c/Strip%252520Sunset.jpg",
+            "https://lh5.googleusercontent.com/-at6apgFiN20/URqvDyffUZI/AAAAAAAAAbs/clABCx171bE/s240-c/Sunset%252520Hills.jpg",
+            "https://lh4.googleusercontent.com/-7-EHhtQthII/URqvEYTk4vI/AAAAAAAAAbs/QSJZoB3YjVg/s240-c/Tenaya%252520Lake%2525202.jpg",
+            "https://lh6.googleusercontent.com/-8MrjV_a-Pok/URqvFC5repI/AAAAAAAAAbs/9inKTg9fbCE/s240-c/Tenaya%252520Lake.jpg",
+            "https://lh5.googleusercontent.com/-B1HW-z4zwao/URqvFWYRwUI/AAAAAAAAAbs/8Peli53Bs8I/s240-c/The%252520Cave%252520BW.jpg",
+            "https://lh3.googleusercontent.com/-PO4E-xZKAnQ/URqvGRqjYkI/AAAAAAAAAbs/42nyADFsXag/s240-c/The%252520Fisherman.jpg",
+            "https://lh4.googleusercontent.com/-iLyZlzfdy7s/URqvG0YScdI/AAAAAAAAAbs/1J9eDKmkXtk/s240-c/The%252520Night%252520is%252520Coming.jpg",
+            "https://lh6.googleusercontent.com/-G-k7YkkUco0/URqvHhah6fI/AAAAAAAAAbs/_taQQG7t0vo/s240-c/The%252520Road.jpg",
+            "https://lh6.googleusercontent.com/-h-ALJt7kSus/URqvIThqYfI/AAAAAAAAAbs/ejiv35olWS8/s240-c/Tokyo%252520Heights.jpg",
+            "https://lh5.googleusercontent.com/-Hy9k-TbS7xg/URqvIjQMOxI/AAAAAAAAAbs/RSpmmOATSkg/s240-c/Tokyo%252520Highway.jpg",
+            "https://lh6.googleusercontent.com/-83oOvMb4OZs/URqvJL0T7lI/AAAAAAAAAbs/c5TECZ6RONM/s240-c/Tokyo%252520Smog.jpg",
+            "https://lh3.googleusercontent.com/-FB-jfgREEfI/URqvJI3EXAI/AAAAAAAAAbs/XfyweiRF4v8/s240-c/Tufa%252520at%252520Night.jpg",
+            "https://lh4.googleusercontent.com/-vngKD5Z1U8w/URqvJUCEgPI/AAAAAAAAAbs/ulxCMVcU6EU/s240-c/Valley%252520Sunset.jpg",
+            "https://lh6.googleusercontent.com/-DOz5I2E2oMQ/URqvKMND1kI/AAAAAAAAAbs/Iqf0IsInleo/s240-c/Windmill%252520Sunrise.jpg",
+            "https://lh5.googleusercontent.com/-biyiyWcJ9MU/URqvKculiAI/AAAAAAAAAbs/jyPsCplJOpE/s240-c/Windmill.jpg",
+            "https://lh4.googleusercontent.com/-PDT167_xRdA/URqvK36mLcI/AAAAAAAAAbs/oi2ik9QseMI/s240-c/Windmills.jpg",
+            "https://lh5.googleusercontent.com/-kI_QdYx7VlU/URqvLXCB6gI/AAAAAAAAAbs/N31vlZ6u89o/s240-c/Yet%252520Another%252520Rockaway%252520Sunset.jpg",
+            "https://lh4.googleusercontent.com/-e9NHZ5k5MSs/URqvMIBZjtI/AAAAAAAAAbs/1fV810rDNfQ/s240-c/Yosemite%252520Tree.jpg",
+    };
+}
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/ImageDetailActivity.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailActivity.java
similarity index 100%
rename from samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/ImageDetailActivity.java
rename to samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailActivity.java
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/ImageDetailFragment.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailFragment.java
similarity index 100%
rename from samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/ImageDetailFragment.java
rename to samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailFragment.java
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridActivity.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridActivity.java
new file mode 100644
index 0000000..e7c7d1c
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridActivity.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.bitmapfun.ui;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+
+import com.example.android.bitmapfun.BuildConfig;
+import com.example.android.bitmapfun.util.Utils;
+
+/**
+ * Simple FragmentActivity to hold the main {@link ImageGridFragment} and not much else.
+ */
+public class ImageGridActivity extends FragmentActivity {
+    private static final String TAG = "ImageGridActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        if (BuildConfig.DEBUG) {
+            Utils.enableStrictMode();
+        }
+        super.onCreate(savedInstanceState);
+
+        if (getSupportFragmentManager().findFragmentByTag(TAG) == null) {
+            final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+            ft.add(android.R.id.content, new ImageGridFragment(), TAG);
+            ft.commit();
+        }
+    }
+}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridFragment.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridFragment.java
new file mode 100644
index 0000000..a968326
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridFragment.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.bitmapfun.ui;
+
+import android.annotation.TargetApi;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewTreeObserver;
+import android.widget.AbsListView;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import com.example.android.bitmapfun.BuildConfig;
+import com.example.android.bitmapfun.R;
+import com.example.android.bitmapfun.provider.Images;
+import com.example.android.bitmapfun.util.ImageCache.ImageCacheParams;
+import com.example.android.bitmapfun.util.ImageFetcher;
+import com.example.android.bitmapfun.util.Utils;
+
+/**
+ * The main fragment that powers the ImageGridActivity screen. Fairly straight forward GridView
+ * implementation with the key addition being the ImageWorker class w/ImageCache to load children
+ * asynchronously, keeping the UI nice and smooth and caching thumbnails for quick retrieval. The
+ * cache is retained over configuration changes like orientation change so the images are populated
+ * quickly if, for example, the user rotates the device.
+ */
+public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
+    private static final String TAG = "ImageGridFragment";
+    private static final String IMAGE_CACHE_DIR = "thumbs";
+
+    private int mImageThumbSize;
+    private int mImageThumbSpacing;
+    private ImageAdapter mAdapter;
+    private ImageFetcher mImageFetcher;
+
+    /**
+     * Empty constructor as per the Fragment documentation
+     */
+    public ImageGridFragment() {}
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+
+        mImageThumbSize = getResources().getDimensionPixelSize(R.dimen.image_thumbnail_size);
+        mImageThumbSpacing = getResources().getDimensionPixelSize(R.dimen.image_thumbnail_spacing);
+
+        mAdapter = new ImageAdapter(getActivity());
+
+        ImageCacheParams cacheParams = new ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
+
+        cacheParams.setMemCacheSizePercent(0.25f); // Set memory cache to 25% of app memory
+
+        // The ImageFetcher takes care of loading images into our ImageView children asynchronously
+        mImageFetcher = new ImageFetcher(getActivity(), mImageThumbSize);
+        mImageFetcher.setLoadingImage(R.drawable.empty_photo);
+        mImageFetcher.addImageCache(getActivity().getSupportFragmentManager(), cacheParams);
+    }
+
+    @Override
+    public View onCreateView(
+            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        final View v = inflater.inflate(R.layout.image_grid_fragment, container, false);
+        final GridView mGridView = (GridView) v.findViewById(R.id.gridView);
+        mGridView.setAdapter(mAdapter);
+        mGridView.setOnItemClickListener(this);
+        mGridView.setOnScrollListener(new AbsListView.OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(AbsListView absListView, int scrollState) {
+                // Pause fetcher to ensure smoother scrolling when flinging
+                if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
+                    // Before Honeycomb pause image loading on scroll to help with performance
+                    if (!Utils.hasHoneycomb()) {
+                        mImageFetcher.setPauseWork(true);
+                    }
+                } else {
+                    mImageFetcher.setPauseWork(false);
+                }
+            }
+
+            @Override
+            public void onScroll(AbsListView absListView, int firstVisibleItem,
+                    int visibleItemCount, int totalItemCount) {
+            }
+        });
+
+        // This listener is used to get the final width of the GridView and then calculate the
+        // number of columns and the width of each column. The width of each column is variable
+        // as the GridView has stretchMode=columnWidth. The column width is used to set the height
+        // of each view so we get nice square thumbnails.
+        mGridView.getViewTreeObserver().addOnGlobalLayoutListener(
+                new ViewTreeObserver.OnGlobalLayoutListener() {
+                    @Override
+                    public void onGlobalLayout() {
+                        if (mAdapter.getNumColumns() == 0) {
+                            final int numColumns = (int) Math.floor(
+                                    mGridView.getWidth() / (mImageThumbSize + mImageThumbSpacing));
+                            if (numColumns > 0) {
+                                final int columnWidth =
+                                        (mGridView.getWidth() / numColumns) - mImageThumbSpacing;
+                                mAdapter.setNumColumns(numColumns);
+                                mAdapter.setItemHeight(columnWidth);
+                                if (BuildConfig.DEBUG) {
+                                    Log.d(TAG, "onCreateView - numColumns set to " + numColumns);
+                                }
+                            }
+                        }
+                    }
+                });
+
+        return v;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mImageFetcher.setExitTasksEarly(false);
+        mAdapter.notifyDataSetChanged();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mImageFetcher.setPauseWork(false);
+        mImageFetcher.setExitTasksEarly(true);
+        mImageFetcher.flushCache();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mImageFetcher.closeCache();
+    }
+
+    @TargetApi(16)
+    @Override
+    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+        final Intent i = new Intent(getActivity(), ImageDetailActivity.class);
+        i.putExtra(ImageDetailActivity.EXTRA_IMAGE, (int) id);
+        if (Utils.hasJellyBean()) {
+            // makeThumbnailScaleUpAnimation() looks kind of ugly here as the loading spinner may
+            // show plus the thumbnail image in GridView is cropped. so using
+            // makeScaleUpAnimation() instead.
+            ActivityOptions options =
+                    ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getWidth(), v.getHeight());
+            getActivity().startActivity(i, options.toBundle());
+        } else {
+            startActivity(i);
+        }
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        inflater.inflate(R.menu.main_menu, menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.clear_cache:
+                mImageFetcher.clearCache();
+                Toast.makeText(getActivity(), R.string.clear_cache_complete_toast,
+                        Toast.LENGTH_SHORT).show();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /**
+     * The main adapter that backs the GridView. This is fairly standard except the number of
+     * columns in the GridView is used to create a fake top row of empty views as we use a
+     * transparent ActionBar and don't want the real top row of images to start off covered by it.
+     */
+    private class ImageAdapter extends BaseAdapter {
+
+        private final Context mContext;
+        private int mItemHeight = 0;
+        private int mNumColumns = 0;
+        private int mActionBarHeight = 0;
+        private GridView.LayoutParams mImageViewLayoutParams;
+
+        public ImageAdapter(Context context) {
+            super();
+            mContext = context;
+            mImageViewLayoutParams = new GridView.LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+            // Calculate ActionBar height
+            TypedValue tv = new TypedValue();
+            if (context.getTheme().resolveAttribute(
+                    android.R.attr.actionBarSize, tv, true)) {
+                mActionBarHeight = TypedValue.complexToDimensionPixelSize(
+                        tv.data, context.getResources().getDisplayMetrics());
+            }
+        }
+
+        @Override
+        public int getCount() {
+            // Size + number of columns for top empty row
+            return Images.imageThumbUrls.length + mNumColumns;
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return position < mNumColumns ?
+                    null : Images.imageThumbUrls[position - mNumColumns];
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position < mNumColumns ? 0 : position - mNumColumns;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            // Two types of views, the normal ImageView and the top row of empty views
+            return 2;
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            return (position < mNumColumns) ? 1 : 0;
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return true;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup container) {
+            // First check if this is the top row
+            if (position < mNumColumns) {
+                if (convertView == null) {
+                    convertView = new View(mContext);
+                }
+                // Set empty view with height of ActionBar
+                convertView.setLayoutParams(new AbsListView.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT, mActionBarHeight));
+                return convertView;
+            }
+
+            // Now handle the main ImageView thumbnails
+            ImageView imageView;
+            if (convertView == null) { // if it's not recycled, instantiate and initialize
+                imageView = new RecyclingImageView(mContext);
+                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+                imageView.setLayoutParams(mImageViewLayoutParams);
+            } else { // Otherwise re-use the converted view
+                imageView = (ImageView) convertView;
+            }
+
+            // Check the height matches our calculated column width
+            if (imageView.getLayoutParams().height != mItemHeight) {
+                imageView.setLayoutParams(mImageViewLayoutParams);
+            }
+
+            // Finally load the image asynchronously into the ImageView, this also takes care of
+            // setting a placeholder image while the background thread runs
+            mImageFetcher.loadImage(Images.imageThumbUrls[position - mNumColumns], imageView);
+            return imageView;
+        }
+
+        /**
+         * Sets the item height. Useful for when we know the column width so the height can be set
+         * to match.
+         *
+         * @param height
+         */
+        public void setItemHeight(int height) {
+            if (height == mItemHeight) {
+                return;
+            }
+            mItemHeight = height;
+            mImageViewLayoutParams =
+                    new GridView.LayoutParams(LayoutParams.MATCH_PARENT, mItemHeight);
+            mImageFetcher.setImageSize(height);
+            notifyDataSetChanged();
+        }
+
+        public void setNumColumns(int numColumns) {
+            mNumColumns = numColumns;
+        }
+
+        public int getNumColumns() {
+            return mNumColumns;
+        }
+    }
+}
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/RecyclingImageView.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/RecyclingImageView.java
similarity index 100%
rename from samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/RecyclingImageView.java
rename to samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/RecyclingImageView.java
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/AsyncTask.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/AsyncTask.java
similarity index 100%
rename from samples/training/bitmapfun/src/com/example/android/bitmapfun/util/AsyncTask.java
rename to samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/AsyncTask.java
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/DiskLruCache.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/DiskLruCache.java
similarity index 100%
rename from samples/training/bitmapfun/src/com/example/android/bitmapfun/util/DiskLruCache.java
rename to samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/DiskLruCache.java
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageCache.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageCache.java
new file mode 100644
index 0000000..145c881
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageCache.java
@@ -0,0 +1,721 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.bitmapfun.util;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.StatFs;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.util.LruCache;
+import android.util.Log;
+
+import com.example.android.bitmapfun.BuildConfig;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.ref.SoftReference;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * This class handles disk and memory caching of bitmaps in conjunction with the
+ * {@link ImageWorker} class and its subclasses. Use
+ * {@link ImageCache#getInstance(FragmentManager, ImageCacheParams)} to get an instance of this
+ * class, although usually a cache should be added directly to an {@link ImageWorker} by calling
+ * {@link ImageWorker#addImageCache(FragmentManager, ImageCacheParams)}.
+ */
+public class ImageCache {
+    private static final String TAG = "ImageCache";
+
+    // Default memory cache size in kilobytes
+    private static final int DEFAULT_MEM_CACHE_SIZE = 1024 * 5; // 5MB
+
+    // Default disk cache size in bytes
+    private static final int DEFAULT_DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
+
+    // Compression settings when writing images to disk cache
+    private static final CompressFormat DEFAULT_COMPRESS_FORMAT = CompressFormat.JPEG;
+    private static final int DEFAULT_COMPRESS_QUALITY = 70;
+    private static final int DISK_CACHE_INDEX = 0;
+
+    // Constants to easily toggle various caches
+    private static final boolean DEFAULT_MEM_CACHE_ENABLED = true;
+    private static final boolean DEFAULT_DISK_CACHE_ENABLED = true;
+    private static final boolean DEFAULT_INIT_DISK_CACHE_ON_CREATE = false;
+
+    private DiskLruCache mDiskLruCache;
+    private LruCache<String, BitmapDrawable> mMemoryCache;
+    private ImageCacheParams mCacheParams;
+    private final Object mDiskCacheLock = new Object();
+    private boolean mDiskCacheStarting = true;
+
+    private Set<SoftReference<Bitmap>> mReusableBitmaps;
+
+    /**
+     * Create a new ImageCache object using the specified parameters. This should not be
+     * called directly by other classes, instead use
+     * {@link ImageCache#getInstance(FragmentManager, ImageCacheParams)} to fetch an ImageCache
+     * instance.
+     *
+     * @param cacheParams The cache parameters to use to initialize the cache
+     */
+    private ImageCache(ImageCacheParams cacheParams) {
+        init(cacheParams);
+    }
+
+    /**
+     * Return an {@link ImageCache} instance. A {@link RetainFragment} is used to retain the
+     * ImageCache object across configuration changes such as a change in device orientation.
+     *
+     * @param fragmentManager The fragment manager to use when dealing with the retained fragment.
+     * @param cacheParams The cache parameters to use if the ImageCache needs instantiation.
+     * @return An existing retained ImageCache object or a new one if one did not exist
+     */
+    public static ImageCache getInstance(
+            FragmentManager fragmentManager, ImageCacheParams cacheParams) {
+
+        // Search for, or create an instance of the non-UI RetainFragment
+        final RetainFragment mRetainFragment = findOrCreateRetainFragment(fragmentManager);
+
+        // See if we already have an ImageCache stored in RetainFragment
+        ImageCache imageCache = (ImageCache) mRetainFragment.getObject();
+
+        // No existing ImageCache, create one and store it in RetainFragment
+        if (imageCache == null) {
+            imageCache = new ImageCache(cacheParams);
+            mRetainFragment.setObject(imageCache);
+        }
+
+        return imageCache;
+    }
+
+    /**
+     * Initialize the cache, providing all parameters.
+     *
+     * @param cacheParams The cache parameters to initialize the cache
+     */
+    private void init(ImageCacheParams cacheParams) {
+        mCacheParams = cacheParams;
+
+        // Set up memory cache
+        if (mCacheParams.memoryCacheEnabled) {
+            if (BuildConfig.DEBUG) {
+                Log.d(TAG, "Memory cache created (size = " + mCacheParams.memCacheSize + ")");
+            }
+
+            // If we're running on Honeycomb or newer, create a set of reusable bitmaps that can be
+            // populated into the inBitmap field of BitmapFactory.Options. Note that the set is
+            // of SoftReferences which will actually not be very effective due to the garbage
+            // collector being aggressive clearing Soft/WeakReferences. A better approach
+            // would be to use a strongly references bitmaps, however this would require some
+            // balancing of memory usage between this set and the bitmap LruCache. It would also
+            // require knowledge of the expected size of the bitmaps. From Honeycomb to JellyBean
+            // the size would need to be precise, from KitKat onward the size would just need to
+            // be the upper bound (due to changes in how inBitmap can re-use bitmaps).
+            if (Utils.hasHoneycomb()) {
+                mReusableBitmaps =
+                        Collections.synchronizedSet(new HashSet<SoftReference<Bitmap>>());
+            }
+
+            mMemoryCache = new LruCache<String, BitmapDrawable>(mCacheParams.memCacheSize) {
+
+                /**
+                 * Notify the removed entry that is no longer being cached
+                 */
+                @Override
+                protected void entryRemoved(boolean evicted, String key,
+                        BitmapDrawable oldValue, BitmapDrawable newValue) {
+                    if (RecyclingBitmapDrawable.class.isInstance(oldValue)) {
+                        // The removed entry is a recycling drawable, so notify it 
+                        // that it has been removed from the memory cache
+                        ((RecyclingBitmapDrawable) oldValue).setIsCached(false);
+                    } else {
+                        // The removed entry is a standard BitmapDrawable
+
+                        if (Utils.hasHoneycomb()) {
+                            // We're running on Honeycomb or later, so add the bitmap
+                            // to a SoftReference set for possible use with inBitmap later
+                            mReusableBitmaps.add(new SoftReference<Bitmap>(oldValue.getBitmap()));
+                        }
+                    }
+                }
+
+                /**
+                 * Measure item size in kilobytes rather than units which is more practical
+                 * for a bitmap cache
+                 */
+                @Override
+                protected int sizeOf(String key, BitmapDrawable value) {
+                    final int bitmapSize = getBitmapSize(value) / 1024;
+                    return bitmapSize == 0 ? 1 : bitmapSize;
+                }
+            };
+        }
+
+        // By default the disk cache is not initialized here as it should be initialized
+        // on a separate thread due to disk access.
+        if (cacheParams.initDiskCacheOnCreate) {
+            // Set up disk cache
+            initDiskCache();
+        }
+    }
+
+    /**
+     * Initializes the disk cache.  Note that this includes disk access so this should not be
+     * executed on the main/UI thread. By default an ImageCache does not initialize the disk
+     * cache when it is created, instead you should call initDiskCache() to initialize it on a
+     * background thread.
+     */
+    public void initDiskCache() {
+        // Set up disk cache
+        synchronized (mDiskCacheLock) {
+            if (mDiskLruCache == null || mDiskLruCache.isClosed()) {
+                File diskCacheDir = mCacheParams.diskCacheDir;
+                if (mCacheParams.diskCacheEnabled && diskCacheDir != null) {
+                    if (!diskCacheDir.exists()) {
+                        diskCacheDir.mkdirs();
+                    }
+                    if (getUsableSpace(diskCacheDir) > mCacheParams.diskCacheSize) {
+                        try {
+                            mDiskLruCache = DiskLruCache.open(
+                                    diskCacheDir, 1, 1, mCacheParams.diskCacheSize);
+                            if (BuildConfig.DEBUG) {
+                                Log.d(TAG, "Disk cache initialized");
+                            }
+                        } catch (final IOException e) {
+                            mCacheParams.diskCacheDir = null;
+                            Log.e(TAG, "initDiskCache - " + e);
+                        }
+                    }
+                }
+            }
+            mDiskCacheStarting = false;
+            mDiskCacheLock.notifyAll();
+        }
+    }
+
+    /**
+     * Adds a bitmap to both memory and disk cache.
+     * @param data Unique identifier for the bitmap to store
+     * @param value The bitmap drawable to store
+     */
+    public void addBitmapToCache(String data, BitmapDrawable value) {
+        if (data == null || value == null) {
+            return;
+        }
+
+        // Add to memory cache
+        if (mMemoryCache != null) {
+            if (RecyclingBitmapDrawable.class.isInstance(value)) {
+                // The removed entry is a recycling drawable, so notify it 
+                // that it has been added into the memory cache
+                ((RecyclingBitmapDrawable) value).setIsCached(true);
+            }
+            mMemoryCache.put(data, value);
+        }
+
+        synchronized (mDiskCacheLock) {
+            // Add to disk cache
+            if (mDiskLruCache != null) {
+                final String key = hashKeyForDisk(data);
+                OutputStream out = null;
+                try {
+                    DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
+                    if (snapshot == null) {
+                        final DiskLruCache.Editor editor = mDiskLruCache.edit(key);
+                        if (editor != null) {
+                            out = editor.newOutputStream(DISK_CACHE_INDEX);
+                            value.getBitmap().compress(
+                                    mCacheParams.compressFormat, mCacheParams.compressQuality, out);
+                            editor.commit();
+                            out.close();
+                        }
+                    } else {
+                        snapshot.getInputStream(DISK_CACHE_INDEX).close();
+                    }
+                } catch (final IOException e) {
+                    Log.e(TAG, "addBitmapToCache - " + e);
+                } catch (Exception e) {
+                    Log.e(TAG, "addBitmapToCache - " + e);
+                } finally {
+                    try {
+                        if (out != null) {
+                            out.close();
+                        }
+                    } catch (IOException e) {}
+                }
+            }
+        }
+    }
+
+    /**
+     * Get from memory cache.
+     *
+     * @param data Unique identifier for which item to get
+     * @return The bitmap drawable if found in cache, null otherwise
+     */
+    public BitmapDrawable getBitmapFromMemCache(String data) {
+        BitmapDrawable memValue = null;
+
+        if (mMemoryCache != null) {
+            memValue = mMemoryCache.get(data);
+        }
+
+        if (BuildConfig.DEBUG && memValue != null) {
+            Log.d(TAG, "Memory cache hit");
+        }
+
+        return memValue;
+    }
+
+    /**
+     * Get from disk cache.
+     *
+     * @param data Unique identifier for which item to get
+     * @return The bitmap if found in cache, null otherwise
+     */
+    public Bitmap getBitmapFromDiskCache(String data) {
+        final String key = hashKeyForDisk(data);
+        Bitmap bitmap = null;
+
+        synchronized (mDiskCacheLock) {
+            while (mDiskCacheStarting) {
+                try {
+                    mDiskCacheLock.wait();
+                } catch (InterruptedException e) {}
+            }
+            if (mDiskLruCache != null) {
+                InputStream inputStream = null;
+                try {
+                    final DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
+                    if (snapshot != null) {
+                        if (BuildConfig.DEBUG) {
+                            Log.d(TAG, "Disk cache hit");
+                        }
+                        inputStream = snapshot.getInputStream(DISK_CACHE_INDEX);
+                        if (inputStream != null) {
+                            FileDescriptor fd = ((FileInputStream) inputStream).getFD();
+
+                            // Decode bitmap, but we don't want to sample so give
+                            // MAX_VALUE as the target dimensions
+                            bitmap = ImageResizer.decodeSampledBitmapFromDescriptor(
+                                    fd, Integer.MAX_VALUE, Integer.MAX_VALUE, this);
+                        }
+                    }
+                } catch (final IOException e) {
+                    Log.e(TAG, "getBitmapFromDiskCache - " + e);
+                } finally {
+                    try {
+                        if (inputStream != null) {
+                            inputStream.close();
+                        }
+                    } catch (IOException e) {}
+                }
+            }
+            return bitmap;
+        }
+    }
+
+    /**
+     * @param options - BitmapFactory.Options with out* options populated
+     * @return Bitmap that case be used for inBitmap
+     */
+    protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) {
+        Bitmap bitmap = null;
+
+        if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) {
+            final Iterator<SoftReference<Bitmap>> iterator = mReusableBitmaps.iterator();
+            Bitmap item;
+
+            while (iterator.hasNext()) {
+                item = iterator.next().get();
+
+                if (null != item && item.isMutable()) {
+                    // Check to see it the item can be used for inBitmap
+                    if (canUseForInBitmap(item, options)) {
+                        bitmap = item;
+
+                        // Remove from reusable set so it can't be used again
+                        iterator.remove();
+                        break;
+                    }
+                } else {
+                    // Remove from the set if the reference has been cleared.
+                    iterator.remove();
+                }
+            }
+        }
+
+        return bitmap;
+    }
+
+    /**
+     * Clears both the memory and disk cache associated with this ImageCache object. Note that
+     * this includes disk access so this should not be executed on the main/UI thread.
+     */
+    public void clearCache() {
+        if (mMemoryCache != null) {
+            mMemoryCache.evictAll();
+            if (BuildConfig.DEBUG) {
+                Log.d(TAG, "Memory cache cleared");
+            }
+        }
+
+        synchronized (mDiskCacheLock) {
+            mDiskCacheStarting = true;
+            if (mDiskLruCache != null && !mDiskLruCache.isClosed()) {
+                try {
+                    mDiskLruCache.delete();
+                    if (BuildConfig.DEBUG) {
+                        Log.d(TAG, "Disk cache cleared");
+                    }
+                } catch (IOException e) {
+                    Log.e(TAG, "clearCache - " + e);
+                }
+                mDiskLruCache = null;
+                initDiskCache();
+            }
+        }
+    }
+
+    /**
+     * Flushes the disk cache associated with this ImageCache object. Note that this includes
+     * disk access so this should not be executed on the main/UI thread.
+     */
+    public void flush() {
+        synchronized (mDiskCacheLock) {
+            if (mDiskLruCache != null) {
+                try {
+                    mDiskLruCache.flush();
+                    if (BuildConfig.DEBUG) {
+                        Log.d(TAG, "Disk cache flushed");
+                    }
+                } catch (IOException e) {
+                    Log.e(TAG, "flush - " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Closes the disk cache associated with this ImageCache object. Note that this includes
+     * disk access so this should not be executed on the main/UI thread.
+     */
+    public void close() {
+        synchronized (mDiskCacheLock) {
+            if (mDiskLruCache != null) {
+                try {
+                    if (!mDiskLruCache.isClosed()) {
+                        mDiskLruCache.close();
+                        mDiskLruCache = null;
+                        if (BuildConfig.DEBUG) {
+                            Log.d(TAG, "Disk cache closed");
+                        }
+                    }
+                } catch (IOException e) {
+                    Log.e(TAG, "close - " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * A holder class that contains cache parameters.
+     */
+    public static class ImageCacheParams {
+        public int memCacheSize = DEFAULT_MEM_CACHE_SIZE;
+        public int diskCacheSize = DEFAULT_DISK_CACHE_SIZE;
+        public File diskCacheDir;
+        public CompressFormat compressFormat = DEFAULT_COMPRESS_FORMAT;
+        public int compressQuality = DEFAULT_COMPRESS_QUALITY;
+        public boolean memoryCacheEnabled = DEFAULT_MEM_CACHE_ENABLED;
+        public boolean diskCacheEnabled = DEFAULT_DISK_CACHE_ENABLED;
+        public boolean initDiskCacheOnCreate = DEFAULT_INIT_DISK_CACHE_ON_CREATE;
+
+        /**
+         * Create a set of image cache parameters that can be provided to
+         * {@link ImageCache#getInstance(FragmentManager, ImageCacheParams)} or
+         * {@link ImageWorker#addImageCache(FragmentManager, ImageCacheParams)}.
+         * @param context A context to use.
+         * @param diskCacheDirectoryName A unique subdirectory name that will be appended to the
+         *                               application cache directory. Usually "cache" or "images"
+         *                               is sufficient.
+         */
+        public ImageCacheParams(Context context, String diskCacheDirectoryName) {
+            diskCacheDir = getDiskCacheDir(context, diskCacheDirectoryName);
+        }
+
+        /**
+         * Sets the memory cache size based on a percentage of the max available VM memory.
+         * Eg. setting percent to 0.2 would set the memory cache to one fifth of the available
+         * memory. Throws {@link IllegalArgumentException} if percent is < 0.01 or > .8.
+         * memCacheSize is stored in kilobytes instead of bytes as this will eventually be passed
+         * to construct a LruCache which takes an int in its constructor.
+         *
+         * This value should be chosen carefully based on a number of factors
+         * Refer to the corresponding Android Training class for more discussion:
+         * http://developer.android.com/training/displaying-bitmaps/
+         *
+         * @param percent Percent of available app memory to use to size memory cache
+         */
+        public void setMemCacheSizePercent(float percent) {
+            if (percent < 0.01f || percent > 0.8f) {
+                throw new IllegalArgumentException("setMemCacheSizePercent - percent must be "
+                        + "between 0.01 and 0.8 (inclusive)");
+            }
+            memCacheSize = Math.round(percent * Runtime.getRuntime().maxMemory() / 1024);
+        }
+    }
+
+    /**
+     * @param candidate - Bitmap to check
+     * @param targetOptions - Options that have the out* value populated
+     * @return true if <code>candidate</code> can be used for inBitmap re-use with
+     *      <code>targetOptions</code>
+     */
+    private static boolean canUseForInBitmap(
+            Bitmap candidate, BitmapFactory.Options targetOptions) {
+
+        if (!Utils.hasKitKat()) {
+            // On earlier versions, the dimensions must match exactly and the inSampleSize must be 1
+            return candidate.getWidth() == targetOptions.outWidth
+                    && candidate.getHeight() == targetOptions.outHeight
+                    && targetOptions.inSampleSize == 1;
+        }
+
+        // From Android 4.4 (KitKat) onward we can re-use if the byte size of the new bitmap
+        // is smaller than the reusable bitmap candidate allocation byte count.
+        int width = targetOptions.outWidth / targetOptions.inSampleSize;
+        int height = targetOptions.outHeight / targetOptions.inSampleSize;
+        int byteCount = width * height * getBytesPerPixel(candidate.getConfig());
+        return byteCount <= candidate.getAllocationByteCount();
+    }
+
+    /**
+     * Return the byte usage per pixel of a bitmap based on its configuration.
+     * @param config The bitmap configuration.
+     * @return The byte usage per pixel.
+     */
+    private static int getBytesPerPixel(Config config) {
+        if (config == Config.ARGB_8888) {
+            return 4;
+        } else if (config == Config.RGB_565) {
+            return 2;
+        } else if (config == Config.ARGB_4444) {
+            return 2;
+        } else if (config == Config.ALPHA_8) {
+            return 1;
+        }
+        return 1;
+    }
+
+    /**
+     * Get a usable cache directory (external if available, internal otherwise).
+     *
+     * @param context The context to use
+     * @param uniqueName A unique directory name to append to the cache dir
+     * @return The cache dir
+     */
+    public static File getDiskCacheDir(Context context, String uniqueName) {
+        // Check if media is mounted or storage is built-in, if so, try and use external cache dir
+        // otherwise use internal cache dir
+        final String cachePath =
+                Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
+                        !isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :
+                                context.getCacheDir().getPath();
+
+        return new File(cachePath + File.separator + uniqueName);
+    }
+
+    /**
+     * A hashing method that changes a string (like a URL) into a hash suitable for using as a
+     * disk filename.
+     */
+    public static String hashKeyForDisk(String key) {
+        String cacheKey;
+        try {
+            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
+            mDigest.update(key.getBytes());
+            cacheKey = bytesToHexString(mDigest.digest());
+        } catch (NoSuchAlgorithmException e) {
+            cacheKey = String.valueOf(key.hashCode());
+        }
+        return cacheKey;
+    }
+
+    private static String bytesToHexString(byte[] bytes) {
+        // http://stackoverflow.com/questions/332079
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < bytes.length; i++) {
+            String hex = Integer.toHexString(0xFF & bytes[i]);
+            if (hex.length() == 1) {
+                sb.append('0');
+            }
+            sb.append(hex);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Get the size in bytes of a bitmap in a BitmapDrawable. Note that from Android 4.4 (KitKat)
+     * onward this returns the allocated memory size of the bitmap which can be larger than the
+     * actual bitmap data byte count (in the case it was re-used).
+     *
+     * @param value
+     * @return size in bytes
+     */
+    @TargetApi(12)
+    public static int getBitmapSize(BitmapDrawable value) {
+        Bitmap bitmap = value.getBitmap();
+
+        // From KitKat onward use getAllocationByteCount() as allocated bytes can potentially be
+        // larger than bitmap byte count.
+        if (Utils.hasKitKat()) {
+            return bitmap.getAllocationByteCount();
+        }
+
+        if (Utils.hasHoneycombMR1()) {
+            return bitmap.getByteCount();
+        }
+
+        // Pre HC-MR1
+        return bitmap.getRowBytes() * bitmap.getHeight();
+    }
+
+    /**
+     * Check if external storage is built-in or removable.
+     *
+     * @return True if external storage is removable (like an SD card), false
+     *         otherwise.
+     */
+    @TargetApi(9)
+    public static boolean isExternalStorageRemovable() {
+        if (Utils.hasGingerbread()) {
+            return Environment.isExternalStorageRemovable();
+        }
+        return true;
+    }
+
+    /**
+     * Get the external app cache directory.
+     *
+     * @param context The context to use
+     * @return The external cache dir
+     */
+    @TargetApi(8)
+    public static File getExternalCacheDir(Context context) {
+        if (Utils.hasFroyo()) {
+            return context.getExternalCacheDir();
+        }
+
+        // Before Froyo we need to construct the external cache dir ourselves
+        final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/";
+        return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);
+    }
+
+    /**
+     * Check how much usable space is available at a given path.
+     *
+     * @param path The path to check
+     * @return The space available in bytes
+     */
+    @TargetApi(9)
+    public static long getUsableSpace(File path) {
+        if (Utils.hasGingerbread()) {
+            return path.getUsableSpace();
+        }
+        final StatFs stats = new StatFs(path.getPath());
+        return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();
+    }
+
+    /**
+     * Locate an existing instance of this Fragment or if not found, create and
+     * add it using FragmentManager.
+     *
+     * @param fm The FragmentManager manager to use.
+     * @return The existing instance of the Fragment or the new instance if just
+     *         created.
+     */
+    private static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {
+        // Check to see if we have retained the worker fragment.
+        RetainFragment mRetainFragment = (RetainFragment) fm.findFragmentByTag(TAG);
+
+        // If not retained (or first time running), we need to create and add it.
+        if (mRetainFragment == null) {
+            mRetainFragment = new RetainFragment();
+            fm.beginTransaction().add(mRetainFragment, TAG).commitAllowingStateLoss();
+        }
+
+        return mRetainFragment;
+    }
+
+    /**
+     * A simple non-UI Fragment that stores a single Object and is retained over configuration
+     * changes. It will be used to retain the ImageCache object.
+     */
+    public static class RetainFragment extends Fragment {
+        private Object mObject;
+
+        /**
+         * Empty constructor as per the Fragment documentation
+         */
+        public RetainFragment() {}
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+
+            // Make sure this Fragment is retained over a configuration change
+            setRetainInstance(true);
+        }
+
+        /**
+         * Store a single object in this Fragment.
+         *
+         * @param object The object to store
+         */
+        public void setObject(Object object) {
+            mObject = object;
+        }
+
+        /**
+         * Get the stored object.
+         *
+         * @return The stored object
+         */
+        public Object getObject() {
+            return mObject;
+        }
+    }
+
+}
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/ImageFetcher.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageFetcher.java
similarity index 100%
rename from samples/training/bitmapfun/src/com/example/android/bitmapfun/util/ImageFetcher.java
rename to samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageFetcher.java
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageResizer.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageResizer.java
new file mode 100644
index 0000000..e8ce4e1
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageResizer.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.bitmapfun.util;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Build;
+import android.util.Log;
+
+import com.example.android.bitmapfun.BuildConfig;
+
+import java.io.FileDescriptor;
+
+/**
+ * A simple subclass of {@link ImageWorker} that resizes images from resources given a target width
+ * and height. Useful for when the input images might be too large to simply load directly into
+ * memory.
+ */
+public class ImageResizer extends ImageWorker {
+    private static final String TAG = "ImageResizer";
+    protected int mImageWidth;
+    protected int mImageHeight;
+
+    /**
+     * Initialize providing a single target image size (used for both width and height);
+     *
+     * @param context
+     * @param imageWidth
+     * @param imageHeight
+     */
+    public ImageResizer(Context context, int imageWidth, int imageHeight) {
+        super(context);
+        setImageSize(imageWidth, imageHeight);
+    }
+
+    /**
+     * Initialize providing a single target image size (used for both width and height);
+     *
+     * @param context
+     * @param imageSize
+     */
+    public ImageResizer(Context context, int imageSize) {
+        super(context);
+        setImageSize(imageSize);
+    }
+
+    /**
+     * Set the target image width and height.
+     *
+     * @param width
+     * @param height
+     */
+    public void setImageSize(int width, int height) {
+        mImageWidth = width;
+        mImageHeight = height;
+    }
+
+    /**
+     * Set the target image size (width and height will be the same).
+     *
+     * @param size
+     */
+    public void setImageSize(int size) {
+        setImageSize(size, size);
+    }
+
+    /**
+     * The main processing method. This happens in a background task. In this case we are just
+     * sampling down the bitmap and returning it from a resource.
+     *
+     * @param resId
+     * @return
+     */
+    private Bitmap processBitmap(int resId) {
+        if (BuildConfig.DEBUG) {
+            Log.d(TAG, "processBitmap - " + resId);
+        }
+        return decodeSampledBitmapFromResource(mResources, resId, mImageWidth,
+                mImageHeight, getImageCache());
+    }
+
+    @Override
+    protected Bitmap processBitmap(Object data) {
+        return processBitmap(Integer.parseInt(String.valueOf(data)));
+    }
+
+    /**
+     * Decode and sample down a bitmap from resources to the requested width and height.
+     *
+     * @param res The resources object containing the image data
+     * @param resId The resource id of the image data
+     * @param reqWidth The requested width of the resulting bitmap
+     * @param reqHeight The requested height of the resulting bitmap
+     * @param cache The ImageCache used to find candidate bitmaps for use with inBitmap
+     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
+     *         that are equal to or greater than the requested width and height
+     */
+    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
+            int reqWidth, int reqHeight, ImageCache cache) {
+
+        // First decode with inJustDecodeBounds=true to check dimensions
+        final BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeResource(res, resId, options);
+
+        // Calculate inSampleSize
+        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
+
+        // If we're running on Honeycomb or newer, try to use inBitmap
+        if (Utils.hasHoneycomb()) {
+            addInBitmapOptions(options, cache);
+        }
+
+        // Decode bitmap with inSampleSize set
+        options.inJustDecodeBounds = false;
+        return BitmapFactory.decodeResource(res, resId, options);
+    }
+
+    /**
+     * Decode and sample down a bitmap from a file to the requested width and height.
+     *
+     * @param filename The full path of the file to decode
+     * @param reqWidth The requested width of the resulting bitmap
+     * @param reqHeight The requested height of the resulting bitmap
+     * @param cache The ImageCache used to find candidate bitmaps for use with inBitmap
+     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
+     *         that are equal to or greater than the requested width and height
+     */
+    public static Bitmap decodeSampledBitmapFromFile(String filename,
+            int reqWidth, int reqHeight, ImageCache cache) {
+
+        // First decode with inJustDecodeBounds=true to check dimensions
+        final BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeFile(filename, options);
+
+        // Calculate inSampleSize
+        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
+
+        // If we're running on Honeycomb or newer, try to use inBitmap
+        if (Utils.hasHoneycomb()) {
+            addInBitmapOptions(options, cache);
+        }
+
+        // Decode bitmap with inSampleSize set
+        options.inJustDecodeBounds = false;
+        return BitmapFactory.decodeFile(filename, options);
+    }
+
+    /**
+     * Decode and sample down a bitmap from a file input stream to the requested width and height.
+     *
+     * @param fileDescriptor The file descriptor to read from
+     * @param reqWidth The requested width of the resulting bitmap
+     * @param reqHeight The requested height of the resulting bitmap
+     * @param cache The ImageCache used to find candidate bitmaps for use with inBitmap
+     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
+     *         that are equal to or greater than the requested width and height
+     */
+    public static Bitmap decodeSampledBitmapFromDescriptor(
+            FileDescriptor fileDescriptor, int reqWidth, int reqHeight, ImageCache cache) {
+
+        // First decode with inJustDecodeBounds=true to check dimensions
+        final BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
+
+        // Calculate inSampleSize
+        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
+
+        // Decode bitmap with inSampleSize set
+        options.inJustDecodeBounds = false;
+
+        // If we're running on Honeycomb or newer, try to use inBitmap
+        if (Utils.hasHoneycomb()) {
+            addInBitmapOptions(options, cache);
+        }
+
+        return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
+    }
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    private static void addInBitmapOptions(BitmapFactory.Options options, ImageCache cache) {
+        // inBitmap only works with mutable bitmaps so force the decoder to
+        // return mutable bitmaps.
+        options.inMutable = true;
+
+        if (cache != null) {
+            // Try and find a bitmap to use for inBitmap
+            Bitmap inBitmap = cache.getBitmapFromReusableSet(options);
+
+            if (inBitmap != null) {
+                options.inBitmap = inBitmap;
+            }
+        }
+    }
+
+    /**
+     * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
+     * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
+     * the closest inSampleSize that is a power of 2 and will result in the final decoded bitmap
+     * having a width and height equal to or larger than the requested width and height.
+     *
+     * @param options An options object with out* params already populated (run through a decode*
+     *            method with inJustDecodeBounds==true
+     * @param reqWidth The requested width of the resulting bitmap
+     * @param reqHeight The requested height of the resulting bitmap
+     * @return The value to be used for inSampleSize
+     */
+    public static int calculateInSampleSize(BitmapFactory.Options options,
+            int reqWidth, int reqHeight) {
+        // Raw height and width of image
+        final int height = options.outHeight;
+        final int width = options.outWidth;
+        int inSampleSize = 1;
+
+        if (height > reqHeight || width > reqWidth) {
+
+            final int halfHeight = height / 2;
+            final int halfWidth = width / 2;
+
+            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
+            // height and width larger than the requested height and width.
+            while ((halfHeight / inSampleSize) > reqHeight
+                    && (halfWidth / inSampleSize) > reqWidth) {
+                inSampleSize *= 2;
+            }
+
+            // This offers some additional logic in case the image has a strange
+            // aspect ratio. For example, a panorama may have a much larger
+            // width than height. In these cases the total pixels might still
+            // end up being too large to fit comfortably in memory, so we should
+            // be more aggressive with sample down the image (=larger inSampleSize).
+
+            long totalPixels = width * height / inSampleSize;
+
+            // Anything more than 2x the requested pixels we'll sample down further
+            final long totalReqPixelsCap = reqWidth * reqHeight * 2;
+
+            while (totalPixels > totalReqPixelsCap) {
+                inSampleSize *= 2;
+                totalPixels /= 2;
+            }
+        }
+        return inSampleSize;
+    }
+}
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/ImageWorker.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageWorker.java
similarity index 100%
rename from samples/training/bitmapfun/src/com/example/android/bitmapfun/util/ImageWorker.java
rename to samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageWorker.java
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/RecyclingBitmapDrawable.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/RecyclingBitmapDrawable.java
similarity index 100%
rename from samples/training/bitmapfun/src/com/example/android/bitmapfun/util/RecyclingBitmapDrawable.java
rename to samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/RecyclingBitmapDrawable.java
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/Utils.java b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/Utils.java
new file mode 100644
index 0000000..81b856a
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/Utils.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.bitmapfun.util;
+
+import com.example.android.bitmapfun.ui.ImageDetailActivity;
+import com.example.android.bitmapfun.ui.ImageGridActivity;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.StrictMode;
+
+/**
+ * Class containing some static utility methods.
+ */
+public class Utils {
+    private Utils() {};
+
+    @TargetApi(11)
+    public static void enableStrictMode() {
+        if (Utils.hasGingerbread()) {
+            StrictMode.ThreadPolicy.Builder threadPolicyBuilder =
+                    new StrictMode.ThreadPolicy.Builder()
+                            .detectAll()
+                            .penaltyLog();
+            StrictMode.VmPolicy.Builder vmPolicyBuilder =
+                    new StrictMode.VmPolicy.Builder()
+                            .detectAll()
+                            .penaltyLog();
+
+            if (Utils.hasHoneycomb()) {
+                threadPolicyBuilder.penaltyFlashScreen();
+                vmPolicyBuilder
+                        .setClassInstanceLimit(ImageGridActivity.class, 1)
+                        .setClassInstanceLimit(ImageDetailActivity.class, 1);
+            }
+            StrictMode.setThreadPolicy(threadPolicyBuilder.build());
+            StrictMode.setVmPolicy(vmPolicyBuilder.build());
+        }
+    }
+
+    public static boolean hasFroyo() {
+        // Can use static final constants like FROYO, declared in later versions
+        // of the OS since they are inlined at compile time. This is guaranteed behavior.
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
+    }
+
+    public static boolean hasGingerbread() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
+    }
+
+    public static boolean hasHoneycomb() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
+    }
+
+    public static boolean hasHoneycombMR1() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1;
+    }
+
+    public static boolean hasJellyBean() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+    }
+
+    public static boolean hasKitKat() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+    }
+}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-hdpi/ic_launcher.png b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..75b3c97
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/bitmapfun/res/drawable-ldpi/ic_launcher.png b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-ldpi/ic_launcher.png
similarity index 100%
rename from samples/training/bitmapfun/res/drawable-ldpi/ic_launcher.png
rename to samples/training/bitmapfun/BitmapFun/src/main/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-mdpi/ic_launcher.png b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..0c9c11a
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/bitmapfun/res/drawable-nodpi/empty_photo.png b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-nodpi/empty_photo.png
similarity index 100%
rename from samples/training/bitmapfun/res/drawable-nodpi/empty_photo.png
rename to samples/training/bitmapfun/BitmapFun/src/main/res/drawable-nodpi/empty_photo.png
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xhdpi/ic_launcher.png b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..7c5aeed
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xxhdpi/ic_launcher.png b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..91b0f96
--- /dev/null
+++ b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/bitmapfun/res/drawable/photogrid_list_selector.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable/photogrid_list_selector.xml
similarity index 100%
rename from samples/training/bitmapfun/res/drawable/photogrid_list_selector.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/drawable/photogrid_list_selector.xml
diff --git a/samples/training/bitmapfun/res/layout/image_detail_fragment.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_detail_fragment.xml
similarity index 100%
rename from samples/training/bitmapfun/res/layout/image_detail_fragment.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_detail_fragment.xml
diff --git a/samples/training/bitmapfun/res/layout/image_detail_pager.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_detail_pager.xml
similarity index 100%
rename from samples/training/bitmapfun/res/layout/image_detail_pager.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_detail_pager.xml
diff --git a/samples/training/bitmapfun/res/layout/image_grid_fragment.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_grid_fragment.xml
similarity index 100%
rename from samples/training/bitmapfun/res/layout/image_grid_fragment.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_grid_fragment.xml
diff --git a/samples/training/bitmapfun/res/menu/main_menu.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/menu/main_menu.xml
similarity index 100%
rename from samples/training/bitmapfun/res/menu/main_menu.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/menu/main_menu.xml
diff --git a/samples/training/bitmapfun/res/values-large/dimens.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/values-large/dimens.xml
similarity index 100%
rename from samples/training/bitmapfun/res/values-large/dimens.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/values-large/dimens.xml
diff --git a/samples/training/bitmapfun/res/values-v11/styles.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/values-v11/styles.xml
similarity index 100%
rename from samples/training/bitmapfun/res/values-v11/styles.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/values-v11/styles.xml
diff --git a/samples/training/bitmapfun/res/values-xlarge/dimens.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/values-xlarge/dimens.xml
similarity index 100%
rename from samples/training/bitmapfun/res/values-xlarge/dimens.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/values-xlarge/dimens.xml
diff --git a/samples/training/bitmapfun/res/values/colors.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
similarity index 100%
rename from samples/training/bitmapfun/res/values/colors.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
diff --git a/samples/training/bitmapfun/res/values/dimens.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/values/dimens.xml
similarity index 100%
rename from samples/training/bitmapfun/res/values/dimens.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/values/dimens.xml
diff --git a/samples/training/bitmapfun/res/values/strings.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/values/strings.xml
similarity index 100%
rename from samples/training/bitmapfun/res/values/strings.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/values/strings.xml
diff --git a/samples/training/bitmapfun/res/values/styles.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/values/styles.xml
similarity index 100%
rename from samples/training/bitmapfun/res/values/styles.xml
rename to samples/training/bitmapfun/BitmapFun/src/main/res/values/styles.xml
diff --git a/samples/training/bitmapfun/README b/samples/training/bitmapfun/README
new file mode 100644
index 0000000..a0a192f
--- /dev/null
+++ b/samples/training/bitmapfun/README
@@ -0,0 +1,8 @@
+This is an Android Studio project:
+http://developer.android.com/sdk/installing/studio.html
+
+First copy local.properties.sample to local.properties and set your SDK path.
+
+Then import the project into Android Studio:
+File -> Import Project -> Choose Directory -> Import from external model ->
+    Gradle -> Use default gradle wrapper -> Finish
diff --git a/samples/training/bitmapfun/build.gradle b/samples/training/bitmapfun/build.gradle
new file mode 100644
index 0000000..495c503
--- /dev/null
+++ b/samples/training/bitmapfun/build.gradle
@@ -0,0 +1 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
diff --git a/samples/training/bitmapfun/libs/android-support-v4.jar b/samples/training/bitmapfun/libs/android-support-v4.jar
deleted file mode 100644
index 6080877..0000000
--- a/samples/training/bitmapfun/libs/android-support-v4.jar
+++ /dev/null
Binary files differ
diff --git a/samples/training/bitmapfun/local.properties.sample b/samples/training/bitmapfun/local.properties.sample
new file mode 100644
index 0000000..37317f4
--- /dev/null
+++ b/samples/training/bitmapfun/local.properties.sample
@@ -0,0 +1,7 @@
+# This file should be copied to local.properties and path set to point
+# to your Android SDK.
+
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/usr/local/lib/android-sdk
\ No newline at end of file
diff --git a/samples/training/bitmapfun/settings.gradle b/samples/training/bitmapfun/settings.gradle
new file mode 100644
index 0000000..9f12781
--- /dev/null
+++ b/samples/training/bitmapfun/settings.gradle
@@ -0,0 +1 @@
+include ':BitmapFun'
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/provider/Images.java b/samples/training/bitmapfun/src/com/example/android/bitmapfun/provider/Images.java
deleted file mode 100644
index b555784..0000000
--- a/samples/training/bitmapfun/src/com/example/android/bitmapfun/provider/Images.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.bitmapfun.provider;
-
-/**
- * Some simple test data to use for this sample app.
- */
-public class Images {
-
-    /**
-     * This are PicasaWeb URLs and could potentially change. Ideally the PicasaWeb API should be
-     * used to fetch the URLs.
-     *
-     * Credit to Romain Guy for the photos:
-     * http://www.curious-creature.org/
-     * https://plus.google.com/109538161516040592207/about
-     * http://www.flickr.com/photos/romainguy
-     */
-    public final static String[] imageUrls = new String[] {
-            "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg",
-            "https://lh4.googleusercontent.com/--dq8niRp7W4/URquVgmXvgI/AAAAAAAAAbs/-gnuLQfNnBA/s1024/A%252520Song%252520of%252520Ice%252520and%252520Fire.jpg",
-            "https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s1024/Another%252520Rockaway%252520Sunset.jpg",
-            "https://lh3.googleusercontent.com/--L0Km39l5J8/URquXHGcdNI/AAAAAAAAAbs/3ZrSJNrSomQ/s1024/Antelope%252520Butte.jpg",
-            "https://lh6.googleusercontent.com/-8HO-4vIFnlw/URquZnsFgtI/AAAAAAAAAbs/WT8jViTF7vw/s1024/Antelope%252520Hallway.jpg",
-            "https://lh4.googleusercontent.com/-WIuWgVcU3Qw/URqubRVcj4I/AAAAAAAAAbs/YvbwgGjwdIQ/s1024/Antelope%252520Walls.jpg",
-            "https://lh6.googleusercontent.com/-UBmLbPELvoQ/URqucCdv0kI/AAAAAAAAAbs/IdNhr2VQoQs/s1024/Apre%2525CC%252580s%252520la%252520Pluie.jpg",
-            "https://lh3.googleusercontent.com/-s-AFpvgSeew/URquc6dF-JI/AAAAAAAAAbs/Mt3xNGRUd68/s1024/Backlit%252520Cloud.jpg",
-            "https://lh5.googleusercontent.com/-bvmif9a9YOQ/URquea3heHI/AAAAAAAAAbs/rcr6wyeQtAo/s1024/Bee%252520and%252520Flower.jpg",
-            "https://lh5.googleusercontent.com/-n7mdm7I7FGs/URqueT_BT-I/AAAAAAAAAbs/9MYmXlmpSAo/s1024/Bonzai%252520Rock%252520Sunset.jpg",
-            "https://lh6.googleusercontent.com/-4CN4X4t0M1k/URqufPozWzI/AAAAAAAAAbs/8wK41lg1KPs/s1024/Caterpillar.jpg",
-            "https://lh3.googleusercontent.com/-rrFnVC8xQEg/URqufdrLBaI/AAAAAAAAAbs/s69WYy_fl1E/s1024/Chess.jpg",
-            "https://lh5.googleusercontent.com/-WVpRptWH8Yw/URqugh-QmDI/AAAAAAAAAbs/E-MgBgtlUWU/s1024/Chihuly.jpg",
-            "https://lh5.googleusercontent.com/-0BDXkYmckbo/URquhKFW84I/AAAAAAAAAbs/ogQtHCTk2JQ/s1024/Closed%252520Door.jpg",
-            "https://lh3.googleusercontent.com/-PyggXXZRykM/URquh-kVvoI/AAAAAAAAAbs/hFtDwhtrHHQ/s1024/Colorado%252520River%252520Sunset.jpg",
-            "https://lh3.googleusercontent.com/-ZAs4dNZtALc/URquikvOCWI/AAAAAAAAAbs/DXz4h3dll1Y/s1024/Colors%252520of%252520Autumn.jpg",
-            "https://lh4.googleusercontent.com/-GztnWEIiMz8/URqukVCU7bI/AAAAAAAAAbs/jo2Hjv6MZ6M/s1024/Countryside.jpg",
-            "https://lh4.googleusercontent.com/-bEg9EZ9QoiM/URquklz3FGI/AAAAAAAAAbs/UUuv8Ac2BaE/s1024/Death%252520Valley%252520-%252520Dunes.jpg",
-            "https://lh6.googleusercontent.com/-ijQJ8W68tEE/URqulGkvFEI/AAAAAAAAAbs/zPXvIwi_rFw/s1024/Delicate%252520Arch.jpg",
-            "https://lh5.googleusercontent.com/-Oh8mMy2ieng/URqullDwehI/AAAAAAAAAbs/TbdeEfsaIZY/s1024/Despair.jpg",
-            "https://lh5.googleusercontent.com/-gl0y4UiAOlk/URqumC_KjBI/AAAAAAAAAbs/PM1eT7dn4oo/s1024/Eagle%252520Fall%252520Sunrise.jpg",
-            "https://lh3.googleusercontent.com/-hYYHd2_vXPQ/URqumtJa9eI/AAAAAAAAAbs/wAalXVkbSh0/s1024/Electric%252520Storm.jpg",
-            "https://lh5.googleusercontent.com/-PyY_yiyjPTo/URqunUOhHFI/AAAAAAAAAbs/azZoULNuJXc/s1024/False%252520Kiva.jpg",
-            "https://lh6.googleusercontent.com/-PYvLVdvXywk/URqunwd8hfI/AAAAAAAAAbs/qiMwgkFvf6I/s1024/Fitzgerald%252520Streaks.jpg",
-            "https://lh4.googleusercontent.com/-KIR_UobIIqY/URquoCZ9SlI/AAAAAAAAAbs/Y4d4q8sXu4c/s1024/Foggy%252520Sunset.jpg",
-            "https://lh6.googleusercontent.com/-9lzOk_OWZH0/URquoo4xYoI/AAAAAAAAAbs/AwgzHtNVCwU/s1024/Frantic.jpg",
-            "https://lh3.googleusercontent.com/-0X3JNaKaz48/URqupH78wpI/AAAAAAAAAbs/lHXxu_zbH8s/s1024/Golden%252520Gate%252520Afternoon.jpg",
-            "https://lh6.googleusercontent.com/-95sb5ag7ABc/URqupl95RDI/AAAAAAAAAbs/g73R20iVTRA/s1024/Golden%252520Gate%252520Fog.jpg",
-            "https://lh3.googleusercontent.com/-JB9v6rtgHhk/URqup21F-zI/AAAAAAAAAbs/64Fb8qMZWXk/s1024/Golden%252520Grass.jpg",
-            "https://lh4.googleusercontent.com/-EIBGfnuLtII/URquqVHwaRI/AAAAAAAAAbs/FA4McV2u8VE/s1024/Grand%252520Teton.jpg",
-            "https://lh4.googleusercontent.com/-WoMxZvmN9nY/URquq1v2AoI/AAAAAAAAAbs/grj5uMhL6NA/s1024/Grass%252520Closeup.jpg",
-            "https://lh3.googleusercontent.com/-6hZiEHXx64Q/URqurxvNdqI/AAAAAAAAAbs/kWMXM3o5OVI/s1024/Green%252520Grass.jpg",
-            "https://lh5.googleusercontent.com/-6LVb9OXtQ60/URquteBFuKI/AAAAAAAAAbs/4F4kRgecwFs/s1024/Hanging%252520Leaf.jpg",
-            "https://lh4.googleusercontent.com/-zAvf__52ONk/URqutT_IuxI/AAAAAAAAAbs/D_bcuc0thoU/s1024/Highway%2525201.jpg",
-            "https://lh6.googleusercontent.com/-H4SrUg615rA/URquuL27fXI/AAAAAAAAAbs/4aEqJfiMsOU/s1024/Horseshoe%252520Bend%252520Sunset.jpg",
-            "https://lh4.googleusercontent.com/-JhFi4fb_Pqw/URquuX-QXbI/AAAAAAAAAbs/IXpYUxuweYM/s1024/Horseshoe%252520Bend.jpg",
-            "https://lh5.googleusercontent.com/-UGgssvFRJ7g/URquueyJzGI/AAAAAAAAAbs/yYIBlLT0toM/s1024/Into%252520the%252520Blue.jpg",
-            "https://lh3.googleusercontent.com/-CH7KoupI7uI/URquu0FF__I/AAAAAAAAAbs/R7GDmI7v_G0/s1024/Jelly%252520Fish%2525202.jpg",
-            "https://lh4.googleusercontent.com/-pwuuw6yhg8U/URquvPxR3FI/AAAAAAAAAbs/VNGk6f-tsGE/s1024/Jelly%252520Fish%2525203.jpg",
-            "https://lh5.googleusercontent.com/-GoUQVw1fnFw/URquv6xbC0I/AAAAAAAAAbs/zEUVTQQ43Zc/s1024/Kauai.jpg",
-            "https://lh6.googleusercontent.com/-8QdYYQEpYjw/URquwvdh88I/AAAAAAAAAbs/cktDy-ysfHo/s1024/Kyoto%252520Sunset.jpg",
-            "https://lh4.googleusercontent.com/-vPeekyDjOE0/URquwzJ28qI/AAAAAAAAAbs/qxcyXULsZrg/s1024/Lake%252520Tahoe%252520Colors.jpg",
-            "https://lh4.googleusercontent.com/-xBPxWpD4yxU/URquxWHk8AI/AAAAAAAAAbs/ARDPeDYPiMY/s1024/Lava%252520from%252520the%252520Sky.jpg",
-            "https://lh3.googleusercontent.com/-897VXrJB6RE/URquxxxd-5I/AAAAAAAAAbs/j-Cz4T4YvIw/s1024/Leica%25252050mm%252520Summilux.jpg",
-            "https://lh5.googleusercontent.com/-qSJ4D4iXzGo/URquyDWiJ1I/AAAAAAAAAbs/k2pBXeWehOA/s1024/Leica%25252050mm%252520Summilux.jpg",
-            "https://lh6.googleusercontent.com/-dwlPg83vzLg/URquylTVuFI/AAAAAAAAAbs/G6SyQ8b4YsI/s1024/Leica%252520M8%252520%252528Front%252529.jpg",
-            "https://lh3.googleusercontent.com/-R3_EYAyJvfk/URquzQBv8eI/AAAAAAAAAbs/b9xhpUM3pEI/s1024/Light%252520to%252520Sand.jpg",
-            "https://lh3.googleusercontent.com/-fHY5h67QPi0/URqu0Cp4J1I/AAAAAAAAAbs/0lG6m94Z6vM/s1024/Little%252520Bit%252520of%252520Paradise.jpg",
-            "https://lh5.googleusercontent.com/-TzF_LwrCnRM/URqu0RddPOI/AAAAAAAAAbs/gaj2dLiuX0s/s1024/Lone%252520Pine%252520Sunset.jpg",
-            "https://lh3.googleusercontent.com/-4HdpJ4_DXU4/URqu046dJ9I/AAAAAAAAAbs/eBOodtk2_uk/s1024/Lonely%252520Rock.jpg",
-            "https://lh6.googleusercontent.com/-erbF--z-W4s/URqu1ajSLkI/AAAAAAAAAbs/xjDCDO1INzM/s1024/Longue%252520Vue.jpg",
-            "https://lh6.googleusercontent.com/-0CXJRdJaqvc/URqu1opNZNI/AAAAAAAAAbs/PFB2oPUU7Lk/s1024/Look%252520Me%252520in%252520the%252520Eye.jpg",
-            "https://lh3.googleusercontent.com/-D_5lNxnDN6g/URqu2Tk7HVI/AAAAAAAAAbs/p0ddca9W__Y/s1024/Lost%252520in%252520a%252520Field.jpg",
-            "https://lh6.googleusercontent.com/-flsqwMrIk2Q/URqu24PcmjI/AAAAAAAAAbs/5ocIH85XofM/s1024/Marshall%252520Beach%252520Sunset.jpg",
-            "https://lh4.googleusercontent.com/-Y4lgryEVTmU/URqu28kG3gI/AAAAAAAAAbs/OjXpekqtbJ4/s1024/Mono%252520Lake%252520Blue.jpg",
-            "https://lh4.googleusercontent.com/-AaHAJPmcGYA/URqu3PIldHI/AAAAAAAAAbs/lcTqk1SIcRs/s1024/Monument%252520Valley%252520Overlook.jpg",
-            "https://lh4.googleusercontent.com/-vKxfdQ83dQA/URqu31Yq_BI/AAAAAAAAAbs/OUoGk_2AyfM/s1024/Moving%252520Rock.jpg",
-            "https://lh5.googleusercontent.com/-CG62QiPpWXg/URqu4ia4vRI/AAAAAAAAAbs/0YOdqLAlcAc/s1024/Napali%252520Coast.jpg",
-            "https://lh6.googleusercontent.com/-wdGrP5PMmJQ/URqu5PZvn7I/AAAAAAAAAbs/m0abEcdPXe4/s1024/One%252520Wheel.jpg",
-            "https://lh6.googleusercontent.com/-6WS5DoCGuOA/URqu5qx1UgI/AAAAAAAAAbs/giMw2ixPvrY/s1024/Open%252520Sky.jpg",
-            "https://lh6.googleusercontent.com/-u8EHKj8G8GQ/URqu55sM6yI/AAAAAAAAAbs/lIXX_GlTdmI/s1024/Orange%252520Sunset.jpg",
-            "https://lh6.googleusercontent.com/-74Z5qj4bTDE/URqu6LSrJrI/AAAAAAAAAbs/XzmVkw90szQ/s1024/Orchid.jpg",
-            "https://lh6.googleusercontent.com/-lEQE4h6TePE/URqu6t_lSkI/AAAAAAAAAbs/zvGYKOea_qY/s1024/Over%252520there.jpg",
-            "https://lh5.googleusercontent.com/-cauH-53JH2M/URqu66v_USI/AAAAAAAAAbs/EucwwqclfKQ/s1024/Plumes.jpg",
-            "https://lh3.googleusercontent.com/-eDLT2jHDoy4/URqu7axzkAI/AAAAAAAAAbs/iVZE-xJ7lZs/s1024/Rainbokeh.jpg",
-            "https://lh5.googleusercontent.com/-j1NLqEFIyco/URqu8L1CGcI/AAAAAAAAAbs/aqZkgX66zlI/s1024/Rainbow.jpg",
-            "https://lh5.googleusercontent.com/-DRnqmK0t4VU/URqu8XYN9yI/AAAAAAAAAbs/LgvF_592WLU/s1024/Rice%252520Fields.jpg",
-            "https://lh3.googleusercontent.com/-hwh1v3EOGcQ/URqu8qOaKwI/AAAAAAAAAbs/IljRJRnbJGw/s1024/Rockaway%252520Fire%252520Sky.jpg",
-            "https://lh5.googleusercontent.com/-wjV6FQk7tlk/URqu9jCQ8sI/AAAAAAAAAbs/RyYUpdo-c9o/s1024/Rockaway%252520Flow.jpg",
-            "https://lh6.googleusercontent.com/-6cAXNfo7D20/URqu-BdzgPI/AAAAAAAAAbs/OmsYllzJqwo/s1024/Rockaway%252520Sunset%252520Sky.jpg",
-            "https://lh3.googleusercontent.com/-sl8fpGPS-RE/URqu_BOkfgI/AAAAAAAAAbs/Dg2Fv-JxOeg/s1024/Russian%252520Ridge%252520Sunset.jpg",
-            "https://lh6.googleusercontent.com/-gVtY36mMBIg/URqu_q91lkI/AAAAAAAAAbs/3CiFMBcy5MA/s1024/Rust%252520Knot.jpg",
-            "https://lh6.googleusercontent.com/-GHeImuHqJBE/URqu_FKfVLI/AAAAAAAAAbs/axuEJeqam7Q/s1024/Sailing%252520Stones.jpg",
-            "https://lh3.googleusercontent.com/-hBbYZjTOwGc/URqu_ycpIrI/AAAAAAAAAbs/nAdJUXnGJYE/s1024/Seahorse.jpg",
-            "https://lh3.googleusercontent.com/-Iwi6-i6IexY/URqvAYZHsVI/AAAAAAAAAbs/5ETWl4qXsFE/s1024/Shinjuku%252520Street.jpg",
-            "https://lh6.googleusercontent.com/-amhnySTM_MY/URqvAlb5KoI/AAAAAAAAAbs/pFCFgzlKsn0/s1024/Sierra%252520Heavens.jpg",
-            "https://lh5.googleusercontent.com/-dJgjepFrYSo/URqvBVJZrAI/AAAAAAAAAbs/v-F5QWpYO6s/s1024/Sierra%252520Sunset.jpg",
-            "https://lh4.googleusercontent.com/-Z4zGiC5nWdc/URqvBdEwivI/AAAAAAAAAbs/ZRZR1VJ84QA/s1024/Sin%252520Lights.jpg",
-            "https://lh4.googleusercontent.com/-_0cYiWW8ccY/URqvBz3iM4I/AAAAAAAAAbs/9N_Wq8MhLTY/s1024/Starry%252520Lake.jpg",
-            "https://lh3.googleusercontent.com/-A9LMoRyuQUA/URqvCYx_JoI/AAAAAAAAAbs/s7sde1Bz9cI/s1024/Starry%252520Night.jpg",
-            "https://lh3.googleusercontent.com/-KtLJ3k858eY/URqvC_2h_bI/AAAAAAAAAbs/zzEBImwDA_g/s1024/Stream.jpg",
-            "https://lh5.googleusercontent.com/-dFB7Lad6RcA/URqvDUftwWI/AAAAAAAAAbs/BrhoUtXTN7o/s1024/Strip%252520Sunset.jpg",
-            "https://lh5.googleusercontent.com/-at6apgFiN20/URqvDyffUZI/AAAAAAAAAbs/clABCx171bE/s1024/Sunset%252520Hills.jpg",
-            "https://lh4.googleusercontent.com/-7-EHhtQthII/URqvEYTk4vI/AAAAAAAAAbs/QSJZoB3YjVg/s1024/Tenaya%252520Lake%2525202.jpg",
-            "https://lh6.googleusercontent.com/-8MrjV_a-Pok/URqvFC5repI/AAAAAAAAAbs/9inKTg9fbCE/s1024/Tenaya%252520Lake.jpg",
-            "https://lh5.googleusercontent.com/-B1HW-z4zwao/URqvFWYRwUI/AAAAAAAAAbs/8Peli53Bs8I/s1024/The%252520Cave%252520BW.jpg",
-            "https://lh3.googleusercontent.com/-PO4E-xZKAnQ/URqvGRqjYkI/AAAAAAAAAbs/42nyADFsXag/s1024/The%252520Fisherman.jpg",
-            "https://lh4.googleusercontent.com/-iLyZlzfdy7s/URqvG0YScdI/AAAAAAAAAbs/1J9eDKmkXtk/s1024/The%252520Night%252520is%252520Coming.jpg",
-            "https://lh6.googleusercontent.com/-G-k7YkkUco0/URqvHhah6fI/AAAAAAAAAbs/_taQQG7t0vo/s1024/The%252520Road.jpg",
-            "https://lh6.googleusercontent.com/-h-ALJt7kSus/URqvIThqYfI/AAAAAAAAAbs/ejiv35olWS8/s1024/Tokyo%252520Heights.jpg",
-            "https://lh5.googleusercontent.com/-Hy9k-TbS7xg/URqvIjQMOxI/AAAAAAAAAbs/RSpmmOATSkg/s1024/Tokyo%252520Highway.jpg",
-            "https://lh6.googleusercontent.com/-83oOvMb4OZs/URqvJL0T7lI/AAAAAAAAAbs/c5TECZ6RONM/s1024/Tokyo%252520Smog.jpg",
-            "https://lh3.googleusercontent.com/-FB-jfgREEfI/URqvJI3EXAI/AAAAAAAAAbs/XfyweiRF4v8/s1024/Tufa%252520at%252520Night.jpg",
-            "https://lh4.googleusercontent.com/-vngKD5Z1U8w/URqvJUCEgPI/AAAAAAAAAbs/ulxCMVcU6EU/s1024/Valley%252520Sunset.jpg",
-            "https://lh6.googleusercontent.com/-DOz5I2E2oMQ/URqvKMND1kI/AAAAAAAAAbs/Iqf0IsInleo/s1024/Windmill%252520Sunrise.jpg",
-            "https://lh5.googleusercontent.com/-biyiyWcJ9MU/URqvKculiAI/AAAAAAAAAbs/jyPsCplJOpE/s1024/Windmill.jpg",
-            "https://lh4.googleusercontent.com/-PDT167_xRdA/URqvK36mLcI/AAAAAAAAAbs/oi2ik9QseMI/s1024/Windmills.jpg",
-            "https://lh5.googleusercontent.com/-kI_QdYx7VlU/URqvLXCB6gI/AAAAAAAAAbs/N31vlZ6u89o/s1024/Yet%252520Another%252520Rockaway%252520Sunset.jpg",
-            "https://lh4.googleusercontent.com/-e9NHZ5k5MSs/URqvMIBZjtI/AAAAAAAAAbs/1fV810rDNfQ/s1024/Yosemite%252520Tree.jpg",
-    };
-
-    /**
-     * This are PicasaWeb thumbnail URLs and could potentially change. Ideally the PicasaWeb API
-     * should be used to fetch the URLs.
-     *
-     * Credit to Romain Guy for the photos:
-     * http://www.curious-creature.org/
-     * https://plus.google.com/109538161516040592207/about
-     * http://www.flickr.com/photos/romainguy
-     */
-    public final static String[] imageThumbUrls = new String[] {
-            "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s160-c/A%252520Photographer.jpg",
-            "https://lh4.googleusercontent.com/--dq8niRp7W4/URquVgmXvgI/AAAAAAAAAbs/-gnuLQfNnBA/s160-c/A%252520Song%252520of%252520Ice%252520and%252520Fire.jpg",
-            "https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s160-c/Another%252520Rockaway%252520Sunset.jpg",
-            "https://lh3.googleusercontent.com/--L0Km39l5J8/URquXHGcdNI/AAAAAAAAAbs/3ZrSJNrSomQ/s160-c/Antelope%252520Butte.jpg",
-            "https://lh6.googleusercontent.com/-8HO-4vIFnlw/URquZnsFgtI/AAAAAAAAAbs/WT8jViTF7vw/s160-c/Antelope%252520Hallway.jpg",
-            "https://lh4.googleusercontent.com/-WIuWgVcU3Qw/URqubRVcj4I/AAAAAAAAAbs/YvbwgGjwdIQ/s160-c/Antelope%252520Walls.jpg",
-            "https://lh6.googleusercontent.com/-UBmLbPELvoQ/URqucCdv0kI/AAAAAAAAAbs/IdNhr2VQoQs/s160-c/Apre%2525CC%252580s%252520la%252520Pluie.jpg",
-            "https://lh3.googleusercontent.com/-s-AFpvgSeew/URquc6dF-JI/AAAAAAAAAbs/Mt3xNGRUd68/s160-c/Backlit%252520Cloud.jpg",
-            "https://lh5.googleusercontent.com/-bvmif9a9YOQ/URquea3heHI/AAAAAAAAAbs/rcr6wyeQtAo/s160-c/Bee%252520and%252520Flower.jpg",
-            "https://lh5.googleusercontent.com/-n7mdm7I7FGs/URqueT_BT-I/AAAAAAAAAbs/9MYmXlmpSAo/s160-c/Bonzai%252520Rock%252520Sunset.jpg",
-            "https://lh6.googleusercontent.com/-4CN4X4t0M1k/URqufPozWzI/AAAAAAAAAbs/8wK41lg1KPs/s160-c/Caterpillar.jpg",
-            "https://lh3.googleusercontent.com/-rrFnVC8xQEg/URqufdrLBaI/AAAAAAAAAbs/s69WYy_fl1E/s160-c/Chess.jpg",
-            "https://lh5.googleusercontent.com/-WVpRptWH8Yw/URqugh-QmDI/AAAAAAAAAbs/E-MgBgtlUWU/s160-c/Chihuly.jpg",
-            "https://lh5.googleusercontent.com/-0BDXkYmckbo/URquhKFW84I/AAAAAAAAAbs/ogQtHCTk2JQ/s160-c/Closed%252520Door.jpg",
-            "https://lh3.googleusercontent.com/-PyggXXZRykM/URquh-kVvoI/AAAAAAAAAbs/hFtDwhtrHHQ/s160-c/Colorado%252520River%252520Sunset.jpg",
-            "https://lh3.googleusercontent.com/-ZAs4dNZtALc/URquikvOCWI/AAAAAAAAAbs/DXz4h3dll1Y/s160-c/Colors%252520of%252520Autumn.jpg",
-            "https://lh4.googleusercontent.com/-GztnWEIiMz8/URqukVCU7bI/AAAAAAAAAbs/jo2Hjv6MZ6M/s160-c/Countryside.jpg",
-            "https://lh4.googleusercontent.com/-bEg9EZ9QoiM/URquklz3FGI/AAAAAAAAAbs/UUuv8Ac2BaE/s160-c/Death%252520Valley%252520-%252520Dunes.jpg",
-            "https://lh6.googleusercontent.com/-ijQJ8W68tEE/URqulGkvFEI/AAAAAAAAAbs/zPXvIwi_rFw/s160-c/Delicate%252520Arch.jpg",
-            "https://lh5.googleusercontent.com/-Oh8mMy2ieng/URqullDwehI/AAAAAAAAAbs/TbdeEfsaIZY/s160-c/Despair.jpg",
-            "https://lh5.googleusercontent.com/-gl0y4UiAOlk/URqumC_KjBI/AAAAAAAAAbs/PM1eT7dn4oo/s160-c/Eagle%252520Fall%252520Sunrise.jpg",
-            "https://lh3.googleusercontent.com/-hYYHd2_vXPQ/URqumtJa9eI/AAAAAAAAAbs/wAalXVkbSh0/s160-c/Electric%252520Storm.jpg",
-            "https://lh5.googleusercontent.com/-PyY_yiyjPTo/URqunUOhHFI/AAAAAAAAAbs/azZoULNuJXc/s160-c/False%252520Kiva.jpg",
-            "https://lh6.googleusercontent.com/-PYvLVdvXywk/URqunwd8hfI/AAAAAAAAAbs/qiMwgkFvf6I/s160-c/Fitzgerald%252520Streaks.jpg",
-            "https://lh4.googleusercontent.com/-KIR_UobIIqY/URquoCZ9SlI/AAAAAAAAAbs/Y4d4q8sXu4c/s160-c/Foggy%252520Sunset.jpg",
-            "https://lh6.googleusercontent.com/-9lzOk_OWZH0/URquoo4xYoI/AAAAAAAAAbs/AwgzHtNVCwU/s160-c/Frantic.jpg",
-            "https://lh3.googleusercontent.com/-0X3JNaKaz48/URqupH78wpI/AAAAAAAAAbs/lHXxu_zbH8s/s160-c/Golden%252520Gate%252520Afternoon.jpg",
-            "https://lh6.googleusercontent.com/-95sb5ag7ABc/URqupl95RDI/AAAAAAAAAbs/g73R20iVTRA/s160-c/Golden%252520Gate%252520Fog.jpg",
-            "https://lh3.googleusercontent.com/-JB9v6rtgHhk/URqup21F-zI/AAAAAAAAAbs/64Fb8qMZWXk/s160-c/Golden%252520Grass.jpg",
-            "https://lh4.googleusercontent.com/-EIBGfnuLtII/URquqVHwaRI/AAAAAAAAAbs/FA4McV2u8VE/s160-c/Grand%252520Teton.jpg",
-            "https://lh4.googleusercontent.com/-WoMxZvmN9nY/URquq1v2AoI/AAAAAAAAAbs/grj5uMhL6NA/s160-c/Grass%252520Closeup.jpg",
-            "https://lh3.googleusercontent.com/-6hZiEHXx64Q/URqurxvNdqI/AAAAAAAAAbs/kWMXM3o5OVI/s160-c/Green%252520Grass.jpg",
-            "https://lh5.googleusercontent.com/-6LVb9OXtQ60/URquteBFuKI/AAAAAAAAAbs/4F4kRgecwFs/s160-c/Hanging%252520Leaf.jpg",
-            "https://lh4.googleusercontent.com/-zAvf__52ONk/URqutT_IuxI/AAAAAAAAAbs/D_bcuc0thoU/s160-c/Highway%2525201.jpg",
-            "https://lh6.googleusercontent.com/-H4SrUg615rA/URquuL27fXI/AAAAAAAAAbs/4aEqJfiMsOU/s160-c/Horseshoe%252520Bend%252520Sunset.jpg",
-            "https://lh4.googleusercontent.com/-JhFi4fb_Pqw/URquuX-QXbI/AAAAAAAAAbs/IXpYUxuweYM/s160-c/Horseshoe%252520Bend.jpg",
-            "https://lh5.googleusercontent.com/-UGgssvFRJ7g/URquueyJzGI/AAAAAAAAAbs/yYIBlLT0toM/s160-c/Into%252520the%252520Blue.jpg",
-            "https://lh3.googleusercontent.com/-CH7KoupI7uI/URquu0FF__I/AAAAAAAAAbs/R7GDmI7v_G0/s160-c/Jelly%252520Fish%2525202.jpg",
-            "https://lh4.googleusercontent.com/-pwuuw6yhg8U/URquvPxR3FI/AAAAAAAAAbs/VNGk6f-tsGE/s160-c/Jelly%252520Fish%2525203.jpg",
-            "https://lh5.googleusercontent.com/-GoUQVw1fnFw/URquv6xbC0I/AAAAAAAAAbs/zEUVTQQ43Zc/s160-c/Kauai.jpg",
-            "https://lh6.googleusercontent.com/-8QdYYQEpYjw/URquwvdh88I/AAAAAAAAAbs/cktDy-ysfHo/s160-c/Kyoto%252520Sunset.jpg",
-            "https://lh4.googleusercontent.com/-vPeekyDjOE0/URquwzJ28qI/AAAAAAAAAbs/qxcyXULsZrg/s160-c/Lake%252520Tahoe%252520Colors.jpg",
-            "https://lh4.googleusercontent.com/-xBPxWpD4yxU/URquxWHk8AI/AAAAAAAAAbs/ARDPeDYPiMY/s160-c/Lava%252520from%252520the%252520Sky.jpg",
-            "https://lh3.googleusercontent.com/-897VXrJB6RE/URquxxxd-5I/AAAAAAAAAbs/j-Cz4T4YvIw/s160-c/Leica%25252050mm%252520Summilux.jpg",
-            "https://lh5.googleusercontent.com/-qSJ4D4iXzGo/URquyDWiJ1I/AAAAAAAAAbs/k2pBXeWehOA/s160-c/Leica%25252050mm%252520Summilux.jpg",
-            "https://lh6.googleusercontent.com/-dwlPg83vzLg/URquylTVuFI/AAAAAAAAAbs/G6SyQ8b4YsI/s160-c/Leica%252520M8%252520%252528Front%252529.jpg",
-            "https://lh3.googleusercontent.com/-R3_EYAyJvfk/URquzQBv8eI/AAAAAAAAAbs/b9xhpUM3pEI/s160-c/Light%252520to%252520Sand.jpg",
-            "https://lh3.googleusercontent.com/-fHY5h67QPi0/URqu0Cp4J1I/AAAAAAAAAbs/0lG6m94Z6vM/s160-c/Little%252520Bit%252520of%252520Paradise.jpg",
-            "https://lh5.googleusercontent.com/-TzF_LwrCnRM/URqu0RddPOI/AAAAAAAAAbs/gaj2dLiuX0s/s160-c/Lone%252520Pine%252520Sunset.jpg",
-            "https://lh3.googleusercontent.com/-4HdpJ4_DXU4/URqu046dJ9I/AAAAAAAAAbs/eBOodtk2_uk/s160-c/Lonely%252520Rock.jpg",
-            "https://lh6.googleusercontent.com/-erbF--z-W4s/URqu1ajSLkI/AAAAAAAAAbs/xjDCDO1INzM/s160-c/Longue%252520Vue.jpg",
-            "https://lh6.googleusercontent.com/-0CXJRdJaqvc/URqu1opNZNI/AAAAAAAAAbs/PFB2oPUU7Lk/s160-c/Look%252520Me%252520in%252520the%252520Eye.jpg",
-            "https://lh3.googleusercontent.com/-D_5lNxnDN6g/URqu2Tk7HVI/AAAAAAAAAbs/p0ddca9W__Y/s160-c/Lost%252520in%252520a%252520Field.jpg",
-            "https://lh6.googleusercontent.com/-flsqwMrIk2Q/URqu24PcmjI/AAAAAAAAAbs/5ocIH85XofM/s160-c/Marshall%252520Beach%252520Sunset.jpg",
-            "https://lh4.googleusercontent.com/-Y4lgryEVTmU/URqu28kG3gI/AAAAAAAAAbs/OjXpekqtbJ4/s160-c/Mono%252520Lake%252520Blue.jpg",
-            "https://lh4.googleusercontent.com/-AaHAJPmcGYA/URqu3PIldHI/AAAAAAAAAbs/lcTqk1SIcRs/s160-c/Monument%252520Valley%252520Overlook.jpg",
-            "https://lh4.googleusercontent.com/-vKxfdQ83dQA/URqu31Yq_BI/AAAAAAAAAbs/OUoGk_2AyfM/s160-c/Moving%252520Rock.jpg",
-            "https://lh5.googleusercontent.com/-CG62QiPpWXg/URqu4ia4vRI/AAAAAAAAAbs/0YOdqLAlcAc/s160-c/Napali%252520Coast.jpg",
-            "https://lh6.googleusercontent.com/-wdGrP5PMmJQ/URqu5PZvn7I/AAAAAAAAAbs/m0abEcdPXe4/s160-c/One%252520Wheel.jpg",
-            "https://lh6.googleusercontent.com/-6WS5DoCGuOA/URqu5qx1UgI/AAAAAAAAAbs/giMw2ixPvrY/s160-c/Open%252520Sky.jpg",
-            "https://lh6.googleusercontent.com/-u8EHKj8G8GQ/URqu55sM6yI/AAAAAAAAAbs/lIXX_GlTdmI/s160-c/Orange%252520Sunset.jpg",
-            "https://lh6.googleusercontent.com/-74Z5qj4bTDE/URqu6LSrJrI/AAAAAAAAAbs/XzmVkw90szQ/s160-c/Orchid.jpg",
-            "https://lh6.googleusercontent.com/-lEQE4h6TePE/URqu6t_lSkI/AAAAAAAAAbs/zvGYKOea_qY/s160-c/Over%252520there.jpg",
-            "https://lh5.googleusercontent.com/-cauH-53JH2M/URqu66v_USI/AAAAAAAAAbs/EucwwqclfKQ/s160-c/Plumes.jpg",
-            "https://lh3.googleusercontent.com/-eDLT2jHDoy4/URqu7axzkAI/AAAAAAAAAbs/iVZE-xJ7lZs/s160-c/Rainbokeh.jpg",
-            "https://lh5.googleusercontent.com/-j1NLqEFIyco/URqu8L1CGcI/AAAAAAAAAbs/aqZkgX66zlI/s160-c/Rainbow.jpg",
-            "https://lh5.googleusercontent.com/-DRnqmK0t4VU/URqu8XYN9yI/AAAAAAAAAbs/LgvF_592WLU/s160-c/Rice%252520Fields.jpg",
-            "https://lh3.googleusercontent.com/-hwh1v3EOGcQ/URqu8qOaKwI/AAAAAAAAAbs/IljRJRnbJGw/s160-c/Rockaway%252520Fire%252520Sky.jpg",
-            "https://lh5.googleusercontent.com/-wjV6FQk7tlk/URqu9jCQ8sI/AAAAAAAAAbs/RyYUpdo-c9o/s160-c/Rockaway%252520Flow.jpg",
-            "https://lh6.googleusercontent.com/-6cAXNfo7D20/URqu-BdzgPI/AAAAAAAAAbs/OmsYllzJqwo/s160-c/Rockaway%252520Sunset%252520Sky.jpg",
-            "https://lh3.googleusercontent.com/-sl8fpGPS-RE/URqu_BOkfgI/AAAAAAAAAbs/Dg2Fv-JxOeg/s160-c/Russian%252520Ridge%252520Sunset.jpg",
-            "https://lh6.googleusercontent.com/-gVtY36mMBIg/URqu_q91lkI/AAAAAAAAAbs/3CiFMBcy5MA/s160-c/Rust%252520Knot.jpg",
-            "https://lh6.googleusercontent.com/-GHeImuHqJBE/URqu_FKfVLI/AAAAAAAAAbs/axuEJeqam7Q/s160-c/Sailing%252520Stones.jpg",
-            "https://lh3.googleusercontent.com/-hBbYZjTOwGc/URqu_ycpIrI/AAAAAAAAAbs/nAdJUXnGJYE/s160-c/Seahorse.jpg",
-            "https://lh3.googleusercontent.com/-Iwi6-i6IexY/URqvAYZHsVI/AAAAAAAAAbs/5ETWl4qXsFE/s160-c/Shinjuku%252520Street.jpg",
-            "https://lh6.googleusercontent.com/-amhnySTM_MY/URqvAlb5KoI/AAAAAAAAAbs/pFCFgzlKsn0/s160-c/Sierra%252520Heavens.jpg",
-            "https://lh5.googleusercontent.com/-dJgjepFrYSo/URqvBVJZrAI/AAAAAAAAAbs/v-F5QWpYO6s/s160-c/Sierra%252520Sunset.jpg",
-            "https://lh4.googleusercontent.com/-Z4zGiC5nWdc/URqvBdEwivI/AAAAAAAAAbs/ZRZR1VJ84QA/s160-c/Sin%252520Lights.jpg",
-            "https://lh4.googleusercontent.com/-_0cYiWW8ccY/URqvBz3iM4I/AAAAAAAAAbs/9N_Wq8MhLTY/s160-c/Starry%252520Lake.jpg",
-            "https://lh3.googleusercontent.com/-A9LMoRyuQUA/URqvCYx_JoI/AAAAAAAAAbs/s7sde1Bz9cI/s160-c/Starry%252520Night.jpg",
-            "https://lh3.googleusercontent.com/-KtLJ3k858eY/URqvC_2h_bI/AAAAAAAAAbs/zzEBImwDA_g/s160-c/Stream.jpg",
-            "https://lh5.googleusercontent.com/-dFB7Lad6RcA/URqvDUftwWI/AAAAAAAAAbs/BrhoUtXTN7o/s160-c/Strip%252520Sunset.jpg",
-            "https://lh5.googleusercontent.com/-at6apgFiN20/URqvDyffUZI/AAAAAAAAAbs/clABCx171bE/s160-c/Sunset%252520Hills.jpg",
-            "https://lh4.googleusercontent.com/-7-EHhtQthII/URqvEYTk4vI/AAAAAAAAAbs/QSJZoB3YjVg/s160-c/Tenaya%252520Lake%2525202.jpg",
-            "https://lh6.googleusercontent.com/-8MrjV_a-Pok/URqvFC5repI/AAAAAAAAAbs/9inKTg9fbCE/s160-c/Tenaya%252520Lake.jpg",
-            "https://lh5.googleusercontent.com/-B1HW-z4zwao/URqvFWYRwUI/AAAAAAAAAbs/8Peli53Bs8I/s160-c/The%252520Cave%252520BW.jpg",
-            "https://lh3.googleusercontent.com/-PO4E-xZKAnQ/URqvGRqjYkI/AAAAAAAAAbs/42nyADFsXag/s160-c/The%252520Fisherman.jpg",
-            "https://lh4.googleusercontent.com/-iLyZlzfdy7s/URqvG0YScdI/AAAAAAAAAbs/1J9eDKmkXtk/s160-c/The%252520Night%252520is%252520Coming.jpg",
-            "https://lh6.googleusercontent.com/-G-k7YkkUco0/URqvHhah6fI/AAAAAAAAAbs/_taQQG7t0vo/s160-c/The%252520Road.jpg",
-            "https://lh6.googleusercontent.com/-h-ALJt7kSus/URqvIThqYfI/AAAAAAAAAbs/ejiv35olWS8/s160-c/Tokyo%252520Heights.jpg",
-            "https://lh5.googleusercontent.com/-Hy9k-TbS7xg/URqvIjQMOxI/AAAAAAAAAbs/RSpmmOATSkg/s160-c/Tokyo%252520Highway.jpg",
-            "https://lh6.googleusercontent.com/-83oOvMb4OZs/URqvJL0T7lI/AAAAAAAAAbs/c5TECZ6RONM/s160-c/Tokyo%252520Smog.jpg",
-            "https://lh3.googleusercontent.com/-FB-jfgREEfI/URqvJI3EXAI/AAAAAAAAAbs/XfyweiRF4v8/s160-c/Tufa%252520at%252520Night.jpg",
-            "https://lh4.googleusercontent.com/-vngKD5Z1U8w/URqvJUCEgPI/AAAAAAAAAbs/ulxCMVcU6EU/s160-c/Valley%252520Sunset.jpg",
-            "https://lh6.googleusercontent.com/-DOz5I2E2oMQ/URqvKMND1kI/AAAAAAAAAbs/Iqf0IsInleo/s160-c/Windmill%252520Sunrise.jpg",
-            "https://lh5.googleusercontent.com/-biyiyWcJ9MU/URqvKculiAI/AAAAAAAAAbs/jyPsCplJOpE/s160-c/Windmill.jpg",
-            "https://lh4.googleusercontent.com/-PDT167_xRdA/URqvK36mLcI/AAAAAAAAAbs/oi2ik9QseMI/s160-c/Windmills.jpg",
-            "https://lh5.googleusercontent.com/-kI_QdYx7VlU/URqvLXCB6gI/AAAAAAAAAbs/N31vlZ6u89o/s160-c/Yet%252520Another%252520Rockaway%252520Sunset.jpg",
-            "https://lh4.googleusercontent.com/-e9NHZ5k5MSs/URqvMIBZjtI/AAAAAAAAAbs/1fV810rDNfQ/s160-c/Yosemite%252520Tree.jpg",
-    };
-}
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/ImageGridActivity.java b/samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/ImageGridActivity.java
deleted file mode 100644
index 2e00930..0000000
--- a/samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/ImageGridActivity.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.bitmapfun.ui;
-
-import com.example.android.bitmapfun.BuildConfig;
-import com.example.android.bitmapfun.util.Utils;
-
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentTransaction;
-
-/**
- * Simple FragmentActivity to hold the main {@link ImageGridFragment} and not much else.
- */
-public class ImageGridActivity extends FragmentActivity {
-    private static final String TAG = "ImageGridActivity";
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        if (BuildConfig.DEBUG) {
-            Utils.enableStrictMode();
-        }
-        super.onCreate(savedInstanceState);
-
-        if (getSupportFragmentManager().findFragmentByTag(TAG) == null) {
-            final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-            ft.add(android.R.id.content, new ImageGridFragment(), TAG);
-            ft.commit();
-        }
-    }
-}
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/ImageGridFragment.java b/samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/ImageGridFragment.java
deleted file mode 100644
index 9076cd9..0000000
--- a/samples/training/bitmapfun/src/com/example/android/bitmapfun/ui/ImageGridFragment.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.bitmapfun.ui;
-
-import android.annotation.TargetApi;
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.ViewTreeObserver;
-import android.widget.AbsListView;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.GridView;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.example.android.bitmapfun.BuildConfig;
-import com.example.android.bitmapfun.R;
-import com.example.android.bitmapfun.provider.Images;
-import com.example.android.bitmapfun.util.ImageCache.ImageCacheParams;
-import com.example.android.bitmapfun.util.ImageFetcher;
-import com.example.android.bitmapfun.util.Utils;
-
-/**
- * The main fragment that powers the ImageGridActivity screen. Fairly straight forward GridView
- * implementation with the key addition being the ImageWorker class w/ImageCache to load children
- * asynchronously, keeping the UI nice and smooth and caching thumbnails for quick retrieval. The
- * cache is retained over configuration changes like orientation change so the images are populated
- * quickly if, for example, the user rotates the device.
- */
-public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
-    private static final String TAG = "ImageGridFragment";
-    private static final String IMAGE_CACHE_DIR = "thumbs";
-
-    private int mImageThumbSize;
-    private int mImageThumbSpacing;
-    private ImageAdapter mAdapter;
-    private ImageFetcher mImageFetcher;
-
-    /**
-     * Empty constructor as per the Fragment documentation
-     */
-    public ImageGridFragment() {}
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setHasOptionsMenu(true);
-
-        mImageThumbSize = getResources().getDimensionPixelSize(R.dimen.image_thumbnail_size);
-        mImageThumbSpacing = getResources().getDimensionPixelSize(R.dimen.image_thumbnail_spacing);
-
-        mAdapter = new ImageAdapter(getActivity());
-
-        ImageCacheParams cacheParams = new ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
-
-        cacheParams.setMemCacheSizePercent(0.25f); // Set memory cache to 25% of app memory
-
-        // The ImageFetcher takes care of loading images into our ImageView children asynchronously
-        mImageFetcher = new ImageFetcher(getActivity(), mImageThumbSize);
-        mImageFetcher.setLoadingImage(R.drawable.empty_photo);
-        mImageFetcher.addImageCache(getActivity().getSupportFragmentManager(), cacheParams);
-    }
-
-    @Override
-    public View onCreateView(
-            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
-        final View v = inflater.inflate(R.layout.image_grid_fragment, container, false);
-        final GridView mGridView = (GridView) v.findViewById(R.id.gridView);
-        mGridView.setAdapter(mAdapter);
-        mGridView.setOnItemClickListener(this);
-        mGridView.setOnScrollListener(new AbsListView.OnScrollListener() {
-            @Override
-            public void onScrollStateChanged(AbsListView absListView, int scrollState) {
-                // Pause fetcher to ensure smoother scrolling when flinging
-                if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
-                    mImageFetcher.setPauseWork(true);
-                } else {
-                    mImageFetcher.setPauseWork(false);
-                }
-            }
-
-            @Override
-            public void onScroll(AbsListView absListView, int firstVisibleItem,
-                    int visibleItemCount, int totalItemCount) {
-            }
-        });
-
-        // This listener is used to get the final width of the GridView and then calculate the
-        // number of columns and the width of each column. The width of each column is variable
-        // as the GridView has stretchMode=columnWidth. The column width is used to set the height
-        // of each view so we get nice square thumbnails.
-        mGridView.getViewTreeObserver().addOnGlobalLayoutListener(
-                new ViewTreeObserver.OnGlobalLayoutListener() {
-                    @Override
-                    public void onGlobalLayout() {
-                        if (mAdapter.getNumColumns() == 0) {
-                            final int numColumns = (int) Math.floor(
-                                    mGridView.getWidth() / (mImageThumbSize + mImageThumbSpacing));
-                            if (numColumns > 0) {
-                                final int columnWidth =
-                                        (mGridView.getWidth() / numColumns) - mImageThumbSpacing;
-                                mAdapter.setNumColumns(numColumns);
-                                mAdapter.setItemHeight(columnWidth);
-                                if (BuildConfig.DEBUG) {
-                                    Log.d(TAG, "onCreateView - numColumns set to " + numColumns);
-                                }
-                            }
-                        }
-                    }
-                });
-
-        return v;
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        mImageFetcher.setExitTasksEarly(false);
-        mAdapter.notifyDataSetChanged();
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        mImageFetcher.setPauseWork(false);
-        mImageFetcher.setExitTasksEarly(true);
-        mImageFetcher.flushCache();
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        mImageFetcher.closeCache();
-    }
-
-    @TargetApi(16)
-    @Override
-    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
-        final Intent i = new Intent(getActivity(), ImageDetailActivity.class);
-        i.putExtra(ImageDetailActivity.EXTRA_IMAGE, (int) id);
-        if (Utils.hasJellyBean()) {
-            // makeThumbnailScaleUpAnimation() looks kind of ugly here as the loading spinner may
-            // show plus the thumbnail image in GridView is cropped. so using
-            // makeScaleUpAnimation() instead.
-            ActivityOptions options =
-                    ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getWidth(), v.getHeight());
-            getActivity().startActivity(i, options.toBundle());
-        } else {
-            startActivity(i);
-        }
-    }
-
-    @Override
-    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        inflater.inflate(R.menu.main_menu, menu);
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.clear_cache:
-                mImageFetcher.clearCache();
-                Toast.makeText(getActivity(), R.string.clear_cache_complete_toast,
-                        Toast.LENGTH_SHORT).show();
-                return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    /**
-     * The main adapter that backs the GridView. This is fairly standard except the number of
-     * columns in the GridView is used to create a fake top row of empty views as we use a
-     * transparent ActionBar and don't want the real top row of images to start off covered by it.
-     */
-    private class ImageAdapter extends BaseAdapter {
-
-        private final Context mContext;
-        private int mItemHeight = 0;
-        private int mNumColumns = 0;
-        private int mActionBarHeight = 0;
-        private GridView.LayoutParams mImageViewLayoutParams;
-
-        public ImageAdapter(Context context) {
-            super();
-            mContext = context;
-            mImageViewLayoutParams = new GridView.LayoutParams(
-                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-            // Calculate ActionBar height
-            TypedValue tv = new TypedValue();
-            if (context.getTheme().resolveAttribute(
-                    android.R.attr.actionBarSize, tv, true)) {
-                mActionBarHeight = TypedValue.complexToDimensionPixelSize(
-                        tv.data, context.getResources().getDisplayMetrics());
-            }
-        }
-
-        @Override
-        public int getCount() {
-            // Size + number of columns for top empty row
-            return Images.imageThumbUrls.length + mNumColumns;
-        }
-
-        @Override
-        public Object getItem(int position) {
-            return position < mNumColumns ?
-                    null : Images.imageThumbUrls[position - mNumColumns];
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return position < mNumColumns ? 0 : position - mNumColumns;
-        }
-
-        @Override
-        public int getViewTypeCount() {
-            // Two types of views, the normal ImageView and the top row of empty views
-            return 2;
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            return (position < mNumColumns) ? 1 : 0;
-        }
-
-        @Override
-        public boolean hasStableIds() {
-            return true;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup container) {
-            // First check if this is the top row
-            if (position < mNumColumns) {
-                if (convertView == null) {
-                    convertView = new View(mContext);
-                }
-                // Set empty view with height of ActionBar
-                convertView.setLayoutParams(new AbsListView.LayoutParams(
-                        ViewGroup.LayoutParams.MATCH_PARENT, mActionBarHeight));
-                return convertView;
-            }
-
-            // Now handle the main ImageView thumbnails
-            ImageView imageView;
-            if (convertView == null) { // if it's not recycled, instantiate and initialize
-                imageView = new RecyclingImageView(mContext);
-                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
-                imageView.setLayoutParams(mImageViewLayoutParams);
-            } else { // Otherwise re-use the converted view
-                imageView = (ImageView) convertView;
-            }
-
-            // Check the height matches our calculated column width
-            if (imageView.getLayoutParams().height != mItemHeight) {
-                imageView.setLayoutParams(mImageViewLayoutParams);
-            }
-
-            // Finally load the image asynchronously into the ImageView, this also takes care of
-            // setting a placeholder image while the background thread runs
-            mImageFetcher.loadImage(Images.imageThumbUrls[position - mNumColumns], imageView);
-            return imageView;
-        }
-
-        /**
-         * Sets the item height. Useful for when we know the column width so the height can be set
-         * to match.
-         *
-         * @param height
-         */
-        public void setItemHeight(int height) {
-            if (height == mItemHeight) {
-                return;
-            }
-            mItemHeight = height;
-            mImageViewLayoutParams =
-                    new GridView.LayoutParams(LayoutParams.MATCH_PARENT, mItemHeight);
-            mImageFetcher.setImageSize(height);
-            notifyDataSetChanged();
-        }
-
-        public void setNumColumns(int numColumns) {
-            mNumColumns = numColumns;
-        }
-
-        public int getNumColumns() {
-            return mNumColumns;
-        }
-    }
-}
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/ImageCache.java b/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/ImageCache.java
deleted file mode 100644
index 1459c12..0000000
--- a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/ImageCache.java
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.bitmapfun.util;
-
-import com.example.android.bitmapfun.BuildConfig;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.CompressFormat;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.StatFs;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.util.LruCache;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.ref.SoftReference;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.HashSet;
-import java.util.Iterator;
-
-/**
- * This class handles disk and memory caching of bitmaps in conjunction with the
- * {@link ImageWorker} class and its subclasses. Use
- * {@link ImageCache#getInstance(FragmentManager, ImageCacheParams)} to get an instance of this
- * class, although usually a cache should be added directly to an {@link ImageWorker} by calling
- * {@link ImageWorker#addImageCache(FragmentManager, ImageCacheParams)}.
- */
-public class ImageCache {
-    private static final String TAG = "ImageCache";
-
-    // Default memory cache size in kilobytes
-    private static final int DEFAULT_MEM_CACHE_SIZE = 1024 * 5; // 5MB
-
-    // Default disk cache size in bytes
-    private static final int DEFAULT_DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
-
-    // Compression settings when writing images to disk cache
-    private static final CompressFormat DEFAULT_COMPRESS_FORMAT = CompressFormat.JPEG;
-    private static final int DEFAULT_COMPRESS_QUALITY = 70;
-    private static final int DISK_CACHE_INDEX = 0;
-
-    // Constants to easily toggle various caches
-    private static final boolean DEFAULT_MEM_CACHE_ENABLED = true;
-    private static final boolean DEFAULT_DISK_CACHE_ENABLED = true;
-    private static final boolean DEFAULT_INIT_DISK_CACHE_ON_CREATE = false;
-
-    private DiskLruCache mDiskLruCache;
-    private LruCache<String, BitmapDrawable> mMemoryCache;
-    private ImageCacheParams mCacheParams;
-    private final Object mDiskCacheLock = new Object();
-    private boolean mDiskCacheStarting = true;
-
-    private HashSet<SoftReference<Bitmap>> mReusableBitmaps;
-
-    /**
-     * Create a new ImageCache object using the specified parameters. This should not be
-     * called directly by other classes, instead use
-     * {@link ImageCache#getInstance(FragmentManager, ImageCacheParams)} to fetch an ImageCache
-     * instance.
-     *
-     * @param cacheParams The cache parameters to use to initialize the cache
-     */
-    private ImageCache(ImageCacheParams cacheParams) {
-        init(cacheParams);
-    }
-
-    /**
-     * Return an {@link ImageCache} instance. A {@link RetainFragment} is used to retain the
-     * ImageCache object across configuration changes such as a change in device orientation.
-     *
-     * @param fragmentManager The fragment manager to use when dealing with the retained fragment.
-     * @param cacheParams The cache parameters to use if the ImageCache needs instantiation.
-     * @return An existing retained ImageCache object or a new one if one did not exist
-     */
-    public static ImageCache getInstance(
-            FragmentManager fragmentManager, ImageCacheParams cacheParams) {
-
-        // Search for, or create an instance of the non-UI RetainFragment
-        final RetainFragment mRetainFragment = findOrCreateRetainFragment(fragmentManager);
-
-        // See if we already have an ImageCache stored in RetainFragment
-        ImageCache imageCache = (ImageCache) mRetainFragment.getObject();
-
-        // No existing ImageCache, create one and store it in RetainFragment
-        if (imageCache == null) {
-            imageCache = new ImageCache(cacheParams);
-            mRetainFragment.setObject(imageCache);
-        }
-
-        return imageCache;
-    }
-
-    /**
-     * Initialize the cache, providing all parameters.
-     *
-     * @param cacheParams The cache parameters to initialize the cache
-     */
-    private void init(ImageCacheParams cacheParams) {
-        mCacheParams = cacheParams;
-
-        // Set up memory cache
-        if (mCacheParams.memoryCacheEnabled) {
-            if (BuildConfig.DEBUG) {
-                Log.d(TAG, "Memory cache created (size = " + mCacheParams.memCacheSize + ")");
-            }
-
-            // If we're running on Honeycomb or newer, then
-            if (Utils.hasHoneycomb()) {
-                mReusableBitmaps = new HashSet<SoftReference<Bitmap>>();
-            }
-
-            mMemoryCache = new LruCache<String, BitmapDrawable>(mCacheParams.memCacheSize) {
-
-                /**
-                 * Notify the removed entry that is no longer being cached
-                 */
-                @Override
-                protected void entryRemoved(boolean evicted, String key,
-                        BitmapDrawable oldValue, BitmapDrawable newValue) {
-                    if (RecyclingBitmapDrawable.class.isInstance(oldValue)) {
-                        // The removed entry is a recycling drawable, so notify it 
-                        // that it has been removed from the memory cache
-                        ((RecyclingBitmapDrawable) oldValue).setIsCached(false);
-                    } else {
-                        // The removed entry is a standard BitmapDrawable
-
-                        if (Utils.hasHoneycomb()) {
-                            // We're running on Honeycomb or later, so add the bitmap
-                            // to a SoftRefrence set for possible use with inBitmap later
-                            mReusableBitmaps.add(new SoftReference<Bitmap>(oldValue.getBitmap()));
-                        }
-                    }
-                }
-
-                /**
-                 * Measure item size in kilobytes rather than units which is more practical
-                 * for a bitmap cache
-                 */
-                @Override
-                protected int sizeOf(String key, BitmapDrawable value) {
-                    final int bitmapSize = getBitmapSize(value) / 1024;
-                    return bitmapSize == 0 ? 1 : bitmapSize;
-                }
-            };
-        }
-
-        // By default the disk cache is not initialized here as it should be initialized
-        // on a separate thread due to disk access.
-        if (cacheParams.initDiskCacheOnCreate) {
-            // Set up disk cache
-            initDiskCache();
-        }
-    }
-
-    /**
-     * Initializes the disk cache.  Note that this includes disk access so this should not be
-     * executed on the main/UI thread. By default an ImageCache does not initialize the disk
-     * cache when it is created, instead you should call initDiskCache() to initialize it on a
-     * background thread.
-     */
-    public void initDiskCache() {
-        // Set up disk cache
-        synchronized (mDiskCacheLock) {
-            if (mDiskLruCache == null || mDiskLruCache.isClosed()) {
-                File diskCacheDir = mCacheParams.diskCacheDir;
-                if (mCacheParams.diskCacheEnabled && diskCacheDir != null) {
-                    if (!diskCacheDir.exists()) {
-                        diskCacheDir.mkdirs();
-                    }
-                    if (getUsableSpace(diskCacheDir) > mCacheParams.diskCacheSize) {
-                        try {
-                            mDiskLruCache = DiskLruCache.open(
-                                    diskCacheDir, 1, 1, mCacheParams.diskCacheSize);
-                            if (BuildConfig.DEBUG) {
-                                Log.d(TAG, "Disk cache initialized");
-                            }
-                        } catch (final IOException e) {
-                            mCacheParams.diskCacheDir = null;
-                            Log.e(TAG, "initDiskCache - " + e);
-                        }
-                    }
-                }
-            }
-            mDiskCacheStarting = false;
-            mDiskCacheLock.notifyAll();
-        }
-    }
-
-    /**
-     * Adds a bitmap to both memory and disk cache.
-     * @param data Unique identifier for the bitmap to store
-     * @param value The bitmap drawable to store
-     */
-    public void addBitmapToCache(String data, BitmapDrawable value) {
-        if (data == null || value == null) {
-            return;
-        }
-
-        // Add to memory cache
-        if (mMemoryCache != null) {
-            if (RecyclingBitmapDrawable.class.isInstance(value)) {
-                // The removed entry is a recycling drawable, so notify it 
-                // that it has been added into the memory cache
-                ((RecyclingBitmapDrawable) value).setIsCached(true);
-            }
-            mMemoryCache.put(data, value);
-        }
-
-        synchronized (mDiskCacheLock) {
-            // Add to disk cache
-            if (mDiskLruCache != null) {
-                final String key = hashKeyForDisk(data);
-                OutputStream out = null;
-                try {
-                    DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
-                    if (snapshot == null) {
-                        final DiskLruCache.Editor editor = mDiskLruCache.edit(key);
-                        if (editor != null) {
-                            out = editor.newOutputStream(DISK_CACHE_INDEX);
-                            value.getBitmap().compress(
-                                    mCacheParams.compressFormat, mCacheParams.compressQuality, out);
-                            editor.commit();
-                            out.close();
-                        }
-                    } else {
-                        snapshot.getInputStream(DISK_CACHE_INDEX).close();
-                    }
-                } catch (final IOException e) {
-                    Log.e(TAG, "addBitmapToCache - " + e);
-                } catch (Exception e) {
-                    Log.e(TAG, "addBitmapToCache - " + e);
-                } finally {
-                    try {
-                        if (out != null) {
-                            out.close();
-                        }
-                    } catch (IOException e) {}
-                }
-            }
-        }
-    }
-
-    /**
-     * Get from memory cache.
-     *
-     * @param data Unique identifier for which item to get
-     * @return The bitmap drawable if found in cache, null otherwise
-     */
-    public BitmapDrawable getBitmapFromMemCache(String data) {
-        BitmapDrawable memValue = null;
-
-        if (mMemoryCache != null) {
-            memValue = mMemoryCache.get(data);
-        }
-
-        if (BuildConfig.DEBUG && memValue != null) {
-            Log.d(TAG, "Memory cache hit");
-        }
-
-        return memValue;
-    }
-
-    /**
-     * Get from disk cache.
-     *
-     * @param data Unique identifier for which item to get
-     * @return The bitmap if found in cache, null otherwise
-     */
-    public Bitmap getBitmapFromDiskCache(String data) {
-        final String key = hashKeyForDisk(data);
-        Bitmap bitmap = null;
-
-        synchronized (mDiskCacheLock) {
-            while (mDiskCacheStarting) {
-                try {
-                    mDiskCacheLock.wait();
-                } catch (InterruptedException e) {}
-            }
-            if (mDiskLruCache != null) {
-                InputStream inputStream = null;
-                try {
-                    final DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
-                    if (snapshot != null) {
-                        if (BuildConfig.DEBUG) {
-                            Log.d(TAG, "Disk cache hit");
-                        }
-                        inputStream = snapshot.getInputStream(DISK_CACHE_INDEX);
-                        if (inputStream != null) {
-                            FileDescriptor fd = ((FileInputStream) inputStream).getFD();
-
-                            // Decode bitmap, but we don't want to sample so give
-                            // MAX_VALUE as the target dimensions
-                            bitmap = ImageResizer.decodeSampledBitmapFromDescriptor(
-                                    fd, Integer.MAX_VALUE, Integer.MAX_VALUE, this);
-                        }
-                    }
-                } catch (final IOException e) {
-                    Log.e(TAG, "getBitmapFromDiskCache - " + e);
-                } finally {
-                    try {
-                        if (inputStream != null) {
-                            inputStream.close();
-                        }
-                    } catch (IOException e) {}
-                }
-            }
-            return bitmap;
-        }
-    }
-
-    /**
-     * @param options - BitmapFactory.Options with out* options populated
-     * @return Bitmap that case be used for inBitmap
-     */
-    protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) {
-        Bitmap bitmap = null;
-
-        if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) {
-            final Iterator<SoftReference<Bitmap>> iterator = mReusableBitmaps.iterator();
-            Bitmap item;
-
-            while (iterator.hasNext()) {
-                item = iterator.next().get();
-
-                if (null != item && item.isMutable()) {
-                    // Check to see it the item can be used for inBitmap
-                    if (canUseForInBitmap(item, options)) {
-                        bitmap = item;
-
-                        // Remove from reusable set so it can't be used again
-                        iterator.remove();
-                        break;
-                    }
-                } else {
-                    // Remove from the set if the reference has been cleared.
-                    iterator.remove();
-                }
-            }
-        }
-
-        return bitmap;
-    }
-
-    /**
-     * Clears both the memory and disk cache associated with this ImageCache object. Note that
-     * this includes disk access so this should not be executed on the main/UI thread.
-     */
-    public void clearCache() {
-        if (mMemoryCache != null) {
-            mMemoryCache.evictAll();
-            if (BuildConfig.DEBUG) {
-                Log.d(TAG, "Memory cache cleared");
-            }
-        }
-
-        synchronized (mDiskCacheLock) {
-            mDiskCacheStarting = true;
-            if (mDiskLruCache != null && !mDiskLruCache.isClosed()) {
-                try {
-                    mDiskLruCache.delete();
-                    if (BuildConfig.DEBUG) {
-                        Log.d(TAG, "Disk cache cleared");
-                    }
-                } catch (IOException e) {
-                    Log.e(TAG, "clearCache - " + e);
-                }
-                mDiskLruCache = null;
-                initDiskCache();
-            }
-        }
-    }
-
-    /**
-     * Flushes the disk cache associated with this ImageCache object. Note that this includes
-     * disk access so this should not be executed on the main/UI thread.
-     */
-    public void flush() {
-        synchronized (mDiskCacheLock) {
-            if (mDiskLruCache != null) {
-                try {
-                    mDiskLruCache.flush();
-                    if (BuildConfig.DEBUG) {
-                        Log.d(TAG, "Disk cache flushed");
-                    }
-                } catch (IOException e) {
-                    Log.e(TAG, "flush - " + e);
-                }
-            }
-        }
-    }
-
-    /**
-     * Closes the disk cache associated with this ImageCache object. Note that this includes
-     * disk access so this should not be executed on the main/UI thread.
-     */
-    public void close() {
-        synchronized (mDiskCacheLock) {
-            if (mDiskLruCache != null) {
-                try {
-                    if (!mDiskLruCache.isClosed()) {
-                        mDiskLruCache.close();
-                        mDiskLruCache = null;
-                        if (BuildConfig.DEBUG) {
-                            Log.d(TAG, "Disk cache closed");
-                        }
-                    }
-                } catch (IOException e) {
-                    Log.e(TAG, "close - " + e);
-                }
-            }
-        }
-    }
-
-    /**
-     * A holder class that contains cache parameters.
-     */
-    public static class ImageCacheParams {
-        public int memCacheSize = DEFAULT_MEM_CACHE_SIZE;
-        public int diskCacheSize = DEFAULT_DISK_CACHE_SIZE;
-        public File diskCacheDir;
-        public CompressFormat compressFormat = DEFAULT_COMPRESS_FORMAT;
-        public int compressQuality = DEFAULT_COMPRESS_QUALITY;
-        public boolean memoryCacheEnabled = DEFAULT_MEM_CACHE_ENABLED;
-        public boolean diskCacheEnabled = DEFAULT_DISK_CACHE_ENABLED;
-        public boolean initDiskCacheOnCreate = DEFAULT_INIT_DISK_CACHE_ON_CREATE;
-
-        /**
-         * Create a set of image cache parameters that can be provided to
-         * {@link ImageCache#getInstance(FragmentManager, ImageCacheParams)} or
-         * {@link ImageWorker#addImageCache(FragmentManager, ImageCacheParams)}.
-         * @param context A context to use.
-         * @param diskCacheDirectoryName A unique subdirectory name that will be appended to the
-         *                               application cache directory. Usually "cache" or "images"
-         *                               is sufficient.
-         */
-        public ImageCacheParams(Context context, String diskCacheDirectoryName) {
-            diskCacheDir = getDiskCacheDir(context, diskCacheDirectoryName);
-        }
-
-        /**
-         * Sets the memory cache size based on a percentage of the max available VM memory.
-         * Eg. setting percent to 0.2 would set the memory cache to one fifth of the available
-         * memory. Throws {@link IllegalArgumentException} if percent is < 0.05 or > .8.
-         * memCacheSize is stored in kilobytes instead of bytes as this will eventually be passed
-         * to construct a LruCache which takes an int in its constructor.
-         *
-         * This value should be chosen carefully based on a number of factors
-         * Refer to the corresponding Android Training class for more discussion:
-         * http://developer.android.com/training/displaying-bitmaps/
-         *
-         * @param percent Percent of available app memory to use to size memory cache
-         */
-        public void setMemCacheSizePercent(float percent) {
-            if (percent < 0.05f || percent > 0.8f) {
-                throw new IllegalArgumentException("setMemCacheSizePercent - percent must be "
-                        + "between 0.05 and 0.8 (inclusive)");
-            }
-            memCacheSize = Math.round(percent * Runtime.getRuntime().maxMemory() / 1024);
-        }
-    }
-
-    /**
-     * @param candidate - Bitmap to check
-     * @param targetOptions - Options that have the out* value populated
-     * @return true if <code>candidate</code> can be used for inBitmap re-use with
-     *      <code>targetOptions</code>
-     */
-    private static boolean canUseForInBitmap(
-            Bitmap candidate, BitmapFactory.Options targetOptions) {
-        int width = targetOptions.outWidth / targetOptions.inSampleSize;
-        int height = targetOptions.outHeight / targetOptions.inSampleSize;
-
-        return candidate.getWidth() == width && candidate.getHeight() == height;
-    }
-
-    /**
-     * Get a usable cache directory (external if available, internal otherwise).
-     *
-     * @param context The context to use
-     * @param uniqueName A unique directory name to append to the cache dir
-     * @return The cache dir
-     */
-    public static File getDiskCacheDir(Context context, String uniqueName) {
-        // Check if media is mounted or storage is built-in, if so, try and use external cache dir
-        // otherwise use internal cache dir
-        final String cachePath =
-                Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
-                        !isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :
-                                context.getCacheDir().getPath();
-
-        return new File(cachePath + File.separator + uniqueName);
-    }
-
-    /**
-     * A hashing method that changes a string (like a URL) into a hash suitable for using as a
-     * disk filename.
-     */
-    public static String hashKeyForDisk(String key) {
-        String cacheKey;
-        try {
-            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
-            mDigest.update(key.getBytes());
-            cacheKey = bytesToHexString(mDigest.digest());
-        } catch (NoSuchAlgorithmException e) {
-            cacheKey = String.valueOf(key.hashCode());
-        }
-        return cacheKey;
-    }
-
-    private static String bytesToHexString(byte[] bytes) {
-        // http://stackoverflow.com/questions/332079
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < bytes.length; i++) {
-            String hex = Integer.toHexString(0xFF & bytes[i]);
-            if (hex.length() == 1) {
-                sb.append('0');
-            }
-            sb.append(hex);
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Get the size in bytes of a bitmap in a BitmapDrawable.
-     * @param value
-     * @return size in bytes
-     */
-    @TargetApi(12)
-    public static int getBitmapSize(BitmapDrawable value) {
-        Bitmap bitmap = value.getBitmap();
-
-        if (Utils.hasHoneycombMR1()) {
-            return bitmap.getByteCount();
-        }
-        // Pre HC-MR1
-        return bitmap.getRowBytes() * bitmap.getHeight();
-    }
-
-    /**
-     * Check if external storage is built-in or removable.
-     *
-     * @return True if external storage is removable (like an SD card), false
-     *         otherwise.
-     */
-    @TargetApi(9)
-    public static boolean isExternalStorageRemovable() {
-        if (Utils.hasGingerbread()) {
-            return Environment.isExternalStorageRemovable();
-        }
-        return true;
-    }
-
-    /**
-     * Get the external app cache directory.
-     *
-     * @param context The context to use
-     * @return The external cache dir
-     */
-    @TargetApi(8)
-    public static File getExternalCacheDir(Context context) {
-        if (Utils.hasFroyo()) {
-            return context.getExternalCacheDir();
-        }
-
-        // Before Froyo we need to construct the external cache dir ourselves
-        final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/";
-        return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);
-    }
-
-    /**
-     * Check how much usable space is available at a given path.
-     *
-     * @param path The path to check
-     * @return The space available in bytes
-     */
-    @TargetApi(9)
-    public static long getUsableSpace(File path) {
-        if (Utils.hasGingerbread()) {
-            return path.getUsableSpace();
-        }
-        final StatFs stats = new StatFs(path.getPath());
-        return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();
-    }
-
-    /**
-     * Locate an existing instance of this Fragment or if not found, create and
-     * add it using FragmentManager.
-     *
-     * @param fm The FragmentManager manager to use.
-     * @return The existing instance of the Fragment or the new instance if just
-     *         created.
-     */
-    private static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {
-        // Check to see if we have retained the worker fragment.
-        RetainFragment mRetainFragment = (RetainFragment) fm.findFragmentByTag(TAG);
-
-        // If not retained (or first time running), we need to create and add it.
-        if (mRetainFragment == null) {
-            mRetainFragment = new RetainFragment();
-            fm.beginTransaction().add(mRetainFragment, TAG).commitAllowingStateLoss();
-        }
-
-        return mRetainFragment;
-    }
-
-    /**
-     * A simple non-UI Fragment that stores a single Object and is retained over configuration
-     * changes. It will be used to retain the ImageCache object.
-     */
-    public static class RetainFragment extends Fragment {
-        private Object mObject;
-
-        /**
-         * Empty constructor as per the Fragment documentation
-         */
-        public RetainFragment() {}
-
-        @Override
-        public void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-
-            // Make sure this Fragment is retained over a configuration change
-            setRetainInstance(true);
-        }
-
-        /**
-         * Store a single object in this Fragment.
-         *
-         * @param object The object to store
-         */
-        public void setObject(Object object) {
-            mObject = object;
-        }
-
-        /**
-         * Get the stored object.
-         *
-         * @return The stored object
-         */
-        public Object getObject() {
-            return mObject;
-        }
-    }
-
-}
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/ImageResizer.java b/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/ImageResizer.java
deleted file mode 100644
index 2a9d152..0000000
--- a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/ImageResizer.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.bitmapfun.util;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Build;
-import android.util.Log;
-
-import com.example.android.bitmapfun.BuildConfig;
-
-import java.io.FileDescriptor;
-
-/**
- * A simple subclass of {@link ImageWorker} that resizes images from resources given a target width
- * and height. Useful for when the input images might be too large to simply load directly into
- * memory.
- */
-public class ImageResizer extends ImageWorker {
-    private static final String TAG = "ImageResizer";
-    protected int mImageWidth;
-    protected int mImageHeight;
-
-    /**
-     * Initialize providing a single target image size (used for both width and height);
-     *
-     * @param context
-     * @param imageWidth
-     * @param imageHeight
-     */
-    public ImageResizer(Context context, int imageWidth, int imageHeight) {
-        super(context);
-        setImageSize(imageWidth, imageHeight);
-    }
-
-    /**
-     * Initialize providing a single target image size (used for both width and height);
-     *
-     * @param context
-     * @param imageSize
-     */
-    public ImageResizer(Context context, int imageSize) {
-        super(context);
-        setImageSize(imageSize);
-    }
-
-    /**
-     * Set the target image width and height.
-     *
-     * @param width
-     * @param height
-     */
-    public void setImageSize(int width, int height) {
-        mImageWidth = width;
-        mImageHeight = height;
-    }
-
-    /**
-     * Set the target image size (width and height will be the same).
-     *
-     * @param size
-     */
-    public void setImageSize(int size) {
-        setImageSize(size, size);
-    }
-
-    /**
-     * The main processing method. This happens in a background task. In this case we are just
-     * sampling down the bitmap and returning it from a resource.
-     *
-     * @param resId
-     * @return
-     */
-    private Bitmap processBitmap(int resId) {
-        if (BuildConfig.DEBUG) {
-            Log.d(TAG, "processBitmap - " + resId);
-        }
-        return decodeSampledBitmapFromResource(mResources, resId, mImageWidth,
-                mImageHeight, getImageCache());
-    }
-
-    @Override
-    protected Bitmap processBitmap(Object data) {
-        return processBitmap(Integer.parseInt(String.valueOf(data)));
-    }
-
-    /**
-     * Decode and sample down a bitmap from resources to the requested width and height.
-     *
-     * @param res The resources object containing the image data
-     * @param resId The resource id of the image data
-     * @param reqWidth The requested width of the resulting bitmap
-     * @param reqHeight The requested height of the resulting bitmap
-     * @param cache The ImageCache used to find candidate bitmaps for use with inBitmap
-     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
-     *         that are equal to or greater than the requested width and height
-     */
-    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
-            int reqWidth, int reqHeight, ImageCache cache) {
-
-        // First decode with inJustDecodeBounds=true to check dimensions
-        final BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inJustDecodeBounds = true;
-        BitmapFactory.decodeResource(res, resId, options);
-
-        // Calculate inSampleSize
-        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
-
-        // If we're running on Honeycomb or newer, try to use inBitmap
-        if (Utils.hasHoneycomb()) {
-            addInBitmapOptions(options, cache);
-        }
-
-        // Decode bitmap with inSampleSize set
-        options.inJustDecodeBounds = false;
-        return BitmapFactory.decodeResource(res, resId, options);
-    }
-
-    /**
-     * Decode and sample down a bitmap from a file to the requested width and height.
-     *
-     * @param filename The full path of the file to decode
-     * @param reqWidth The requested width of the resulting bitmap
-     * @param reqHeight The requested height of the resulting bitmap
-     * @param cache The ImageCache used to find candidate bitmaps for use with inBitmap
-     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
-     *         that are equal to or greater than the requested width and height
-     */
-    public static Bitmap decodeSampledBitmapFromFile(String filename,
-            int reqWidth, int reqHeight, ImageCache cache) {
-
-        // First decode with inJustDecodeBounds=true to check dimensions
-        final BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inJustDecodeBounds = true;
-        BitmapFactory.decodeFile(filename, options);
-
-        // Calculate inSampleSize
-        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
-
-        // If we're running on Honeycomb or newer, try to use inBitmap
-        if (Utils.hasHoneycomb()) {
-            addInBitmapOptions(options, cache);
-        }
-
-        // Decode bitmap with inSampleSize set
-        options.inJustDecodeBounds = false;
-        return BitmapFactory.decodeFile(filename, options);
-    }
-
-    /**
-     * Decode and sample down a bitmap from a file input stream to the requested width and height.
-     *
-     * @param fileDescriptor The file descriptor to read from
-     * @param reqWidth The requested width of the resulting bitmap
-     * @param reqHeight The requested height of the resulting bitmap
-     * @param cache The ImageCache used to find candidate bitmaps for use with inBitmap
-     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
-     *         that are equal to or greater than the requested width and height
-     */
-    public static Bitmap decodeSampledBitmapFromDescriptor(
-            FileDescriptor fileDescriptor, int reqWidth, int reqHeight, ImageCache cache) {
-
-        // First decode with inJustDecodeBounds=true to check dimensions
-        final BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inJustDecodeBounds = true;
-        BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
-
-        // Calculate inSampleSize
-        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
-
-        // Decode bitmap with inSampleSize set
-        options.inJustDecodeBounds = false;
-
-        // If we're running on Honeycomb or newer, try to use inBitmap
-        if (Utils.hasHoneycomb()) {
-            addInBitmapOptions(options, cache);
-        }
-
-        return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
-    }
-
-    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
-    private static void addInBitmapOptions(BitmapFactory.Options options, ImageCache cache) {
-        // inBitmap only works with mutable bitmaps so force the decoder to
-        // return mutable bitmaps.
-        options.inMutable = true;
-
-        if (cache != null) {
-            // Try and find a bitmap to use for inBitmap
-            Bitmap inBitmap = cache.getBitmapFromReusableSet(options);
-
-            if (inBitmap != null) {
-                if (BuildConfig.DEBUG) {
-                    Log.d(TAG, "Found bitmap to use for inBitmap");
-                }
-                options.inBitmap = inBitmap;
-            }
-        }
-    }
-
-    /**
-     * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
-     * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
-     * the closest inSampleSize that will result in the final decoded bitmap having a width and
-     * height equal to or larger than the requested width and height. This implementation does not
-     * ensure a power of 2 is returned for inSampleSize which can be faster when decoding but
-     * results in a larger bitmap which isn't as useful for caching purposes.
-     *
-     * @param options An options object with out* params already populated (run through a decode*
-     *            method with inJustDecodeBounds==true
-     * @param reqWidth The requested width of the resulting bitmap
-     * @param reqHeight The requested height of the resulting bitmap
-     * @return The value to be used for inSampleSize
-     */
-    public static int calculateInSampleSize(BitmapFactory.Options options,
-            int reqWidth, int reqHeight) {
-        // Raw height and width of image
-        final int height = options.outHeight;
-        final int width = options.outWidth;
-        int inSampleSize = 1;
-
-        if (height > reqHeight || width > reqWidth) {
-
-            // Calculate ratios of height and width to requested height and width
-            final int heightRatio = Math.round((float) height / (float) reqHeight);
-            final int widthRatio = Math.round((float) width / (float) reqWidth);
-
-            // Choose the smallest ratio as inSampleSize value, this will guarantee a final image
-            // with both dimensions larger than or equal to the requested height and width.
-            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
-
-            // This offers some additional logic in case the image has a strange
-            // aspect ratio. For example, a panorama may have a much larger
-            // width than height. In these cases the total pixels might still
-            // end up being too large to fit comfortably in memory, so we should
-            // be more aggressive with sample down the image (=larger inSampleSize).
-
-            final float totalPixels = width * height;
-
-            // Anything more than 2x the requested pixels we'll sample down further
-            final float totalReqPixelsCap = reqWidth * reqHeight * 2;
-
-            while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
-                inSampleSize++;
-            }
-        }
-        return inSampleSize;
-    }
-}
diff --git a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/Utils.java b/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/Utils.java
deleted file mode 100644
index 52a99f9..0000000
--- a/samples/training/bitmapfun/src/com/example/android/bitmapfun/util/Utils.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.bitmapfun.util;
-
-import com.example.android.bitmapfun.ui.ImageDetailActivity;
-import com.example.android.bitmapfun.ui.ImageGridActivity;
-
-import android.annotation.TargetApi;
-import android.os.Build;
-import android.os.StrictMode;
-
-/**
- * Class containing some static utility methods.
- */
-public class Utils {
-    private Utils() {};
-
-    @TargetApi(11)
-    public static void enableStrictMode() {
-        if (Utils.hasGingerbread()) {
-            StrictMode.ThreadPolicy.Builder threadPolicyBuilder =
-                    new StrictMode.ThreadPolicy.Builder()
-                            .detectAll()
-                            .penaltyLog();
-            StrictMode.VmPolicy.Builder vmPolicyBuilder =
-                    new StrictMode.VmPolicy.Builder()
-                            .detectAll()
-                            .penaltyLog();
-
-            if (Utils.hasHoneycomb()) {
-                threadPolicyBuilder.penaltyFlashScreen();
-                vmPolicyBuilder
-                        .setClassInstanceLimit(ImageGridActivity.class, 1)
-                        .setClassInstanceLimit(ImageDetailActivity.class, 1);
-            }
-            StrictMode.setThreadPolicy(threadPolicyBuilder.build());
-            StrictMode.setVmPolicy(vmPolicyBuilder.build());
-        }
-    }
-
-    public static boolean hasFroyo() {
-        // Can use static final constants like FROYO, declared in later versions
-        // of the OS since they are inlined at compile time. This is guaranteed behavior.
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
-    }
-
-    public static boolean hasGingerbread() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
-    }
-
-    public static boolean hasHoneycomb() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
-    }
-
-    public static boolean hasHoneycombMR1() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1;
-    }
-
-    public static boolean hasJellyBean() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
-    }
-}
diff --git a/samples/training/testingfun/app/AndroidManifest.xml b/samples/training/testingfun/app/AndroidManifest.xml
new file mode 100644
index 0000000..a71247a
--- /dev/null
+++ b/samples/training/testingfun/app/AndroidManifest.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.testingfun"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="17" />
+    <application
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme"
+        android:allowBackup="false">
+
+        <activity
+            android:name=".lesson2.MyFirstTestActivity"
+            android:label="@string/my_first_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".lesson3.ClickFunActivity"
+            android:label="@string/click_fun">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".lesson4.LaunchActivity"
+            android:label="@string/launch_next">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".lesson4.NextActivity"
+            android:label="@string/next_activity" />
+        <activity
+            android:name=".lesson5.SenderActivity"
+            android:label="@string/sender_activity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".lesson5.ReceiverActivity"
+            android:label="@string/receiver_activity" />
+    </application>
+</manifest>
diff --git a/samples/training/testingfun/app/build.gradle b/samples/training/testingfun/app/build.gradle
new file mode 100644
index 0000000..c68484f
--- /dev/null
+++ b/samples/training/testingfun/app/build.gradle
@@ -0,0 +1,27 @@
+apply plugin: 'android'
+
+android {
+    compileSdkVersion 17
+    buildToolsVersion "17.0.0"
+
+    defaultConfig {
+        minSdkVersion 8
+    }
+
+    android {
+        sourceSets {
+            main {
+                manifest.srcFile 'AndroidManifest.xml'
+                java.srcDirs = ['src']
+                resources.srcDirs = ['src']
+                aild.srcDirs = ['src']
+                renderscript.srcDirs = ['src']
+                res.srcDirs = ['res']
+                assets.srcDirs = ['assets']
+            }
+
+            instrumentTest.setRoot('tests')
+            instrumentTest.java.srcDirs = ['tests/src']
+        }
+    }
+}
\ No newline at end of file
diff --git a/samples/training/bitmapfun/project.properties b/samples/training/testingfun/app/project.properties
similarity index 100%
rename from samples/training/bitmapfun/project.properties
rename to samples/training/testingfun/app/project.properties
diff --git a/samples/training/testingfun/app/res/drawable-hdpi/ic_launcher.png b/samples/training/testingfun/app/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..136343e
--- /dev/null
+++ b/samples/training/testingfun/app/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/testingfun/app/res/drawable-mdpi/ic_launcher.png b/samples/training/testingfun/app/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..6837266
--- /dev/null
+++ b/samples/training/testingfun/app/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/testingfun/app/res/drawable-xhdpi/ic_launcher.png b/samples/training/testingfun/app/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e88e975
--- /dev/null
+++ b/samples/training/testingfun/app/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/testingfun/app/res/drawable-xxhdpi/ic_launcher.png b/samples/training/testingfun/app/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..ac31a90
--- /dev/null
+++ b/samples/training/testingfun/app/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/testingfun/app/res/layout/activity_click_fun.xml b/samples/training/testingfun/app/res/layout/activity_click_fun.xml
new file mode 100644
index 0000000..c960c3b
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_click_fun.xml
@@ -0,0 +1,32 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <Button
+        android:id="@+id/launch_next_activity_button"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/label_click_me" />
+
+    <TextView
+        android:id="@+id/info_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:visibility="gone" />
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/res/layout/activity_launch_next.xml b/samples/training/testingfun/app/res/layout/activity_launch_next.xml
new file mode 100644
index 0000000..cfd0114
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_launch_next.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <Button
+        android:id="@+id/launch_next_activity_button"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/label_launch_next" />
+</merge>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/res/layout/activity_my_first_test.xml b/samples/training/testingfun/app/res/layout/activity_my_first_test.xml
new file mode 100644
index 0000000..3499bc7
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_my_first_test.xml
@@ -0,0 +1,27 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/my_first_test_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/my_first_test" />
+</LinearLayout>
+
diff --git a/samples/training/testingfun/app/res/layout/activity_next.xml b/samples/training/testingfun/app/res/layout/activity_next.xml
new file mode 100644
index 0000000..92f30f7
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_next.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/next_activity_info_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+</merge>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/res/layout/activity_receiver.xml b/samples/training/testingfun/app/res/layout/activity_receiver.xml
new file mode 100644
index 0000000..e93d16b
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_receiver.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/received_message_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+</merge>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/res/layout/activity_sender.xml b/samples/training/testingfun/app/res/layout/activity_sender.xml
new file mode 100644
index 0000000..e18f4c4
--- /dev/null
+++ b/samples/training/testingfun/app/res/layout/activity_sender.xml
@@ -0,0 +1,33 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <EditText
+        android:id="@+id/message_input_edit_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/message_input_hint_edit_text" />
+
+    <Button
+        android:id="@+id/send_message_button"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/label_send_message" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/training/testingfun/app/res/values-sw720dp-land/dimens.xml b/samples/training/testingfun/app/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..3201e93
--- /dev/null
+++ b/samples/training/testingfun/app/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,18 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+</resources>
diff --git a/samples/training/testingfun/app/res/values-v11/styles.xml b/samples/training/testingfun/app/res/values-v11/styles.xml
new file mode 100644
index 0000000..90ff160
--- /dev/null
+++ b/samples/training/testingfun/app/res/values-v11/styles.xml
@@ -0,0 +1,18 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar" />
+</resources>
diff --git a/samples/training/testingfun/app/res/values-v14/styles.xml b/samples/training/testingfun/app/res/values-v14/styles.xml
new file mode 100644
index 0000000..90ff160
--- /dev/null
+++ b/samples/training/testingfun/app/res/values-v14/styles.xml
@@ -0,0 +1,18 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar" />
+</resources>
diff --git a/samples/training/testingfun/app/res/values/dimens.xml b/samples/training/testingfun/app/res/values/dimens.xml
new file mode 100644
index 0000000..e96acda
--- /dev/null
+++ b/samples/training/testingfun/app/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/samples/training/testingfun/app/res/values/strings.xml b/samples/training/testingfun/app/res/values/strings.xml
new file mode 100644
index 0000000..1fc3bc0
--- /dev/null
+++ b/samples/training/testingfun/app/res/values/strings.xml
@@ -0,0 +1,34 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+    <string name="app_name">Android Testing Fun</string>
+
+    <string name="my_first_test">My First Test</string>
+
+    <string name="click_fun">Click Fun Test</string>
+    <string name="label_click_me">Click me</string>
+
+    <string name="launch_next">Launch Activity</string>
+    <string name="next_activity">Next Activity</string>
+
+    <string name="sender_activity">Sender Activity</string>
+    <string name="receiver_activity">Receiver Activity</string>
+
+    <string name="info_text">Button clicked!</string>
+    <string name="label_launch_next">Launch Next</string>
+    <string name="label_send_message">Send</string>
+    <string name="message_input_hint_edit_text">Enter a message</string>
+</resources>
diff --git a/samples/training/testingfun/app/res/values/styles.xml b/samples/training/testingfun/app/res/values/styles.xml
new file mode 100644
index 0000000..fa3d1bd
--- /dev/null
+++ b/samples/training/testingfun/app/res/values/styles.xml
@@ -0,0 +1,20 @@
+<!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+    <style name="AppBaseTheme" parent="android:Theme.Light" />
+
+    <style name="AppTheme" parent="AppBaseTheme" />
+</resources>
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson2/MyFirstTestActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson2/MyFirstTestActivity.java
new file mode 100644
index 0000000..db977cf
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson2/MyFirstTestActivity.java
@@ -0,0 +1,36 @@
+/*
+ * 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.testingfun.lesson2;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Activity with a TextView that contains a String label.
+ */
+public class MyFirstTestActivity extends Activity {
+
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_my_first_test);
+    }
+}
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson3/ClickFunActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson3/ClickFunActivity.java
new file mode 100644
index 0000000..09db694
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson3/ClickFunActivity.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.testingfun.lesson3;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Activity which shows a "click me" button. When the button is clicked, a TextView is shown below
+ * the button.
+ */
+public class ClickFunActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_click_fun);
+
+        final TextView infoTextView = (TextView) findViewById(R.id.info_text_view);
+        final Button clickMeButton = (Button) findViewById(R.id.launch_next_activity_button);
+        clickMeButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                infoTextView.setVisibility(View.VISIBLE);
+                infoTextView.setText(getString(R.string.info_text));
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/LaunchActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/LaunchActivity.java
new file mode 100644
index 0000000..8f1fb9b
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/LaunchActivity.java
@@ -0,0 +1,48 @@
+/*
+ * 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.testingfun.lesson4;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+/**
+ * Launches NextActivity and passes a payload in the Bundle.
+ */
+public class LaunchActivity extends Activity {
+
+    /**
+     * The payload that is passed as Intent data to NextActivity.
+     */
+    public final static String STRING_PAYLOAD = "Started from LaunchActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_launch_next);
+        Button launchNextButton = (Button) findViewById(R.id.launch_next_activity_button);
+        launchNextButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                startActivity(NextActivity.makeIntent(LaunchActivity.this, STRING_PAYLOAD));
+                finish();
+            }
+        });
+    }
+}
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/NextActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/NextActivity.java
new file mode 100644
index 0000000..68965c2
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson4/NextActivity.java
@@ -0,0 +1,61 @@
+/*
+ * 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.testingfun.lesson4;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * This activity is started from LaunchActivity. It reads the payload from the given bundle and
+ * displays it using a TextView.
+ */
+public class NextActivity extends Activity {
+
+    /**
+     * Extras key for the payload.
+     */
+    public final static String EXTRAS_PAYLOAD_KEY
+            = "com.example.android.testingfun.lesson4.EXTRAS_PAYLOAD_KEY";
+
+    /**
+     * Factory method to create a launch Intent for this activity.
+     *
+     * @param context the context that intent should be bound to
+     * @param payload the payload data that should be added for this intent
+     * @return a configured intent to launch this activity with a String payload.
+     */
+    public static Intent makeIntent(Context context, String payload) {
+        return new Intent(context, NextActivity.class).putExtra(EXTRAS_PAYLOAD_KEY, payload);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_next);
+
+        final String stringPayload = getIntent().getStringExtra(EXTRAS_PAYLOAD_KEY);
+
+        if (stringPayload != null) {
+            ((TextView) findViewById(R.id.next_activity_info_text_view)).setText(stringPayload);
+        }
+
+    }
+}
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/ReceiverActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/ReceiverActivity.java
new file mode 100644
index 0000000..2bc401d
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/ReceiverActivity.java
@@ -0,0 +1,61 @@
+/*
+ * 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.testingfun.lesson5;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.widget.TextView;
+
+/**
+ * Receives a message from SenderActivity and displays the message.
+ */
+public class ReceiverActivity extends Activity {
+
+    /**
+     * The extra key that is used to identify the message in the Intents data bundle
+     */
+    private static final String EXTRA_SENDER_MESSAGE_TEXT
+            = "com.example.android.testingfun.lesson5.extra.sender.message.text";
+
+    /**
+     * Factory method to create an launch intent for this activity.
+     *
+     * @param context the context to this intent should be bound to
+     * @param message the message data that should be added to this intent
+     * @return a configured intent to launch this activity with a given message
+     */
+    public static Intent makeIntent(Context context, CharSequence message) {
+        return new Intent(context, ReceiverActivity.class)
+                .putExtra(EXTRA_SENDER_MESSAGE_TEXT, message);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_receiver);
+        final CharSequence senderMessage = getIntent()
+                .getCharSequenceExtra(EXTRA_SENDER_MESSAGE_TEXT);
+        final TextView receiverTextView = (TextView) findViewById(R.id.received_message_text_view);
+        if (!TextUtils.isEmpty(senderMessage)) {
+            receiverTextView.setText(senderMessage);
+        }
+    }
+}
diff --git a/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/SenderActivity.java b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/SenderActivity.java
new file mode 100644
index 0000000..495f1e6
--- /dev/null
+++ b/samples/training/testingfun/app/src/com/example/android/testingfun/lesson5/SenderActivity.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.testingfun.lesson5;
+
+import com.example.android.testingfun.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+
+/**
+ * Sends a user generated message to the ReceiverActivity
+ */
+public class SenderActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_sender);
+        final Button sendMessageButton = (Button) findViewById(R.id.send_message_button);
+        final EditText messageInputEditText = (EditText) findViewById(R.id.message_input_edit_text);
+        sendMessageButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (messageInputEditText != null) {
+                    final CharSequence message = messageInputEditText.getText();
+                    startActivity(ReceiverActivity.makeIntent(SenderActivity.this, message));
+                }
+            }
+        });
+    }
+}
diff --git a/samples/training/testingfun/app/tests/AndroidManifest.xml b/samples/training/testingfun/app/tests/AndroidManifest.xml
new file mode 100644
index 0000000..13ce6ab
--- /dev/null
+++ b/samples/training/testingfun/app/tests/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright (C) 2013 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.testingfun.tests"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="17" />
+
+    <!-- We add an application tag here just so that we can indicate that
+         this package needs to link against the android.test library,
+         which is needed when building test cases. -->
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!--
+    Specifies the instrumentation test runner used to run the tests.
+    -->
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.example.android.testingfun"
+        android:label="Tests for com.example.android.testingfun" />
+</manifest>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/project.properties b/samples/training/testingfun/app/tests/project.properties
similarity index 100%
copy from samples/training/bitmapfun/project.properties
copy to samples/training/testingfun/app/tests/project.properties
diff --git a/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson2/MyFirstTestActivityTest.java b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson2/MyFirstTestActivityTest.java
new file mode 100644
index 0000000..ad18b55
--- /dev/null
+++ b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson2/MyFirstTestActivityTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.testingfun.tests.lesson2;
+
+import com.example.android.testingfun.R;
+import com.example.android.testingfun.lesson2.MyFirstTestActivity;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.widget.TextView;
+
+/**
+ * Tests for MyFirstTestActivity.
+ */
+public class MyFirstTestActivityTest extends ActivityInstrumentationTestCase2<MyFirstTestActivity> {
+
+    private MyFirstTestActivity mFirstTestActivity;
+    private TextView mFirstTestText;
+
+    public MyFirstTestActivityTest() {
+        super(MyFirstTestActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Starts the activity under test using the default Intent with:
+        // action = {@link Intent#ACTION_MAIN}
+        // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+        // All other fields are null or empty.
+        mFirstTestActivity = getActivity();
+        mFirstTestText = (TextView) mFirstTestActivity.findViewById(R.id.my_first_test_text_view);
+    }
+
+    /**
+     * Test if your test fixture has been set up correctly. You should always implement a test that
+     * checks the correct setup of your test fixture. If this tests fails all other tests are
+     * likely to fail as well.
+     */
+    public void testPreconditions() {
+        //Try to add a message to add context to your assertions. These messages will be shown if
+        //a tests fails and make it easy to understand why a test failed
+        assertNotNull("mFirstTestActivity is null", mFirstTestActivity);
+        assertNotNull("mFirstTestText is null", mFirstTestText);
+    }
+
+    /**
+     * Tests the correctness of the initial text.
+     */
+    public void testMyFirstTestTextView_labelText() {
+        //It is good practice to read the string from your resources in order to not break
+        //multiple tests when a string changes.
+        final String expected = mFirstTestActivity.getString(R.string.my_first_test);
+        final String actual = mFirstTestText.getText().toString();
+        assertEquals("mFirstTestText contains wrong text", expected, actual);
+    }
+}
\ No newline at end of file
diff --git a/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson3/ClickFunActivityTest.java b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson3/ClickFunActivityTest.java
new file mode 100644
index 0000000..5d3d387
--- /dev/null
+++ b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson3/ClickFunActivityTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.testingfun.tests.lesson3;
+
+
+import com.example.android.testingfun.R;
+import com.example.android.testingfun.lesson3.ClickFunActivity;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.test.ViewAsserts;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * Tests for ClickFunActivity. Introduces touch mode, test size annotations and TouchUtils.
+ */
+public class ClickFunActivityTest extends ActivityInstrumentationTestCase2<ClickFunActivity> {
+    
+    private ClickFunActivity mClickFunActivity;
+    private Button mClickMeButton;
+    private TextView mInfoTextView;
+
+    public ClickFunActivityTest() {
+        super(ClickFunActivity.class);
+    }
+
+    /**
+     * Sets up the test fixture for this test case. This method is always called before every test
+     * run.
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        //Sets the initial touch mode for the Activity under test. This must be called before
+        //getActivity()
+        setActivityInitialTouchMode(true);
+
+        //Get a reference to the Activity under test, starting it if necessary.
+        mClickFunActivity = getActivity();
+
+        //Get references to all views
+        mClickMeButton = (Button) mClickFunActivity.findViewById(R.id.launch_next_activity_button);
+        mInfoTextView = (TextView) mClickFunActivity.findViewById(R.id.info_text_view);
+    }
+
+    /**
+     * Tests the preconditions of this test fixture.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull("mClickFunActivity is null", mClickFunActivity);
+        assertNotNull("mClickMeButton is null", mClickMeButton);
+        assertNotNull("mInfoTextView is null", mInfoTextView);
+    }
+
+    @MediumTest
+    public void testClickMeButton_layout() {
+        //Retrieve the top-level window decor view
+        final View decorView = mClickFunActivity.getWindow().getDecorView();
+
+        //Verify that the mClickMeButton is on screen
+        ViewAsserts.assertOnScreen(decorView, mClickMeButton);
+
+        //Verify width and heights
+        final ViewGroup.LayoutParams layoutParams = mClickMeButton.getLayoutParams();
+        assertNotNull(layoutParams);
+        assertEquals(layoutParams.width, WindowManager.LayoutParams.MATCH_PARENT);
+        assertEquals(layoutParams.height, WindowManager.LayoutParams.WRAP_CONTENT);
+    }
+
+    @MediumTest
+    public void testClickMeButton_labelText() {
+        //Verify that mClickMeButton uses the correct string resource
+        final String expectedNextButtonText = mClickFunActivity.getString(R.string.label_click_me);
+        final String actualNextButtonText = mClickMeButton.getText().toString();
+        assertEquals(expectedNextButtonText, actualNextButtonText);
+    }
+
+    @MediumTest
+    public void testInfoTextView_layout() {
+        //Retrieve the top-level window decor view
+        final View decorView = mClickFunActivity.getWindow().getDecorView();
+
+        //Verify that the mInfoTextView is on screen and is not visible
+        ViewAsserts.assertOnScreen(decorView, mInfoTextView);
+        assertTrue(View.GONE == mInfoTextView.getVisibility());
+    }
+
+    @MediumTest
+    public void testInfoTextViewText_isEmpty() {
+        //Verify that the mInfoTextView is initialized with the correct default value
+        assertEquals("", mInfoTextView.getText());
+    }
+
+    @MediumTest
+    public void testClickMeButton_clickButtonAndExpectInfoText() {
+        String expectedInfoText = mClickFunActivity.getString(R.string.info_text);
+        //Perform a click on mClickMeButton
+        TouchUtils.clickView(this, mClickMeButton);
+        //Verify the that mClickMeButton was clicked. mInfoTextView is visible and contains
+        //the correct text.
+        assertTrue(View.VISIBLE == mInfoTextView.getVisibility());
+        assertEquals(expectedInfoText, mInfoTextView.getText());
+    }
+}
diff --git a/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson4/LaunchActivityTest.java b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson4/LaunchActivityTest.java
new file mode 100644
index 0000000..7d472c3
--- /dev/null
+++ b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson4/LaunchActivityTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.testingfun.tests.lesson4;
+
+import com.example.android.testingfun.R;
+import com.example.android.testingfun.lesson4.LaunchActivity;
+import com.example.android.testingfun.lesson4.NextActivity;
+
+import android.content.Intent;
+import android.test.ActivityUnitTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+
+/**
+ * Tests LaunchActivity in isolation from the system.
+ */
+public class LaunchActivityTest extends ActivityUnitTestCase<LaunchActivity> {
+
+    private Intent mLaunchIntent;
+
+    public LaunchActivityTest() {
+        super(LaunchActivity.class);
+    }
+
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        //Create an intent to launch target Activity
+        mLaunchIntent = new Intent(getInstrumentation().getTargetContext(),
+                LaunchActivity.class);
+    }
+
+    /**
+     * Tests the preconditions of this test fixture.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        //Start the activity under test in isolation, without values for savedInstanceState and
+        //lastNonConfigurationInstance
+        startActivity(mLaunchIntent, null, null);
+        final Button launchNextButton = (Button) getActivity().findViewById(R.id.launch_next_activity_button);
+
+        assertNotNull("mLaunchActivity is null", getActivity());
+        assertNotNull("mLaunchNextButton is null", launchNextButton);
+    }
+
+
+    @MediumTest
+    public void testLaunchNextActivityButton_labelText() {
+        startActivity(mLaunchIntent, null, null);
+        final Button launchNextButton = (Button) getActivity().findViewById(R.id.launch_next_activity_button);
+
+        final String expectedButtonText = getActivity().getString(R.string.label_launch_next);
+        assertEquals("Unexpected button label text", expectedButtonText,
+                launchNextButton.getText());
+    }
+
+    @MediumTest
+    public void testNextActivityWasLaunchedWithIntent() {
+        startActivity(mLaunchIntent, null, null);
+        final Button launchNextButton = (Button) getActivity().findViewById(R.id.launch_next_activity_button);
+        //Because this is an isolated ActivityUnitTestCase we have to directly click the
+        //button from code
+        launchNextButton.performClick();
+
+        // Get the intent for the next started activity
+        final Intent launchIntent = getStartedActivityIntent();
+        //Verify the intent was not null.
+        assertNotNull("Intent was null", launchIntent);
+        //Verify that LaunchActivity was finished after button click
+        assertTrue(isFinishCalled());
+
+
+        final String payload = launchIntent.getStringExtra(NextActivity.EXTRAS_PAYLOAD_KEY);
+        //Verify that payload data was added to the intent
+        assertEquals("Payload is empty", LaunchActivity.STRING_PAYLOAD
+                , payload);
+    }
+}
\ No newline at end of file
diff --git a/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson5/SenderActivityTest.java b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson5/SenderActivityTest.java
new file mode 100644
index 0000000..75bc302
--- /dev/null
+++ b/samples/training/testingfun/app/tests/src/com/example/android/testingfun/tests/lesson5/SenderActivityTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.testingfun.tests.lesson5;
+
+import com.example.android.testingfun.R;
+import com.example.android.testingfun.lesson5.ReceiverActivity;
+import com.example.android.testingfun.lesson5.SenderActivity;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+/**
+ * Functional test across multiple Activities. Tests SenderActivity and ReceiverActivity. Introduces
+ * advanced Instrumentation testing practices as sending key events and interaction monitoring
+ * between Activities and the system.
+ */
+public class SenderActivityTest extends ActivityInstrumentationTestCase2<SenderActivity> {
+
+    private static final int TIMEOUT_IN_MS = 5000;
+    private static final String TEST_MESSAGE = "Hello Receiver";
+    private SenderActivity mSenderActivity;
+
+    public SenderActivityTest() {
+        super(SenderActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setActivityInitialTouchMode(true);
+        mSenderActivity = getActivity();
+    }
+
+    /**
+     * Tests the preconditions of this test fixture.
+     */
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull("mSenderActivity is null", mSenderActivity);
+    }
+
+    @MediumTest
+    public void testSendMessageToReceiverActivity() {
+
+        //Because this functional test tests interaction across multiple components these views
+        //are part of the actual test method and not of the test fixture
+        final Button sendToReceiverButton = (Button) mSenderActivity
+                .findViewById(R.id.send_message_button);
+        final EditText senderMessageEditText = (EditText) mSenderActivity
+                .findViewById(R.id.message_input_edit_text);
+
+        //Create and add an ActivityMonitor to monitor interaction between the system and the
+        //ReceiverActivity
+        Instrumentation.ActivityMonitor receiverActivityMonitor = getInstrumentation()
+                .addMonitor(ReceiverActivity.class.getName(), null, false);
+
+        //Request focus on the EditText field. This must be done on the UiThread because
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                senderMessageEditText.requestFocus();
+            }
+        });
+        //Wait until all events from the MainHandler's queue are processed
+        getInstrumentation().waitForIdleSync();
+
+        //Send the text message
+        getInstrumentation().sendStringSync(TEST_MESSAGE);
+        getInstrumentation().waitForIdleSync();
+
+        //Click on the sendToReceiverButton to send the message to ReceiverActivity
+        TouchUtils.clickView(this, sendToReceiverButton);
+
+        //Wait until ReceiverActivity was launched and get a reference to it.
+        ReceiverActivity receiverActivity = (ReceiverActivity) receiverActivityMonitor
+                .waitForActivityWithTimeout(TIMEOUT_IN_MS);
+        //Verify that ReceiverActivity was started
+        assertNotNull("ReceiverActivity is null", receiverActivity);
+        assertEquals("Monitor for ReceiverActivity has not been called", 1,
+                receiverActivityMonitor.getHits());
+        assertEquals("Activity is of wrong type", ReceiverActivity.class,
+                receiverActivity.getClass());
+
+        //Read the message received by ReceiverActivity
+        final TextView receivedMessage = (TextView) receiverActivity
+                .findViewById(R.id.received_message_text_view);
+        //Verify that received message is correct
+        assertNotNull(receivedMessage);
+        assertEquals("Wrong received message", TEST_MESSAGE, receivedMessage.getText().toString());
+
+        //Unregister monitor for ReceiverActivity
+        getInstrumentation().removeMonitor(receiverActivityMonitor);
+    }
+}
\ No newline at end of file
diff --git a/samples/training/testingfun/build.gradle b/samples/training/testingfun/build.gradle
new file mode 100644
index 0000000..06b6030
--- /dev/null
+++ b/samples/training/testingfun/build.gradle
@@ -0,0 +1,8 @@
+buildscript {
+    repositories {
+        mavenCentral()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:0.4.2'
+    }
+}
diff --git a/samples/training/testingfun/gradle/wrapper/gradle-wrapper.jar b/samples/training/testingfun/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/samples/training/testingfun/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/samples/training/testingfun/gradle/wrapper/gradle-wrapper.properties b/samples/training/testingfun/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..5c22dec
--- /dev/null
+++ b/samples/training/testingfun/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip
diff --git a/samples/training/testingfun/gradlew b/samples/training/testingfun/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/samples/training/testingfun/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/samples/training/testingfun/gradlew.bat b/samples/training/testingfun/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/samples/training/testingfun/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windowz variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+if "%@eval[2+2]" == "4" goto 4NT_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+goto execute

+

+:4NT_args

+@rem Get arguments from the 4NT Shell from JP Software

+set CMD_LINE_ARGS=%$

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/samples/training/testingfun/settings.gradle b/samples/training/testingfun/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/samples/training/testingfun/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/scripts/app_engine_server/redirects.yaml b/scripts/app_engine_server/redirects.yaml
index 4f83713..d15017a 100644
--- a/scripts/app_engine_server/redirects.yaml
+++ b/scripts/app_engine_server/redirects.yaml
@@ -634,6 +634,10 @@
   dst: /about/versions/android-4.0.html
   type: permanent
 
+- src: /(k|kk|kitkat)/?$
+  dst: /about/versions/kitkat.html
+  type: permanent
+
 - src: /(j|jb|jellybean)/?$
   dst: /about/versions/jelly-bean.html
   type: permanent
diff --git a/scripts/compare-installed-size.py b/scripts/compare-installed-size.py
new file mode 100755
index 0000000..488723d
--- /dev/null
+++ b/scripts/compare-installed-size.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+
+# 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.
+
+"""summarize and compare the component sizes in installed-files.txt."""
+
+import sys
+
+bin_size1 = {}
+bin_size2 = {}
+bin_sizes = [bin_size1, bin_size2]
+
+file_sizes = {}
+
+def PrintUsage():
+  print "usage: " + sys.argv[0] + " filename [filename2]"
+  print ""
+  print "  Input file is installed-files.txt from the build output directory."
+  print "  When only one input file is given, it will generate module_0.csv."
+  print "  When two input files are given, in addition it will generate"
+  print "  module_1.csv and comparison.csv."
+  print ""
+  print "  The module_x.csv file shows the aggregated file size in each module"
+  print "  (eg bin, lib, app, ...)"
+  print "  The comparison.cvs file shows the individual file sizes side by side"
+  print "  from two different builds"
+  print ""
+  print "  These files can be uploaded to Google Doc for further processing."
+  sys.exit(1)
+
+def ParseFile(install_file, idx):
+  input_stream = open(install_file, 'r')
+  for line in input_stream:
+    # line = "25027208  /system/lib/libchromeview.so"
+    line = line.strip()
+
+    # size = "25027208", name = "/system/lib/libchromeview.so"
+    size, name = line.split()
+
+    # components = ["", "system", "lib", "libchromeview.so"]
+    components = name.split('/')
+
+    # module = "lib"
+    module = components[2]
+
+    # filename = libchromeview.so"
+    filename = components[-1]
+
+    # sum up the file sizes by module name
+    if module not in bin_sizes[idx]:
+      bin_sizes[idx][module] = int(size)
+    else:
+      bin_sizes[idx][module] += int(size)
+
+    # sometimes a file only exists on one build but not the other - use 0 as the
+    # default size.
+    if idx == 0:
+      file_sizes[name] = [module, size, 0]
+    else:
+      if name in file_sizes:
+        file_sizes[name][-1] = size
+      else:
+        file_sizes[name] = [module, 0, size]
+
+  input_stream.close()
+
+  # output the module csv file
+  output = open("module_%d.csv" % idx, 'w')
+  total = 0
+  for key in bin_sizes[idx]:
+    output.write("%s, %d\n" % (key, bin_sizes[idx][key]))
+  output.close()
+
+def main():
+  if len(sys.argv) < 2 or len(sys.argv) > 3:
+    PrintUsage()
+  # Parse the first installed-files.txt
+  ParseFile(sys.argv[1], 0)
+
+  # Parse the second installed-files.txt
+  if len(sys.argv) == 3:
+    ParseFile(sys.argv[2], 1)
+    # comparison.csv has the following columns:
+    # filename, module, size1, size2, size2-size1
+    # eg: /system/lib/libchromeview.so, lib, 25027208, 33278460, 8251252
+    output = open("comparison.csv", 'w')
+    for key in file_sizes:
+      output.write("%s, %s, %s, %s, %d\n" %
+                   (key, file_sizes[key][0], file_sizes[key][1],
+                    file_sizes[key][2],
+                    int(file_sizes[key][2]) - int(file_sizes[key][1])))
+    output.close()
+
+if __name__ == '__main__':
+  main()
+
+# vi: ts=2 sw=2
diff --git a/scripts/gdb/dalvik.gdb b/scripts/gdb/dalvik.gdb
new file mode 100644
index 0000000..cab0951
--- /dev/null
+++ b/scripts/gdb/dalvik.gdb
@@ -0,0 +1,51 @@
+#  dump dalvik backtrace
+define dbt
+    if $argc == 1
+        set $FP = $arg0
+    else
+        set $FP = $r5
+    end
+
+    set $frame = 0
+    set $savedPC = 0
+    while $FP
+        set $stackSave = $FP - sizeof(StackSaveArea)
+        set $savedPC = ((StackSaveArea *)$stackSave)->savedPc
+        set $method = ((StackSaveArea *)$stackSave)->method
+        printf "#%d\n", $frame
+        printf "    FP = %#x\n", $FP
+        printf "    stack save = %#x\n", $stackSave
+        printf "    Curr pc = %#x\n", ((StackSaveArea *) $stackSave)->xtra.currentPc
+        printf "    FP prev = %#x\n", ((StackSaveArea *) $stackSave)->prevFrame
+        if $method != 0
+            printf "    returnAddr: 0x%x\n", \
+                   ((StackSaveArea *)$stackSave)->returnAddr
+            printf "    class = %s\n", ((Method *) $method)->clazz->descriptor
+            printf "    method = %s (%#08x)\n", ((Method *) $method)->name, $method
+            printf "    signature = %s\n", ((Method *) $method)->shorty
+            printf "    bytecode offset = 0x%x\n", (short *) (((StackSaveArea *) $stackSave)->xtra.currentPc) - (short *) (((Method *) $method)->insns)
+            set $regSize = ((Method *) $method)->registersSize
+            set $insSize = ((Method *) $method)->insSize
+            set $index = 0
+            while $index < $regSize
+                printf "    v%d = %d", $index, ((int *)$FP)[$index]
+                if $regSize - $index <= $insSize
+                    printf " (in%d)\n", $insSize - $regSize + $index
+                else
+                    printf " (local%d)\n", $index
+                end
+                set $index = $index + 1
+            end
+        else
+            printf "    break frame\n"
+        end
+        set $FP = (int) ((StackSaveArea *)$stackSave)->prevFrame
+        set $frame = $frame + 1
+    end
+end
+
+document dbt
+    Unwind Dalvik stack frames. Argument 0 is the frame address of the top
+    frame. If omitted r5 will be used as the default (as the case in the
+    interpreter and JIT'ed code).
+end
diff --git a/scripts/stack b/scripts/stack
index 6750752..6bb8d0a 100755
--- a/scripts/stack
+++ b/scripts/stack
@@ -1,18 +1,25 @@
 #!/usr/bin/env python
 #
-# Copyright 2006 Google Inc. All Rights Reserved.
+# 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.
 
 """stack symbolizes native crash dumps."""
 
 import getopt
-import getpass
-import glob
-import os
-import re
-import subprocess
 import sys
-import urllib
 
+import stack_core
 import symbol
 
 
@@ -22,17 +29,8 @@
   print
   print "  usage: " + sys.argv[0] + " [options] [FILE]"
   print
-  print "  --symbols-dir=path"
-  print "       the path to a symbols dir, such as =/tmp/out/target/product/dream/symbols"
-  print
-  print "  --symbols-zip=path"
-  print "       the path to a symbols zip file, such as =dream-symbols-12345.zip"
-  print
-  print "  --auto"
-  print "       attempt to:"
-  print "         1) automatically find the build number in the crash"
-  print "         2) if it's an official build, download the symbols "
-  print "            from the build server, and use them"
+  print "  --arch=arm|x86"
+  print "       the target architecture"
   print
   print "  FILE should contain a stack trace in it somewhere"
   print "       the tool will find that and re-print it with"
@@ -44,347 +42,23 @@
   sys.exit(1)
 
 
-class SSOCookie(object):
-  """Creates a cookie file so we can download files from the build server."""
-
-  def __init__(self, cookiename=".sso.cookie", keep=False):
-    self.sso_server = "login.corp.google.com"
-    self.name = cookiename
-    self.keeper = keep
-    if not os.path.exists(self.name):
-      user = os.environ["USER"]
-      print "\n%s, to access the symbols, please enter your LDAP " % user,
-      sys.stdout.flush()
-      password = getpass.getpass()
-      params = urllib.urlencode({"u": user, "pw": password})
-      url = "https://%s/login?ssoformat=CORP_SSO" % self.sso_server
-      # login to SSO
-      curlcmd = ["/usr/bin/curl",
-                 "--cookie", self.name,
-                 "--cookie-jar", self.name,
-                 "--silent",
-                 "--location",
-                 "--data", params,
-                 "--output", "/dev/null",
-                 url]
-      subprocess.check_call(curlcmd)
-      if os.path.exists(self.name):
-        os.chmod(self.name, 0600)
-      else:
-        print "Could not log in to SSO"
-        sys.exit(1)
-
-  def __del__(self):
-    """Clean up."""
-    if not self.keeper:
-      os.remove(self.name)
-
-
-class NoBuildIDException(Exception):
-  pass
-
-
-def FindBuildFingerprint(lines):
-  """Searches the given file (array of lines) for the build fingerprint."""
-  fingerprint_regex = re.compile("^.*Build fingerprint:\s'(?P<fingerprint>.*)'")
-  for line in lines:
-    fingerprint_search = fingerprint_regex.match(line.strip())
-    if fingerprint_search:
-      return fingerprint_search.group("fingerprint")
-
-  return None  # didn't find the fingerprint string, so return none
-
-
-class SymbolDownloadException(Exception):
-  pass
-
-
-DEFAULT_SYMROOT = "/tmp/symbols"
-
-
-def DownloadSymbols(fingerprint, cookie):
-  """Attempts to download the symbols from the build server.
-
-  If successful, extracts them, and returns the path.
-
-  Args:
-    fingerprint: build fingerprint from the input stack trace
-    cookie: SSOCookie
-
-  Returns:
-    tuple (None, None) if no fingerprint is provided. Otherwise
-    tuple (root directory, symbols directory).
-
-  Raises:
-    SymbolDownloadException: Problem downloading symbols for fingerprint
-  """
-  if fingerprint is None:
-    return (None, None)
-  symdir = "%s/%s" % (DEFAULT_SYMROOT, hash(fingerprint))
-  if not os.path.exists(symdir):
-    os.makedirs(symdir)
-  # build server figures out the branch based on the CL
-  params = {
-      "op": "GET-SYMBOLS-LINK",
-      "fingerprint": fingerprint,
-      }
-  print "url: http://android-build/buildbot-update?" + urllib.urlencode(params)
-  url = urllib.urlopen("http://android-build/buildbot-update?",
-                       urllib.urlencode(params)).readlines()[0]
-  if not url:
-    raise SymbolDownloadException("Build server down? Failed to find syms...")
-
-  regex_str = (r"(?P<base_url>http\:\/\/android-build\/builds\/.*\/[0-9]+)"
-               r"(?P<img>.*)")
-  url_regex = re.compile(regex_str)
-  url_match = url_regex.match(url)
-  if url_match is None:
-    raise SymbolDownloadException("Unexpected results from build server URL...")
-
-  base_url = url_match.group("base_url")
-  img = url_match.group("img")
-  symbolfile = img.replace("-img-", "-symbols-")
-  symurl = base_url + symbolfile
-  localsyms = symdir + symbolfile
-
-  if not os.path.exists(localsyms):
-    print "downloading %s ..." % symurl
-    curlcmd = ["/usr/bin/curl",
-               "--cookie", cookie.name,
-               "--silent",
-               "--location",
-               "--write-out", "%{http_code}",
-               "--output", localsyms,
-               symurl]
-    p = subprocess.Popen(curlcmd,
-                         stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-                         close_fds=True)
-    code = p.stdout.read()
-    err = p.stderr.read()
-    if err:
-      raise SymbolDownloadException("stderr from curl download: %s" % err)
-    if code != "200":
-      raise SymbolDownloadException("Faied to download %s" % symurl)
-  else:
-    print "using existing cache for symbols"
-
-  return UnzipSymbols(localsyms, symdir)
-
-
-def UnzipSymbols(symbolfile, symdir=None):
-  """Unzips a file to DEFAULT_SYMROOT and returns the unzipped location.
-
-  Args:
-    symbolfile: The .zip file to unzip
-    symdir: Optional temporary directory to use for extraction
-
-  Returns:
-    A tuple containing (the directory into which the zip file was unzipped,
-    the path to the "symbols" directory in the unzipped file).  To clean
-    up, the caller can delete the first element of the tuple.
-
-  Raises:
-    SymbolDownloadException: When the unzip fails.
-  """
-  if not symdir:
-    symdir = "%s/%s" % (DEFAULT_SYMROOT, hash(symbolfile))
-  if not os.path.exists(symdir):
-    os.makedirs(symdir)
-
-  print "extracting %s..." % symbolfile
-  saveddir = os.getcwd()
-  os.chdir(symdir)
-  try:
-    unzipcode = subprocess.call(["unzip", "-qq", "-o", symbolfile])
-    if unzipcode > 0:
-      os.remove(symbolfile)
-      raise SymbolDownloadException("failed to extract symbol files (%s)."
-                                    % symbolfile)
-  finally:
-    os.chdir(saveddir)
-
-  return (symdir, glob.glob("%s/out/target/product/*/symbols" % symdir)[0])
-
-
-def PrintTraceLines(trace_lines):
-  """Print back trace."""
-  maxlen = max(map(lambda tl: len(tl[1]), trace_lines))
-  print
-  print "Stack Trace:"
-  print "  RELADDR   " + "FUNCTION".ljust(maxlen) + "  FILE:LINE"
-  for tl in trace_lines:
-    (addr, symbol_with_offset, location) = tl
-    print "  %8s  %s  %s" % (addr, symbol_with_offset.ljust(maxlen), location)
-  return
-
-
-def PrintValueLines(value_lines):
-  """Print stack data values."""
-  print
-  print "Stack Data:"
-  print "  ADDR      VALUE     FILE:LINE/FUNCTION"
-  for vl in value_lines:
-    (addr, value, symbol_with_offset, location) = vl
-    print "  " + addr + "  " + value + "  " + location
-    if location:
-      print "                      " + symbol_with_offset
-  return
-
-UNKNOWN = "<unknown>"
-HEAP = "[heap]"
-STACK = "[stack]"
-
-
-def ConvertTrace(lines):
-  """Convert strings containing native crash to a stack."""
-  process_info_line = re.compile("(pid: [0-9]+, tid: [0-9]+.*)")
-  signal_line = re.compile("(signal [0-9]+ \(.*\).*)")
-  register_line = re.compile("(([ ]*[0-9a-z]{2} [0-9a-f]{8}){4})")
-  thread_line = re.compile("(.*)(\-\-\- ){15}\-\-\-")
-  # Note taht both trace and value line matching allow for variable amounts of
-  # whitespace (e.g. \t). This is because the we want to allow for the stack
-  # tool to operate on AndroidFeedback provided system logs. AndroidFeedback
-  # strips out double spaces that are found in tombsone files and logcat output.
-  #
-  # Examples of matched trace lines include lines from tombstone files like:
-  #   #00  pc 001cf42e  /data/data/com.my.project/lib/libmyproject.so
-  # Or lines from AndroidFeedback crash report system logs like:
-  #   03-25 00:51:05.520 I/DEBUG ( 65): #00 pc 001cf42e /data/data/com.my.project/lib/libmyproject.so
-  # Please note the spacing differences.
-  trace_line = re.compile("(.*)\#([0-9]+)[ \t]+(..)[ \t]+([0-9a-f]{8})[ \t]+([^\r\n \t]*)( \((.*)\))?")  # pylint: disable-msg=C6310
-  # Examples of matched value lines include:
-  #   bea4170c  8018e4e9  /data/data/com.my.project/lib/libmyproject.so
-  #   03-25 00:51:05.530 I/DEBUG ( 65): bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so
-  # Again, note the spacing differences.
-  value_line = re.compile("(.*)([0-9a-f]{8})[ \t]+([0-9a-f]{8})[ \t]+([^\r\n \t]*)")
-  # Lines from 'code around' sections of the output will be matched before
-  # value lines because otheriwse the 'code around' sections will be confused as
-  # value lines.
-  #
-  # Examples include:
-  #   801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
-  #   03-25 00:51:05.530 I/DEBUG ( 65): 801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
-  code_line = re.compile("(.*)[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[ \r\n]")  # pylint: disable-msg=C6310
-
-  trace_lines = []
-  value_lines = []
-
-  for ln in lines:
-    # AndroidFeedback adds zero width spaces into its crash reports. These
-    # should be removed or the regular expresssions will fail to match.
-    line = unicode(ln, errors='ignore')
-    header = process_info_line.search(line)
-    if header:
-      print header.group(1)
-      continue
-    header = signal_line.search(line)
-    if header:
-      print header.group(1)
-      continue
-    header = register_line.search(line)
-    if header:
-      print header.group(1)
-      continue
-    if trace_line.match(line):
-      match = trace_line.match(line)
-      (unused_0, unused_1, unused_2,
-       code_addr, area, symbol_present, symbol_name) = match.groups()
-
-      if area == UNKNOWN or area == HEAP or area == STACK:
-        trace_lines.append((code_addr, area, area))
-      else:
-        # If a calls b which further calls c and c is inlined to b, we want to
-        # display "a -> b -> c" in the stack trace instead of just "a -> c"
-        (source_symbol,
-         source_location,
-         object_symbol_with_offset) = symbol.SymbolInformation(area, code_addr)
-        if not source_symbol:
-          if symbol_present:
-            source_symbol = symbol.CallCppFilt(symbol_name)
-          else:
-            source_symbol = UNKNOWN
-        if not source_location:
-          source_location = area
-        if not object_symbol_with_offset:
-          object_symbol_with_offset = source_symbol
-        if not object_symbol_with_offset.startswith(source_symbol):
-          trace_lines.append(("v------>", source_symbol, source_location))
-          trace_lines.append((code_addr,
-                              object_symbol_with_offset,
-                              source_location))
-        else:
-          trace_lines.append((code_addr,
-                              object_symbol_with_offset,
-                              source_location))
-    if code_line.match(line):
-      # Code lines should be ignored. If this were exluded the 'code around'
-      # sections would trigger value_line matches.
-      continue;
-    if value_line.match(line):
-      match = value_line.match(line)
-      (unused_, addr, value, area) = match.groups()
-      if area == UNKNOWN or area == HEAP or area == STACK or not area:
-        value_lines.append((addr, value, area, ""))
-      else:
-        (source_symbol,
-         source_location,
-         object_symbol_with_offset) = symbol.SymbolInformation(area, value)
-        if not source_location:
-          source_location = ""
-        if not object_symbol_with_offset:
-          object_symbol_with_offset = UNKNOWN
-        value_lines.append((addr,
-                            value,
-                            object_symbol_with_offset,
-                            source_location))
-    header = thread_line.search(line)
-    if header:
-      if trace_lines:
-        PrintTraceLines(trace_lines)
-
-      if value_lines:
-        PrintValueLines(value_lines)
-      trace_lines = []
-      value_lines = []
-      print
-      print "-----------------------------------------------------\n"
-
-  if trace_lines:
-    PrintTraceLines(trace_lines)
-
-  if value_lines:
-    PrintValueLines(value_lines)
-
-
 def main():
   try:
     options, arguments = getopt.getopt(sys.argv[1:], "",
-                                       ["auto",
-                                        "symbols-dir=",
-                                        "symbols-zip=",
+                                       ["arch=",
                                         "help"])
   except getopt.GetoptError, unused_error:
     PrintUsage()
 
-  zip_arg = None
-  auto = False
-  fingerprint = None
   for option, value in options:
     if option == "--help":
       PrintUsage()
-    elif option == "--symbols-dir":
-      symbol.SYMBOLS_DIR = os.path.expanduser(value)
-    elif option == "--symbols-zip":
-      zip_arg = os.path.expanduser(value)
-    elif option == "--auto":
-      auto = True
+    elif option == "--arch":
+      symbol.ARCH = value
 
   if len(arguments) > 1:
     PrintUsage()
 
-  if auto:
-    cookie = SSOCookie(".symbols.cookie")
-
   if not arguments or arguments[0] == "-":
     print "Reading native crash info from stdin"
     f = sys.stdin
@@ -395,22 +69,8 @@
   lines = f.readlines()
   f.close()
 
-  rootdir = None
-  if auto:
-    fingerprint = FindBuildFingerprint(lines)
-    print "fingerprint:", fingerprint
-    rootdir, symbol.SYMBOLS_DIR = DownloadSymbols(fingerprint, cookie)
-  elif zip_arg:
-    rootdir, symbol.SYMBOLS_DIR = UnzipSymbols(zip_arg)
-
   print "Reading symbols from", symbol.SYMBOLS_DIR
-  ConvertTrace(lines)
-
-  if rootdir:
-    # be a good citizen and clean up...os.rmdir and os.removedirs() don't work
-    cmd = "rm -rf \"%s\"" % rootdir
-    print "\ncleaning up (%s)" % cmd
-    os.system(cmd)
+  stack_core.ConvertTrace(lines)
 
 if __name__ == "__main__":
   main()
diff --git a/scripts/stack_core.py b/scripts/stack_core.py
new file mode 100755
index 0000000..42285d4
--- /dev/null
+++ b/scripts/stack_core.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""stack symbolizes native crash dumps."""
+
+import re
+
+import symbol
+
+def PrintTraceLines(trace_lines):
+  """Print back trace."""
+  maxlen = max(map(lambda tl: len(tl[1]), trace_lines))
+  print
+  print "Stack Trace:"
+  print "  RELADDR   " + "FUNCTION".ljust(maxlen) + "  FILE:LINE"
+  for tl in trace_lines:
+    (addr, symbol_with_offset, location) = tl
+    print "  %8s  %s  %s" % (addr, symbol_with_offset.ljust(maxlen), location)
+  return
+
+
+def PrintValueLines(value_lines):
+  """Print stack data values."""
+  maxlen = max(map(lambda tl: len(tl[2]), value_lines))
+  print
+  print "Stack Data:"
+  print "  ADDR      VALUE     " + "FUNCTION".ljust(maxlen) + "  FILE:LINE"
+  for vl in value_lines:
+    (addr, value, symbol_with_offset, location) = vl
+    print "  %8s  %8s  %s  %s" % (addr, value, symbol_with_offset.ljust(maxlen), location)
+  return
+
+UNKNOWN = "<unknown>"
+HEAP = "[heap]"
+STACK = "[stack]"
+
+
+def PrintOutput(trace_lines, value_lines):
+  if trace_lines:
+    PrintTraceLines(trace_lines)
+  if value_lines:
+    PrintValueLines(value_lines)
+
+def PrintDivider():
+  print
+  print "-----------------------------------------------------\n"
+
+def ConvertTrace(lines):
+  """Convert strings containing native crash to a stack."""
+  process_info_line = re.compile("(pid: [0-9]+, tid: [0-9]+.*)")
+  signal_line = re.compile("(signal [0-9]+ \(.*\).*)")
+  register_line = re.compile("(([ ]*[0-9a-z]{2} [0-9a-f]{8}){4})")
+  thread_line = re.compile("(.*)(\-\-\- ){15}\-\-\-")
+  dalvik_jni_thread_line = re.compile("(\".*\" prio=[0-9]+ tid=[0-9]+ NATIVE.*)")
+  dalvik_native_thread_line = re.compile("(\".*\" sysTid=[0-9]+ nice=[0-9]+.*)")
+  # Note that both trace and value line matching allow for variable amounts of
+  # whitespace (e.g. \t). This is because the we want to allow for the stack
+  # tool to operate on AndroidFeedback provided system logs. AndroidFeedback
+  # strips out double spaces that are found in tombsone files and logcat output.
+  #
+  # Examples of matched trace lines include lines from tombstone files like:
+  #   #00  pc 001cf42e  /data/data/com.my.project/lib/libmyproject.so
+  #   #00  pc 001cf42e  /data/data/com.my.project/lib/libmyproject.so (symbol)
+  # Or lines from AndroidFeedback crash report system logs like:
+  #   03-25 00:51:05.520 I/DEBUG ( 65): #00 pc 001cf42e /data/data/com.my.project/lib/libmyproject.so
+  # Please note the spacing differences.
+  trace_line = re.compile("(.*)\#([0-9]+)[ \t]+(..)[ \t]+([0-9a-f]{8})[ \t]+([^\r\n \t]*)( \((.*)\))?")  # pylint: disable-msg=C6310
+  # Examples of matched value lines include:
+  #   bea4170c  8018e4e9  /data/data/com.my.project/lib/libmyproject.so
+  #   bea4170c  8018e4e9  /data/data/com.my.project/lib/libmyproject.so (symbol)
+  #   03-25 00:51:05.530 I/DEBUG ( 65): bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so
+  # Again, note the spacing differences.
+  value_line = re.compile("(.*)([0-9a-f]{8})[ \t]+([0-9a-f]{8})[ \t]+([^\r\n \t]*)( \((.*)\))?")
+  # Lines from 'code around' sections of the output will be matched before
+  # value lines because otheriwse the 'code around' sections will be confused as
+  # value lines.
+  #
+  # Examples include:
+  #   801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
+  #   03-25 00:51:05.530 I/DEBUG ( 65): 801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
+  code_line = re.compile("(.*)[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[ \r\n]")  # pylint: disable-msg=C6310
+
+  trace_lines = []
+  value_lines = []
+  last_frame = -1
+
+  for ln in lines:
+    # AndroidFeedback adds zero width spaces into its crash reports. These
+    # should be removed or the regular expresssions will fail to match.
+    line = unicode(ln, errors='ignore')
+    process_header = process_info_line.search(line)
+    signal_header = signal_line.search(line)
+    register_header = register_line.search(line)
+    thread_header = thread_line.search(line)
+    dalvik_jni_thread_header = dalvik_jni_thread_line.search(line)
+    dalvik_native_thread_header = dalvik_native_thread_line.search(line)
+    if process_header or signal_header or register_header or thread_header \
+        or dalvik_jni_thread_header or dalvik_native_thread_header:
+      if trace_lines or value_lines:
+        PrintOutput(trace_lines, value_lines)
+        PrintDivider()
+        trace_lines = []
+        value_lines = []
+        last_frame = -1
+      if process_header:
+        print process_header.group(1)
+      if signal_header:
+        print signal_header.group(1)
+      if register_header:
+        print register_header.group(1)
+      if thread_header:
+        print thread_header.group(1)
+      if dalvik_jni_thread_header:
+        print dalvik_jni_thread_header.group(1)
+      if dalvik_native_thread_header:
+        print dalvik_native_thread_header.group(1)
+      continue
+    if trace_line.match(line):
+      match = trace_line.match(line)
+      (unused_0, frame, unused_1,
+       code_addr, area, symbol_present, symbol_name) = match.groups()
+
+      if frame <= last_frame and (trace_lines or value_lines):
+        PrintOutput(trace_lines, value_lines)
+        PrintDivider()
+        trace_lines = []
+        value_lines = []
+      last_frame = frame
+
+      if area == UNKNOWN or area == HEAP or area == STACK:
+        trace_lines.append((code_addr, "", area))
+      else:
+        # If a calls b which further calls c and c is inlined to b, we want to
+        # display "a -> b -> c" in the stack trace instead of just "a -> c"
+        info = symbol.SymbolInformation(area, code_addr)
+        nest_count = len(info) - 1
+        for (source_symbol, source_location, object_symbol_with_offset) in info:
+          if not source_symbol:
+            if symbol_present:
+              source_symbol = symbol.CallCppFilt(symbol_name)
+            else:
+              source_symbol = UNKNOWN
+          if not source_location:
+            source_location = area
+          if nest_count > 0:
+            nest_count = nest_count - 1
+            trace_lines.append(("v------>", source_symbol, source_location))
+          else:
+            if not object_symbol_with_offset:
+              object_symbol_with_offset = source_symbol
+            trace_lines.append((code_addr,
+                                object_symbol_with_offset,
+                                source_location))
+    if code_line.match(line):
+      # Code lines should be ignored. If this were exluded the 'code around'
+      # sections would trigger value_line matches.
+      continue;
+    if value_line.match(line):
+      match = value_line.match(line)
+      (unused_, addr, value, area, symbol_present, symbol_name) = match.groups()
+      if area == UNKNOWN or area == HEAP or area == STACK or not area:
+        value_lines.append((addr, value, "", area))
+      else:
+        info = symbol.SymbolInformation(area, value)
+        (source_symbol, source_location, object_symbol_with_offset) = info.pop()
+        if not source_symbol:
+          if symbol_present:
+            source_symbol = symbol.CallCppFilt(symbol_name)
+          else:
+            source_symbol = UNKNOWN
+        if not source_location:
+          source_location = area
+        if not object_symbol_with_offset:
+          object_symbol_with_offset = source_symbol
+        value_lines.append((addr,
+                            value,
+                            object_symbol_with_offset,
+                            source_location))
+
+  PrintOutput(trace_lines, value_lines)
+
+
+# vi: ts=2 sw=2
diff --git a/scripts/symbol.py b/scripts/symbol.py
index b0e94d8..0f58df6 100755
--- a/scripts/symbol.py
+++ b/scripts/symbol.py
@@ -1,6 +1,18 @@
 #!/usr/bin/python
 #
-# Copyright 2006 Google Inc. All Rights Reserved.
+# 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.
 
 """Module for looking up symbolic debugging information.
 
@@ -29,6 +41,10 @@
 
 SYMBOLS_DIR = FindSymbolsDir()
 
+ARCH = "arm"
+
+TOOLCHAIN_INFO = None
+
 def Uname():
   """'uname' for constructing prebuilt/<...> and out/host/<...> paths."""
   uname = os.uname()[0]
@@ -44,9 +60,9 @@
 def ToolPath(tool, toolchain_info=None):
   """Return a full qualified path to the specified tool"""
   if not toolchain_info:
-    toolchain_info = TOOLCHAIN_INFO
-  (label, target) = toolchain_info
-  return os.path.join(ANDROID_BUILD_TOP, "prebuilts", "gcc", Uname(), "arm", label, "bin",
+    toolchain_info = FindToolchain()
+  (label, platform, target) = toolchain_info
+  return os.path.join(ANDROID_BUILD_TOP, "prebuilts/gcc", Uname(), platform, label, "bin",
                      target + "-" + tool)
 
 def FindToolchain():
@@ -58,27 +74,32 @@
   Returns:
     A pair of strings containing toolchain label and target prefix.
   """
+  global TOOLCHAIN_INFO
+  if TOOLCHAIN_INFO is not None:
+    return TOOLCHAIN_INFO
 
   ## Known toolchains, newer ones in the front.
-  known_toolchains = [
-    ("arm-eabi-4.6", "arm-eabi"),
-    ("arm-linux-androideabi-4.4.x", "arm-linux-androideabi"),
-    ("arm-eabi-4.4.3", "arm-eabi"),
-    ("arm-eabi-4.4.0", "arm-eabi"),
-    ("arm-eabi-4.3.1", "arm-eabi"),
-    ("arm-eabi-4.2.1", "arm-eabi")
-  ]
+  if ARCH == "arm":
+    gcc_version = os.environ["TARGET_GCC_VERSION"]
+    known_toolchains = [
+      ("arm-linux-androideabi-" + gcc_version, "arm", "arm-linux-androideabi"),
+    ]
+  elif ARCH =="x86":
+    known_toolchains = [
+      ("i686-android-linux-4.4.3", "x86", "i686-android-linux")
+    ]
+  else:
+    known_toolchains = []
 
   # Look for addr2line to check for valid toolchain path.
-  for (label, target) in known_toolchains:
-    toolchain_info = (label, target);
+  for (label, platform, target) in known_toolchains:
+    toolchain_info = (label, platform, target);
     if os.path.exists(ToolPath("addr2line", toolchain_info)):
+      TOOLCHAIN_INFO = toolchain_info
       return toolchain_info
 
   raise Exception("Could not find tool chain")
 
-TOOLCHAIN_INFO = FindToolchain()
-
 def SymbolInformation(lib, addr):
   """Look up symbol information about an address.
 
@@ -87,20 +108,19 @@
     addr: string hexidecimal address
 
   Returns:
-    For a given library and address, return tuple of: (source_symbol,
-    source_location, object_symbol_with_offset) the values may be None
-    if the information was unavailable.
+    A list of the form [(source_symbol, source_location,
+    object_symbol_with_offset)].
 
-    source_symbol may not be a prefix of object_symbol_with_offset if
-    the source function was inlined in the object code of another
-    function.
+    If the function has been inlined then the list may contain
+    more than one element with the symbols for the most deeply
+    nested inlined location appearing first.  The list is
+    always non-empty, even if no information is available.
 
-    usually you want to display the object_symbol_with_offset and
-    source_location, the source_symbol is only useful to show if the
-    address was from an inlined function.
+    Usually you want to display the source_location and
+    object_symbol_with_offset from the last element in the list.
   """
   info = SymbolInformationForSet(lib, set([addr]))
-  return (info and info.get(addr)) or (None, None, None)
+  return (info and info.get(addr)) or [(None, None, None)]
 
 
 def SymbolInformationForSet(lib, unique_addrs):
@@ -111,17 +131,17 @@
     unique_addrs: set of hexidecimal addresses
 
   Returns:
-    For a given library and set of addresses, returns a dictionary of the form
-    {addr: (source_symbol, source_location, object_symbol_with_offset)}. The
-    values may be None if the information was unavailable.
+    A dictionary of the form {addr: [(source_symbol, source_location,
+    object_symbol_with_offset)]} where each address has a list of
+    associated symbols and locations.  The list is always non-empty.
 
-    For a given address, source_symbol may not be a prefix of
-    object_symbol_with_offset if the source function was inlined in the
-    object code of another function.
+    If the function has been inlined then the list may contain
+    more than one element with the symbols for the most deeply
+    nested inlined location appearing first.  The list is
+    always non-empty, even if no information is available.
 
-    Usually you want to display the object_symbol_with_offset and
-    source_location; the source_symbol is only useful to show if the
-    address was from an inlined function.
+    Usually you want to display the source_location and
+    object_symbol_with_offset from the last element in the list.
   """
   if not lib:
     return None
@@ -136,14 +156,17 @@
 
   result = {}
   for addr in unique_addrs:
-    (source_symbol, source_location) = addr_to_line.get(addr, (None, None))
+    source_info = addr_to_line.get(addr)
+    if not source_info:
+      source_info = [(None, None)]
     if addr in addr_to_objdump:
       (object_symbol, object_offset) = addr_to_objdump.get(addr)
       object_symbol_with_offset = FormatSymbolWithOffset(object_symbol,
                                                          object_offset)
     else:
       object_symbol_with_offset = None
-    result[addr] = (source_symbol, source_location, object_symbol_with_offset)
+    result[addr] = [(source_symbol, source_location, object_symbol_with_offset)
+        for (source_symbol, source_location) in source_info]
 
   return result
 
@@ -156,8 +179,13 @@
     unique_addrs: set of string hexidecimal addresses look up.
 
   Returns:
-    A dictionary of the form {addr: (symbol, file:line)}. The values may
-    be (None, None) if the address could not be looked up.
+    A dictionary of the form {addr: [(symbol, file:line)]} where
+    each address has a list of associated symbols and locations
+    or an empty list if no symbol information was found.
+
+    If the function has been inlined then the list may contain
+    more than one element with the symbols for the most deeply
+    nested inlined location appearing first.
   """
   if not lib:
     return None
@@ -167,8 +195,9 @@
   if not os.path.exists(symbols):
     return None
 
-  (label, target) = TOOLCHAIN_INFO
-  cmd = [ToolPath("addr2line"), "--functions", "--demangle", "--exe=" + symbols]
+  (label, platform, target) = FindToolchain()
+  cmd = [ToolPath("addr2line"), "--functions", "--inlines",
+      "--demangle", "--exe=" + symbols]
   child = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
 
   result = {}
@@ -176,18 +205,45 @@
   for addr in addrs:
     child.stdin.write("0x%s\n" % addr)
     child.stdin.flush()
-    symbol = child.stdout.readline().strip()
-    if symbol == "??":
-      symbol = None
-    location = child.stdout.readline().strip()
-    if location == "??:0":
-      location = None
-    result[addr] = (symbol, location)
+    records = []
+    first = True
+    while True:
+      symbol = child.stdout.readline().strip()
+      if symbol == "??":
+        symbol = None
+      location = child.stdout.readline().strip()
+      if location == "??:0":
+        location = None
+      if symbol is None and location is None:
+        break
+      records.append((symbol, location))
+      if first:
+        # Write a blank line as a sentinel so we know when to stop
+        # reading inlines from the output.
+        # The blank line will cause addr2line to emit "??\n??:0\n".
+        child.stdin.write("\n")
+        first = False
+    result[addr] = records
   child.stdin.close()
   child.stdout.close()
   return result
 
 
+def StripPC(addr):
+  """Strips the Thumb bit a program counter address when appropriate.
+
+  Args:
+    addr: the program counter address
+
+  Returns:
+    The stripped program counter address.
+  """
+  global ARCH
+
+  if ARCH == "arm":
+    return addr & ~1
+  return addr
+
 def CallObjdumpForSet(lib, unique_addrs):
   """Use objdump to find out the names of the containing functions.
 
@@ -210,13 +266,13 @@
     return None
 
   addrs = sorted(unique_addrs)
-  start_addr_hex = addrs[0]
-  stop_addr_dec = str(int(addrs[-1], 16) + 8)
+  start_addr_dec = str(StripPC(int(addrs[0], 16)))
+  stop_addr_dec = str(StripPC(int(addrs[-1], 16)) + 8)
   cmd = [ToolPath("objdump"),
          "--section=.text",
          "--demangle",
          "--disassemble",
-         "--start-address=0x" + start_addr_hex,
+         "--start-address=" + start_addr_dec,
          "--stop-address=" + stop_addr_dec,
          symbols]
 
@@ -261,7 +317,7 @@
       addr = components.group(1)
       target_addr = addrs[addr_index]
       i_addr = int(addr, 16)
-      i_target = int(target_addr, 16)
+      i_target = StripPC(int(target_addr, 16))
       if i_addr == i_target:
         result[target_addr] = (current_symbol, i_target - current_symbol_addr)
         addr_index += 1
diff --git a/sdk/api-versions.xml b/sdk/api-versions.xml
index 4ce952f..3855e9d 100644
--- a/sdk/api-versions.xml
+++ b/sdk/api-versions.xml
@@ -24,13 +24,16 @@
 		<field name="BIND_APPWIDGET" since="3" />
 		<field name="BIND_DEVICE_ADMIN" since="8" />
 		<field name="BIND_INPUT_METHOD" since="3" />
+		<field name="BIND_NFC_SERVICE" since="19" />
 		<field name="BIND_NOTIFICATION_LISTENER_SERVICE" since="18" />
+		<field name="BIND_PRINT_SERVICE" since="19" />
 		<field name="BIND_REMOTEVIEWS" since="11" />
 		<field name="BIND_TEXT_SERVICE" since="14" />
 		<field name="BIND_VPN_SERVICE" since="14" />
 		<field name="BIND_WALLPAPER" since="8" />
 		<field name="BLUETOOTH" />
 		<field name="BLUETOOTH_ADMIN" />
+		<field name="BLUETOOTH_PRIVILEGED" since="19" />
 		<field name="BRICK" />
 		<field name="BROADCAST_PACKAGE_REMOVED" />
 		<field name="BROADCAST_SMS" since="2" />
@@ -39,6 +42,9 @@
 		<field name="CALL_PHONE" />
 		<field name="CALL_PRIVILEGED" />
 		<field name="CAMERA" />
+		<field name="CAPTURE_AUDIO_OUTPUT" since="19" />
+		<field name="CAPTURE_SECURE_VIDEO_OUTPUT" since="19" />
+		<field name="CAPTURE_VIDEO_OUTPUT" since="19" />
 		<field name="CHANGE_COMPONENT_ENABLED_STATE" />
 		<field name="CHANGE_CONFIGURATION" />
 		<field name="CHANGE_NETWORK_STATE" />
@@ -67,13 +73,16 @@
 		<field name="INJECT_EVENTS" />
 		<field name="INSTALL_LOCATION_PROVIDER" since="4" />
 		<field name="INSTALL_PACKAGES" />
+		<field name="INSTALL_SHORTCUT" since="19" />
 		<field name="INTERNAL_SYSTEM_WINDOW" />
 		<field name="INTERNET" />
 		<field name="KILL_BACKGROUND_PROCESSES" since="8" />
 		<field name="LOCATION_HARDWARE" since="18" />
 		<field name="MANAGE_ACCOUNTS" since="5" />
 		<field name="MANAGE_APP_TOKENS" />
+		<field name="MANAGE_DOCUMENTS" since="19" />
 		<field name="MASTER_CLEAR" />
+		<field name="MEDIA_CONTENT_CONTROL" since="19" />
 		<field name="MODIFY_AUDIO_SETTINGS" />
 		<field name="MODIFY_PHONE_STATE" />
 		<field name="MOUNT_FORMAT_FILESYSTEMS" since="3" />
@@ -126,6 +135,8 @@
 		<field name="SUBSCRIBED_FEEDS_READ" />
 		<field name="SUBSCRIBED_FEEDS_WRITE" />
 		<field name="SYSTEM_ALERT_WINDOW" />
+		<field name="TRANSMIT_IR" since="19" />
+		<field name="UNINSTALL_SHORTCUT" since="19" />
 		<field name="UPDATE_DEVICE_STATS" since="3" />
 		<field name="USE_CREDENTIALS" since="5" />
 		<field name="USE_SIP" since="9" />
@@ -225,6 +236,7 @@
 		<field name="accessibilityEventTypes" since="14" />
 		<field name="accessibilityFeedbackType" since="14" />
 		<field name="accessibilityFlags" since="14" />
+		<field name="accessibilityLiveRegion" since="19" />
 		<field name="accountPreferences" since="5" />
 		<field name="accountType" since="5" />
 		<field name="action" />
@@ -259,8 +271,10 @@
 		<field name="activityCloseExitAnimation" />
 		<field name="activityOpenEnterAnimation" />
 		<field name="activityOpenExitAnimation" />
+		<field name="addPrintersActivity" since="19" />
 		<field name="addStatesFromChildren" />
 		<field name="adjustViewBounds" />
+		<field name="advancedPrintOptionsActivity" since="19" />
 		<field name="alertDialogIcon" since="11" />
 		<field name="alertDialogStyle" />
 		<field name="alertDialogTheme" since="11" />
@@ -286,12 +300,14 @@
 		<field name="animationResolution" since="11" />
 		<field name="antialias" />
 		<field name="anyDensity" since="4" />
+		<field name="apduServiceBanner" since="19" />
 		<field name="apiKey" />
 		<field name="author" since="7" />
 		<field name="authorities" />
 		<field name="autoAdvanceViewId" since="11" />
 		<field name="autoCompleteTextViewStyle" />
 		<field name="autoLink" />
+		<field name="autoMirrored" since="19" />
 		<field name="autoStart" since="7" />
 		<field name="autoText" />
 		<field name="autoUrlDetect" since="4" />
@@ -332,6 +348,7 @@
 		<field name="canRetrieveWindowContent" since="14" />
 		<field name="candidatesTextStyleSpans" since="3" />
 		<field name="capitalize" />
+		<field name="category" since="19" />
 		<field name="centerBright" />
 		<field name="centerColor" />
 		<field name="centerDark" />
@@ -480,6 +497,7 @@
 		<field name="fadeScrollbars" since="5" />
 		<field name="fadingEdge" />
 		<field name="fadingEdgeLength" />
+		<field name="fadingMode" since="19" />
 		<field name="fastScrollAlwaysVisible" since="11" />
 		<field name="fastScrollEnabled" since="3" />
 		<field name="fastScrollOverlayPosition" since="11" />
@@ -519,6 +537,7 @@
 		<field name="freezesText" />
 		<field name="fromAlpha" />
 		<field name="fromDegrees" />
+		<field name="fromScene" since="19" />
 		<field name="fromXDelta" />
 		<field name="fromXScale" />
 		<field name="fromYDelta" />
@@ -604,6 +623,7 @@
 		<field name="installLocation" since="8" />
 		<field name="interpolator" />
 		<field name="isAlwaysSyncable" since="11" />
+		<field name="isAsciiCapable" since="19" />
 		<field name="isAuxiliary" since="14" />
 		<field name="isDefault" since="3" />
 		<field name="isIndicator" />
@@ -627,6 +647,7 @@
 		<field name="keyPreviewHeight" since="3" />
 		<field name="keyPreviewLayout" since="3" />
 		<field name="keyPreviewOffset" since="3" />
+		<field name="keySet" since="19" />
 		<field name="keyTextColor" since="3" />
 		<field name="keyTextSize" since="3" />
 		<field name="keyWidth" since="3" />
@@ -859,6 +880,7 @@
 		<field name="reqKeyboardType" since="3" />
 		<field name="reqNavigation" since="3" />
 		<field name="reqTouchScreen" since="3" />
+		<field name="requireDeviceUnlock" since="19" />
 		<field name="required" since="5" />
 		<field name="requiredAccountType" since="18" />
 		<field name="requiredForAllUsers" since="18" />
@@ -957,9 +979,13 @@
 		<field name="spinnersShown" since="11" />
 		<field name="splitMotionEvents" since="11" />
 		<field name="src" />
+		<field name="ssp" since="19" />
+		<field name="sspPattern" since="19" />
+		<field name="sspPrefix" since="19" />
 		<field name="stackFromBottom" />
 		<field name="starStyle" />
 		<field name="startColor" />
+		<field name="startDelay" since="19" />
 		<field name="startOffset" />
 		<field name="startYear" />
 		<field name="stateNotNeeded" />
@@ -1003,6 +1029,7 @@
 		<field name="summaryOff" />
 		<field name="summaryOn" />
 		<field name="supportsRtl" since="17" />
+		<field name="supportsSwitchingToNextInputMethod" since="19" />
 		<field name="supportsUploading" since="5" />
 		<field name="switchMinWidth" since="14" />
 		<field name="switchPadding" since="14" />
@@ -1019,6 +1046,7 @@
 		<field name="targetActivity" />
 		<field name="targetClass" />
 		<field name="targetDescriptions" since="14" />
+		<field name="targetId" since="19" />
 		<field name="targetPackage" />
 		<field name="targetSdkVersion" since="4" />
 		<field name="taskAffinity" />
@@ -1107,6 +1135,7 @@
 		<field name="titleTextStyle" since="11" />
 		<field name="toAlpha" />
 		<field name="toDegrees" />
+		<field name="toScene" since="19" />
 		<field name="toXDelta" />
 		<field name="toXScale" />
 		<field name="toYDelta" />
@@ -1121,6 +1150,8 @@
 		<field name="transcriptMode" />
 		<field name="transformPivotX" since="11" />
 		<field name="transformPivotY" since="11" />
+		<field name="transition" since="19" />
+		<field name="transitionOrdering" since="19" />
 		<field name="translationX" since="11" />
 		<field name="translationY" since="11" />
 		<field name="type" />
@@ -1139,6 +1170,7 @@
 		<field name="valueTo" since="11" />
 		<field name="valueType" since="11" />
 		<field name="variablePadding" />
+		<field name="vendor" since="19" />
 		<field name="versionCode" />
 		<field name="versionName" />
 		<field name="verticalCorrection" since="3" />
@@ -1198,6 +1230,8 @@
 		<field name="windowTitleBackgroundStyle" />
 		<field name="windowTitleSize" />
 		<field name="windowTitleStyle" />
+		<field name="windowTranslucentNavigation" since="19" />
+		<field name="windowTranslucentStatus" since="19" />
 		<field name="writePermission" />
 		<field name="x" />
 		<field name="xlargeScreens" since="9" />
@@ -1730,10 +1764,12 @@
 		<field name="Theme_DeviceDefault_Light_NoActionBar" since="14" />
 		<field name="Theme_DeviceDefault_Light_NoActionBar_Fullscreen" since="14" />
 		<field name="Theme_DeviceDefault_Light_NoActionBar_Overscan" since="18" />
+		<field name="Theme_DeviceDefault_Light_NoActionBar_TranslucentDecor" since="19" />
 		<field name="Theme_DeviceDefault_Light_Panel" since="14" />
 		<field name="Theme_DeviceDefault_NoActionBar" since="14" />
 		<field name="Theme_DeviceDefault_NoActionBar_Fullscreen" since="14" />
 		<field name="Theme_DeviceDefault_NoActionBar_Overscan" since="18" />
+		<field name="Theme_DeviceDefault_NoActionBar_TranslucentDecor" since="19" />
 		<field name="Theme_DeviceDefault_Panel" since="14" />
 		<field name="Theme_DeviceDefault_Wallpaper" since="14" />
 		<field name="Theme_DeviceDefault_Wallpaper_NoTitleBar" since="14" />
@@ -1757,10 +1793,12 @@
 		<field name="Theme_Holo_Light_NoActionBar" since="13" />
 		<field name="Theme_Holo_Light_NoActionBar_Fullscreen" since="13" />
 		<field name="Theme_Holo_Light_NoActionBar_Overscan" since="18" />
+		<field name="Theme_Holo_Light_NoActionBar_TranslucentDecor" since="19" />
 		<field name="Theme_Holo_Light_Panel" since="11" />
 		<field name="Theme_Holo_NoActionBar" since="11" />
 		<field name="Theme_Holo_NoActionBar_Fullscreen" since="11" />
 		<field name="Theme_Holo_NoActionBar_Overscan" since="18" />
+		<field name="Theme_Holo_NoActionBar_TranslucentDecor" since="19" />
 		<field name="Theme_Holo_Panel" since="11" />
 		<field name="Theme_Holo_Wallpaper" since="11" />
 		<field name="Theme_Holo_Wallpaper_NoTitleBar" since="11" />
@@ -2302,20 +2340,12 @@
 		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/Throwable;)V" />
 		<method name="&lt;init>(Ljava/lang/Throwable;)V" />
 	</class>
-	<class name="android/animation/Animatable" since="18">
-		<extends name="java/lang/Object" />
-		<method name="getDuration()J" />
-		<method name="getInterpolator()Landroid/animation/TimeInterpolator;" />
-		<method name="getStartDelay()J" />
-		<method name="setDuration(J)Landroid/animation/Animatable;" />
-		<method name="setInterpolator(Landroid/animation/TimeInterpolator;)V" />
-		<method name="setStartDelay(J)V" />
-	</class>
 	<class name="android/animation/Animator" since="11">
 		<extends name="java/lang/Object" />
 		<implements name="java/lang/Cloneable" />
 		<method name="&lt;init>()V" />
 		<method name="addListener(Landroid/animation/Animator$AnimatorListener;)V" />
+		<method name="addPauseListener(Landroid/animation/Animator$AnimatorPauseListener;)V" since="19" />
 		<method name="cancel()V" />
 		<method name="clone()Landroid/animation/Animator;" />
 		<method name="end()V" />
@@ -2323,10 +2353,14 @@
 		<method name="getInterpolator()Landroid/animation/TimeInterpolator;" since="18" />
 		<method name="getListeners()Ljava/util/ArrayList;" />
 		<method name="getStartDelay()J" />
+		<method name="isPaused()Z" since="19" />
 		<method name="isRunning()Z" />
 		<method name="isStarted()Z" since="14" />
+		<method name="pause()V" since="19" />
 		<method name="removeAllListeners()V" />
 		<method name="removeListener(Landroid/animation/Animator$AnimatorListener;)V" />
+		<method name="removePauseListener(Landroid/animation/Animator$AnimatorPauseListener;)V" since="19" />
+		<method name="resume()V" since="19" />
 		<method name="setDuration(J)Landroid/animation/Animator;" />
 		<method name="setInterpolator(Landroid/animation/TimeInterpolator;)V" />
 		<method name="setStartDelay(J)V" />
@@ -2342,6 +2376,11 @@
 		<method name="onAnimationRepeat(Landroid/animation/Animator;)V" />
 		<method name="onAnimationStart(Landroid/animation/Animator;)V" />
 	</class>
+	<class name="android/animation/Animator$AnimatorPauseListener" since="19">
+		<extends name="java/lang/Object" />
+		<method name="onAnimationPause(Landroid/animation/Animator;)V" />
+		<method name="onAnimationResume(Landroid/animation/Animator;)V" />
+	</class>
 	<class name="android/animation/AnimatorInflater" since="11">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -2350,6 +2389,7 @@
 	<class name="android/animation/AnimatorListenerAdapter" since="11">
 		<extends name="java/lang/Object" />
 		<implements name="android/animation/Animator$AnimatorListener" />
+		<implements name="android/animation/Animator$AnimatorPauseListener" since="19" />
 		<method name="&lt;init>()V" />
 	</class>
 	<class name="android/animation/AnimatorSet" since="11">
@@ -2780,6 +2820,7 @@
 		<method name="recreate()V" since="11" />
 		<method name="registerForContextMenu(Landroid/view/View;)V" />
 		<method name="removeDialog(I)V" />
+		<method name="reportFullyDrawn()V" since="19" />
 		<method name="requestWindowFeature(I)Z" />
 		<method name="runOnUiThread(Ljava/lang/Runnable;)V" />
 		<method name="setContentView(I)V" />
@@ -2851,6 +2892,8 @@
 	<class name="android/app/ActivityManager" since="1">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
+		<method name="clearApplicationUserData()Z" since="19" />
+		<method name="dumpPackageState(Ljava/io/FileDescriptor;Ljava/lang/String;)V" since="19" />
 		<method name="getDeviceConfigurationInfo()Landroid/content/pm/ConfigurationInfo;" since="3" />
 		<method name="getLargeMemoryClass()I" since="11" />
 		<method name="getLauncherLargeIconDensity()I" since="11" />
@@ -2865,12 +2908,14 @@
 		<method name="getRunningServiceControlPanel(Landroid/content/ComponentName;)Landroid/app/PendingIntent;" since="5" />
 		<method name="getRunningServices(I)Ljava/util/List;" />
 		<method name="getRunningTasks(I)Ljava/util/List;" />
+		<method name="isLowRamDevice()Z" since="19" />
 		<method name="isRunningInTestHarness()Z" since="11" />
 		<method name="isUserAMonkey()Z" since="8" />
 		<method name="killBackgroundProcesses(Ljava/lang/String;)V" since="8" />
 		<method name="moveTaskToFront(II)V" since="11" />
 		<method name="moveTaskToFront(IILandroid/os/Bundle;)V" since="16" />
 		<method name="restartPackage(Ljava/lang/String;)V" since="3" />
+		<field name="META_HOME_ALTERNATE" since="19" />
 		<field name="MOVE_TASK_NO_USER_ACTION" since="12" />
 		<field name="MOVE_TASK_WITH_HOME" since="11" />
 		<field name="RECENT_IGNORE_UNAVAILABLE" since="11" />
@@ -2998,10 +3043,12 @@
 		<method name="&lt;init>()V" />
 		<method name="cancel(Landroid/app/PendingIntent;)V" />
 		<method name="set(IJLandroid/app/PendingIntent;)V" />
+		<method name="setExact(IJLandroid/app/PendingIntent;)V" since="19" />
 		<method name="setInexactRepeating(IJJLandroid/app/PendingIntent;)V" since="3" />
 		<method name="setRepeating(IJJLandroid/app/PendingIntent;)V" />
 		<method name="setTime(J)V" since="8" />
 		<method name="setTimeZone(Ljava/lang/String;)V" />
+		<method name="setWindow(IJJLandroid/app/PendingIntent;)V" since="19" />
 		<field name="ELAPSED_REALTIME" />
 		<field name="ELAPSED_REALTIME_WAKEUP" />
 		<field name="INTERVAL_DAY" since="3" />
@@ -3086,6 +3133,31 @@
 		<extends name="android/app/Activity" />
 		<method name="&lt;init>()V" />
 	</class>
+	<class name="android/app/AppOpsManager" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="checkOp(Ljava/lang/String;ILjava/lang/String;)I" />
+		<method name="checkOpNoThrow(Ljava/lang/String;ILjava/lang/String;)I" />
+		<method name="checkPackage(ILjava/lang/String;)V" />
+		<method name="finishOp(Ljava/lang/String;ILjava/lang/String;)V" />
+		<method name="noteOp(Ljava/lang/String;ILjava/lang/String;)I" />
+		<method name="noteOpNoThrow(Ljava/lang/String;ILjava/lang/String;)I" />
+		<method name="startOp(Ljava/lang/String;ILjava/lang/String;)I" />
+		<method name="startOpNoThrow(Ljava/lang/String;ILjava/lang/String;)I" />
+		<method name="startWatchingMode(Ljava/lang/String;Ljava/lang/String;Landroid/app/AppOpsManager$OnOpChangedListener;)V" />
+		<method name="stopWatchingMode(Landroid/app/AppOpsManager$OnOpChangedListener;)V" />
+		<field name="MODE_ALLOWED" />
+		<field name="MODE_ERRORED" />
+		<field name="MODE_IGNORED" />
+		<field name="OPSTR_COARSE_LOCATION" />
+		<field name="OPSTR_FINE_LOCATION" />
+		<field name="OPSTR_MONITOR_HIGH_POWER_LOCATION" />
+		<field name="OPSTR_MONITOR_LOCATION" />
+	</class>
+	<class name="android/app/AppOpsManager$OnOpChangedListener" since="19">
+		<extends name="java/lang/Object" />
+		<method name="onOpChanged(Ljava/lang/String;Ljava/lang/String;)V" />
+	</class>
 	<class name="android/app/Application" since="1">
 		<extends name="android/content/ContextWrapper" />
 		<implements name="android/content/ComponentCallbacks" />
@@ -3775,6 +3847,23 @@
 		<field name="DEFAULT_LIGHTS" />
 		<field name="DEFAULT_SOUND" />
 		<field name="DEFAULT_VIBRATE" />
+		<field name="EXTRA_INFO_TEXT" since="19" />
+		<field name="EXTRA_LARGE_ICON" since="19" />
+		<field name="EXTRA_LARGE_ICON_BIG" since="19" />
+		<field name="EXTRA_PEOPLE" since="19" />
+		<field name="EXTRA_PICTURE" since="19" />
+		<field name="EXTRA_PROGRESS" since="19" />
+		<field name="EXTRA_PROGRESS_INDETERMINATE" since="19" />
+		<field name="EXTRA_PROGRESS_MAX" since="19" />
+		<field name="EXTRA_SHOW_CHRONOMETER" since="19" />
+		<field name="EXTRA_SHOW_WHEN" since="19" />
+		<field name="EXTRA_SMALL_ICON" since="19" />
+		<field name="EXTRA_SUB_TEXT" since="19" />
+		<field name="EXTRA_SUMMARY_TEXT" since="19" />
+		<field name="EXTRA_TEXT" since="19" />
+		<field name="EXTRA_TEXT_LINES" since="19" />
+		<field name="EXTRA_TITLE" since="19" />
+		<field name="EXTRA_TITLE_BIG" since="19" />
 		<field name="FLAG_AUTO_CANCEL" />
 		<field name="FLAG_FOREGROUND_SERVICE" since="5" />
 		<field name="FLAG_HIGH_PRIORITY" since="11" />
@@ -3789,12 +3878,14 @@
 		<field name="PRIORITY_MAX" since="16" />
 		<field name="PRIORITY_MIN" since="16" />
 		<field name="STREAM_DEFAULT" />
+		<field name="actions" since="19" />
 		<field name="audioStreamType" />
 		<field name="bigContentView" since="16" />
 		<field name="contentIntent" />
 		<field name="contentView" />
 		<field name="defaults" />
 		<field name="deleteIntent" />
+		<field name="extras" since="19" />
 		<field name="flags" />
 		<field name="fullScreenIntent" since="9" />
 		<field name="icon" />
@@ -3811,6 +3902,16 @@
 		<field name="vibrate" />
 		<field name="when" />
 	</class>
+	<class name="android/app/Notification$Action" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>(ILjava/lang/CharSequence;Landroid/app/PendingIntent;)V" />
+		<method name="clone()Landroid/app/Notification$Action;" />
+		<field name="CREATOR" />
+		<field name="actionIntent" />
+		<field name="icon" />
+		<field name="title" />
+	</class>
 	<class name="android/app/Notification$BigPictureStyle" since="16">
 		<extends name="android/app/Notification$Style" />
 		<method name="&lt;init>()V" />
@@ -3842,6 +3943,7 @@
 		<method name="setContentTitle(Ljava/lang/CharSequence;)Landroid/app/Notification$Builder;" />
 		<method name="setDefaults(I)Landroid/app/Notification$Builder;" />
 		<method name="setDeleteIntent(Landroid/app/PendingIntent;)Landroid/app/Notification$Builder;" />
+		<method name="setExtras(Landroid/os/Bundle;)Landroid/app/Notification$Builder;" since="19" />
 		<method name="setFullScreenIntent(Landroid/app/PendingIntent;Z)Landroid/app/Notification$Builder;" />
 		<method name="setLargeIcon(Landroid/graphics/Bitmap;)Landroid/app/Notification$Builder;" />
 		<method name="setLights(III)Landroid/app/Notification$Builder;" />
@@ -4194,6 +4296,9 @@
 		<method name="clear()V" />
 		<method name="clearWallpaperOffsets(Landroid/os/IBinder;)V" />
 		<method name="forgetLoadedWallpaper()V" since="14" />
+		<method name="getBuiltInDrawable()Landroid/graphics/drawable/Drawable;" since="19" />
+		<method name="getBuiltInDrawable(IIZFF)Landroid/graphics/drawable/Drawable;" since="19" />
+		<method name="getCropAndSetWallpaperIntent(Landroid/net/Uri;)Landroid/content/Intent;" since="19" />
 		<method name="getDesiredMinimumHeight()I" />
 		<method name="getDesiredMinimumWidth()I" />
 		<method name="getDrawable()Landroid/graphics/drawable/Drawable;" />
@@ -4211,6 +4316,7 @@
 		<method name="setWallpaperOffsets(Landroid/os/IBinder;FF)V" />
 		<method name="suggestDesiredDimensions(II)V" />
 		<field name="ACTION_CHANGE_LIVE_WALLPAPER" since="16" />
+		<field name="ACTION_CROP_AND_SET_WALLPAPER" since="19" />
 		<field name="ACTION_LIVE_WALLPAPER_CHOOSER" since="7" />
 		<field name="COMMAND_DROP" since="7" />
 		<field name="COMMAND_SECONDARY_TAP" since="11" />
@@ -4592,79 +4698,168 @@
 		<extends name="java/lang/Object" />
 		<method name="onLeScan(Landroid/bluetooth/BluetoothDevice;I[B)V" />
 	</class>
-	<class name="android/bluetooth/BluetoothAdapterCallback" since="18">
-		<extends name="java/lang/Object" />
-		<method name="&lt;init>()V" />
-		<method name="onCallbackRegistration(I)V" />
-		<method name="onLeScan(Landroid/bluetooth/BluetoothDevice;I[B)V" />
-		<field name="CALLBACK_REGISTERED" />
-		<field name="CALLBACK_REGISTRATION_FAILURE" />
-	</class>
 	<class name="android/bluetooth/BluetoothAssignedNumbers" since="11">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
+		<field name="AAMP_OF_AMERICA" since="19" />
 		<field name="ACCEL_SEMICONDUCTOR" />
+		<field name="ACE_SENSOR" since="19" />
+		<field name="ADIDAS" since="19" />
+		<field name="ADVANCED_PANMOBIL_SYSTEMS" since="19" />
+		<field name="AIROHA_TECHNOLOGY" since="19" />
 		<field name="ALCATEL" />
+		<field name="ALPWISE" since="19" />
+		<field name="AMICCOM_ELECTRONICS" since="19" />
+		<field name="APLIX" since="19" />
 		<field name="APPLE" />
 		<field name="APT_LICENSING" />
+		<field name="ARCHOS" since="19" />
+		<field name="ARP_DEVICES" since="19" />
 		<field name="ATHEROS_COMMUNICATIONS" />
 		<field name="ATMEL" />
+		<field name="AUSTCO_COMMUNICATION_SYSTEMS" since="19" />
+		<field name="AUTONET_MOBILE" since="19" />
 		<field name="AVAGO" />
 		<field name="AVM_BERLIN" />
+		<field name="A_AND_D_ENGINEERING" since="19" />
+		<field name="A_AND_R_CAMBRIDGE" since="19" />
 		<field name="BANDSPEED" />
+		<field name="BAND_XI_INTERNATIONAL" since="19" />
+		<field name="BDE_TECHNOLOGY" since="19" />
+		<field name="BEATS_ELECTRONICS" since="19" />
+		<field name="BEAUTIFUL_ENTERPRISE" since="19" />
+		<field name="BEKEY" since="19" />
 		<field name="BELKIN_INTERNATIONAL" />
+		<field name="BINAURIC" since="19" />
+		<field name="BIOSENTRONICS" since="19" />
 		<field name="BLUEGIGA" />
+		<field name="BLUERADIOS" since="19" />
 		<field name="BLUETOOTH_SIG" />
+		<field name="BLUETREK_TECHNOLOGIES" since="19" />
+		<field name="BOSE" since="19" />
+		<field name="BRIARTEK" since="19" />
 		<field name="BROADCOM" />
+		<field name="CAEN_RFID" since="19" />
 		<field name="CAMBRIDGE_SILICON_RADIO" />
 		<field name="CATC" />
+		<field name="CINETIX" since="19" />
+		<field name="CLARINOX_TECHNOLOGIES" since="19" />
+		<field name="COLORFY" since="19" />
 		<field name="COMMIL" />
 		<field name="CONEXANT_SYSTEMS" />
+		<field name="CONNECTBLUE" since="19" />
 		<field name="CONTINENTAL_AUTOMOTIVE" />
 		<field name="CONWISE_TECHNOLOGY" />
+		<field name="CREATIVE_TECHNOLOGY" since="19" />
 		<field name="C_TECHNOLOGIES" />
+		<field name="DANLERS" since="19" />
+		<field name="DELORME_PUBLISHING_COMPANY" since="19" />
+		<field name="DEXCOM" since="19" />
+		<field name="DIALOG_SEMICONDUCTOR" since="19" />
 		<field name="DIGIANSWER" />
 		<field name="ECLIPSE" />
+		<field name="ECOTEST" since="19" />
+		<field name="ELGATO_SYSTEMS" since="19" />
 		<field name="EM_MICROELECTRONIC_MARIN" />
+		<field name="EQUINOX_AG" since="19" />
 		<field name="ERICSSON_TECHNOLOGY" />
+		<field name="EVLUMA" since="19" />
 		<field name="FREE2MOVE" />
+		<field name="FUNAI_ELECTRIC" since="19" />
+		<field name="GARMIN_INTERNATIONAL" since="19" />
 		<field name="GCT_SEMICONDUCTOR" />
+		<field name="GELO" since="19" />
+		<field name="GENEQ" since="19" />
+		<field name="GENERAL_MOTORS" since="19" />
 		<field name="GENNUM" />
+		<field name="GEOFORCE" since="19" />
+		<field name="GIBSON_GUITARS" since="19" />
+		<field name="GN_NETCOM" since="19" />
+		<field name="GN_RESOUND" since="19" />
+		<field name="GOOGLE" since="19" />
+		<field name="GREEN_THROTTLE_GAMES" since="19" />
+		<field name="GROUP_SENSE" since="19" />
+		<field name="HANLYNN_TECHNOLOGIES" since="19" />
 		<field name="HARMAN_INTERNATIONAL" />
+		<field name="HEWLETT_PACKARD" since="19" />
 		<field name="HITACHI" />
+		<field name="HOSIDEN" since="19" />
 		<field name="IBM" />
 		<field name="INFINEON_TECHNOLOGIES" />
+		<field name="INGENIEUR_SYSTEMGRUPPE_ZAHN" since="19" />
 		<field name="INTEGRATED_SILICON_SOLUTION" />
 		<field name="INTEGRATED_SYSTEM_SOLUTION" />
 		<field name="INTEL" />
 		<field name="INVENTEL" />
 		<field name="IPEXTREME" />
+		<field name="I_TECH_DYNAMIC_GLOBAL_DISTRIBUTION" since="19" />
+		<field name="JAWBONE" since="19" />
+		<field name="JIANGSU_TOPPOWER_AUTOMOTIVE_ELECTRONICS" since="19" />
+		<field name="JOHNSON_CONTROLS" since="19" />
 		<field name="J_AND_M" />
+		<field name="KAWANTECH" since="19" />
 		<field name="KC_TECHNOLOGY" />
+		<field name="KENSINGTON_COMPUTER_PRODUCTS_GROUP" since="19" />
+		<field name="LAIRD_TECHNOLOGIES" since="19" />
+		<field name="LESSWIRE" since="19" />
+		<field name="LG_ELECTRONICS" since="19" />
+		<field name="LINAK" since="19" />
 		<field name="LUCENT" />
+		<field name="LUDUS_HELSINKI" since="19" />
 		<field name="MACRONIX" />
+		<field name="MAGNETI_MARELLI" since="19" />
 		<field name="MANSELLA" />
 		<field name="MARVELL" />
 		<field name="MATSUSHITA_ELECTRIC" />
+		<field name="MC10" since="19" />
 		<field name="MEDIATEK" />
+		<field name="MESO_INTERNATIONAL" since="19" />
+		<field name="META_WATCH" since="19" />
 		<field name="MEWTEL_TECHNOLOGY" />
+		<field name="MICOMMAND" since="19" />
+		<field name="MICROCHIP_TECHNOLOGY" since="19" />
 		<field name="MICROSOFT" />
+		<field name="MINDTREE" since="19" />
+		<field name="MISFIT_WEARABLES" since="19" />
 		<field name="MITEL_SEMICONDUCTOR" />
 		<field name="MITSUBISHI_ELECTRIC" />
 		<field name="MOBILIAN_CORPORATION" />
+		<field name="MONSTER" since="19" />
 		<field name="MOTOROLA" />
+		<field name="MSTAR_SEMICONDUCTOR" since="19" />
+		<field name="MUZIK" since="19" />
 		<field name="NEC" />
+		<field name="NEC_LIGHTING" since="19" />
 		<field name="NEWLOGIC" />
+		<field name="NIKE" since="19" />
+		<field name="NINE_SOLUTIONS" since="19" />
 		<field name="NOKIA_MOBILE_PHONES" />
 		<field name="NORDIC_SEMICONDUCTOR" />
 		<field name="NORWOOD_SYSTEMS" />
+		<field name="ODM_TECHNOLOGY" since="19" />
+		<field name="OMEGAWAVE" since="19" />
+		<field name="ONSET_COMPUTER" since="19" />
 		<field name="OPEN_INTERFACE" />
+		<field name="OTL_DYNAMICS" since="19" />
+		<field name="PANDA_OCEAN" since="19" />
 		<field name="PARROT" />
 		<field name="PARTHUS_TECHNOLOGIES" />
+		<field name="PASSIF_SEMICONDUCTOR" since="19" />
+		<field name="PETER_SYSTEMTECHNIK" since="19" />
 		<field name="PHILIPS_SEMICONDUCTORS" />
 		<field name="PLANTRONICS" />
+		<field name="POLAR_ELECTRO" since="19" />
+		<field name="POLAR_ELECTRO_EUROPE" since="19" />
+		<field name="PROCTER_AND_GAMBLE" since="19" />
 		<field name="QUALCOMM" />
+		<field name="QUALCOMM_CONNECTED_EXPERIENCES" since="19" />
+		<field name="QUALCOMM_INNOVATION_CENTER" since="19" />
+		<field name="QUALCOMM_LABS" since="19" />
+		<field name="QUALCOMM_TECHNOLOGIES" since="19" />
+		<field name="QUINTIC" since="19" />
+		<field name="QUUPPA" since="19" />
 		<field name="RALINK_TECHNOLOGY" />
+		<field name="RDA_MICROELECTRONICS" since="19" />
 		<field name="REALTEK_SEMICONDUCTOR" />
 		<field name="RED_M" />
 		<field name="RENESAS_TECHNOLOGY" />
@@ -4673,33 +4868,66 @@
 		<field name="RIVIERAWAVES" />
 		<field name="ROHDE_AND_SCHWARZ" />
 		<field name="RTX_TELECOM" />
+		<field name="SAMSUNG_ELECTRONICS" since="19" />
+		<field name="SARIS_CYCLING_GROUP" since="19" />
+		<field name="SEERS_TECHNOLOGY" since="19" />
 		<field name="SEIKO_EPSON" />
+		<field name="SELFLY" since="19" />
+		<field name="SEMILINK" since="19" />
+		<field name="SENNHEISER_COMMUNICATIONS" since="19" />
+		<field name="SHANGHAI_SUPER_SMART_ELECTRONICS" since="19" />
+		<field name="SHENZHEN_EXCELSECU_DATA_TECHNOLOGY" since="19" />
 		<field name="SIGNIA_TECHNOLOGIES" />
 		<field name="SILICON_WAVE" />
 		<field name="SIRF_TECHNOLOGY" />
 		<field name="SOCKET_MOBILE" />
 		<field name="SONY_ERICSSON" />
+		<field name="SOUND_ID" since="19" />
+		<field name="SPORTS_TRACKING_TECHNOLOGIES" since="19" />
+		<field name="SR_MEDIZINELEKTRONIK" since="19" />
 		<field name="STACCATO_COMMUNICATIONS" />
+		<field name="STALMART_TECHNOLOGY" since="19" />
+		<field name="STARKEY_LABORATORIES" since="19" />
+		<field name="STOLLMAN_E_PLUS_V" since="19" />
 		<field name="STONESTREET_ONE" />
 		<field name="ST_MICROELECTRONICS" />
+		<field name="SUMMIT_DATA_COMMUNICATIONS" since="19" />
+		<field name="SUUNTO" since="19" />
+		<field name="SWIRL_NETWORKS" since="19" />
 		<field name="SYMBOL_TECHNOLOGIES" />
 		<field name="SYNOPSYS" />
 		<field name="SYSTEMS_AND_CHIPS" />
+		<field name="S_POWER_ELECTRONICS" since="19" />
+		<field name="TAIXINGBANG_TECHNOLOGY" since="19" />
 		<field name="TENOVIS" />
 		<field name="TERAX" />
 		<field name="TEXAS_INSTRUMENTS" />
+		<field name="THINKOPTICS" since="19" />
 		<field name="THREECOM" />
 		<field name="THREE_DIJOY" />
 		<field name="THREE_DSP" />
+		<field name="TIMEKEEPING_SYSTEMS" since="19" />
+		<field name="TIMEX_GROUP_USA" since="19" />
+		<field name="TOPCORN_POSITIONING_SYSTEMS" since="19" />
 		<field name="TOSHIBA" />
 		<field name="TRANSILICA" />
+		<field name="TRELAB" since="19" />
 		<field name="TTPCOM" />
+		<field name="TXTR" since="19" />
 		<field name="TZERO_TECHNOLOGIES" />
+		<field name="UNIVERSAL_ELECTRONICS" since="19" />
+		<field name="VERTU" since="19" />
+		<field name="VISTEON" since="19" />
 		<field name="VIZIO" />
+		<field name="VOYETRA_TURTLE_BEACH" since="19" />
 		<field name="WAVEPLUS_TECHNOLOGY" />
 		<field name="WICENTRIC" />
 		<field name="WIDCOMM" />
+		<field name="WUXI_VIMICRO" since="19" />
 		<field name="ZEEVO" />
+		<field name="ZER01_TV" since="19" />
+		<field name="ZOMM" since="19" />
+		<field name="ZSCAN_SOFTWARE" since="19" />
 	</class>
 	<class name="android/bluetooth/BluetoothClass" since="5">
 		<extends name="java/lang/Object" />
@@ -4797,6 +5025,7 @@
 		<implements name="android/os/Parcelable" />
 		<method name="&lt;init>()V" />
 		<method name="connectGatt(Landroid/content/Context;ZLandroid/bluetooth/BluetoothGattCallback;)Landroid/bluetooth/BluetoothGatt;" since="18" />
+		<method name="createBond()Z" since="19" />
 		<method name="createInsecureRfcommSocketToServiceRecord(Ljava/util/UUID;)Landroid/bluetooth/BluetoothSocket;" since="10" />
 		<method name="createRfcommSocketToServiceRecord(Ljava/util/UUID;)Landroid/bluetooth/BluetoothSocket;" />
 		<method name="fetchUuidsWithSdp()Z" since="15" />
@@ -4806,6 +5035,8 @@
 		<method name="getName()Ljava/lang/String;" />
 		<method name="getType()I" since="18" />
 		<method name="getUuids()[Landroid/os/ParcelUuid;" since="15" />
+		<method name="setPairingConfirmation(Z)Z" since="19" />
+		<method name="setPin([B)Z" since="19" />
 		<field name="ACTION_ACL_CONNECTED" />
 		<field name="ACTION_ACL_DISCONNECTED" />
 		<field name="ACTION_ACL_DISCONNECT_REQUESTED" />
@@ -4813,6 +5044,7 @@
 		<field name="ACTION_CLASS_CHANGED" />
 		<field name="ACTION_FOUND" />
 		<field name="ACTION_NAME_CHANGED" />
+		<field name="ACTION_PAIRING_REQUEST" since="19" />
 		<field name="ACTION_UUID" since="15" />
 		<field name="BOND_BONDED" />
 		<field name="BOND_BONDING" />
@@ -4827,14 +5059,19 @@
 		<field name="EXTRA_CLASS" />
 		<field name="EXTRA_DEVICE" />
 		<field name="EXTRA_NAME" />
+		<field name="EXTRA_PAIRING_KEY" since="19" />
+		<field name="EXTRA_PAIRING_VARIANT" since="19" />
 		<field name="EXTRA_PREVIOUS_BOND_STATE" />
 		<field name="EXTRA_RSSI" />
 		<field name="EXTRA_UUID" since="15" />
+		<field name="PAIRING_VARIANT_PASSKEY_CONFIRMATION" since="19" />
+		<field name="PAIRING_VARIANT_PIN" since="19" />
 	</class>
 	<class name="android/bluetooth/BluetoothGatt" since="18">
 		<extends name="java/lang/Object" />
 		<implements name="android/bluetooth/BluetoothProfile" />
 		<method name="&lt;init>()V" />
+		<method name="abortReliableWrite()V" since="19" />
 		<method name="abortReliableWrite(Landroid/bluetooth/BluetoothDevice;)V" />
 		<method name="beginReliableWrite()Z" />
 		<method name="close()V" />
@@ -4991,6 +5228,7 @@
 		<implements name="android/bluetooth/BluetoothProfile" />
 		<method name="&lt;init>()V" />
 		<method name="isAudioConnected(Landroid/bluetooth/BluetoothDevice;)Z" />
+		<method name="sendVendorSpecificResultCode(Landroid/bluetooth/BluetoothDevice;Ljava/lang/String;Ljava/lang/String;)Z" since="19" />
 		<method name="startVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z" />
 		<method name="stopVoiceRecognition(Landroid/bluetooth/BluetoothDevice;)Z" />
 		<field name="ACTION_AUDIO_STATE_CHANGED" />
@@ -5007,6 +5245,7 @@
 		<field name="STATE_AUDIO_CONNECTED" />
 		<field name="STATE_AUDIO_CONNECTING" />
 		<field name="STATE_AUDIO_DISCONNECTED" />
+		<field name="VENDOR_RESULT_CODE_COMMAND_ANDROID" since="19" />
 		<field name="VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY" />
 	</class>
 	<class name="android/bluetooth/BluetoothHealth" since="14">
@@ -5301,8 +5540,10 @@
 		<method name="attachInfo(Landroid/content/Context;Landroid/content/pm/ProviderInfo;)V" />
 		<method name="bulkInsert(Landroid/net/Uri;[Landroid/content/ContentValues;)I" />
 		<method name="call(Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;" since="11" />
+		<method name="canonicalize(Landroid/net/Uri;)Landroid/net/Uri;" since="19" />
 		<method name="delete(Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I" />
 		<method name="dump(Ljava/io/FileDescriptor;Ljava/io/PrintWriter;[Ljava/lang/String;)V" since="18" />
+		<method name="getCallingPackage()Ljava/lang/String;" since="19" />
 		<method name="getContext()Landroid/content/Context;" />
 		<method name="getPathPermissions()[Landroid/content/pm/PathPermission;" since="4" />
 		<method name="getReadPermission()Ljava/lang/String;" />
@@ -5313,16 +5554,20 @@
 		<method name="isTemporary()Z" />
 		<method name="onCreate()Z" />
 		<method name="openAssetFile(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;" since="3" />
+		<method name="openAssetFile(Landroid/net/Uri;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/content/res/AssetFileDescriptor;" since="19" />
 		<method name="openFile(Landroid/net/Uri;Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;" />
+		<method name="openFile(Landroid/net/Uri;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/os/ParcelFileDescriptor;" since="19" />
 		<method name="openFileHelper(Landroid/net/Uri;Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;" />
 		<method name="openPipeHelper(Landroid/net/Uri;Ljava/lang/String;Landroid/os/Bundle;Ljava/lang/Object;Landroid/content/ContentProvider$PipeDataWriter;)Landroid/os/ParcelFileDescriptor;" since="11" />
 		<method name="openTypedAssetFile(Landroid/net/Uri;Ljava/lang/String;Landroid/os/Bundle;)Landroid/content/res/AssetFileDescriptor;" since="11" />
+		<method name="openTypedAssetFile(Landroid/net/Uri;Ljava/lang/String;Landroid/os/Bundle;Landroid/os/CancellationSignal;)Landroid/content/res/AssetFileDescriptor;" since="19" />
 		<method name="query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;" />
 		<method name="query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/database/Cursor;" since="16" />
 		<method name="setPathPermissions([Landroid/content/pm/PathPermission;)V" since="4" />
 		<method name="setReadPermission(Ljava/lang/String;)V" />
 		<method name="setWritePermission(Ljava/lang/String;)V" />
 		<method name="shutdown()V" since="11" />
+		<method name="uncanonicalize(Landroid/net/Uri;)Landroid/net/Uri;" since="19" />
 		<method name="update(Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I" />
 	</class>
 	<class name="android/content/ContentProvider$PipeDataWriter" since="11">
@@ -5335,17 +5580,22 @@
 		<method name="applyBatch(Ljava/util/ArrayList;)[Landroid/content/ContentProviderResult;" />
 		<method name="bulkInsert(Landroid/net/Uri;[Landroid/content/ContentValues;)I" />
 		<method name="call(Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;" since="17" />
+		<method name="canonicalize(Landroid/net/Uri;)Landroid/net/Uri;" since="19" />
 		<method name="delete(Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I" />
 		<method name="getLocalContentProvider()Landroid/content/ContentProvider;" />
 		<method name="getStreamTypes(Landroid/net/Uri;Ljava/lang/String;)[Ljava/lang/String;" since="11" />
 		<method name="getType(Landroid/net/Uri;)Ljava/lang/String;" />
 		<method name="insert(Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;" />
 		<method name="openAssetFile(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;" />
+		<method name="openAssetFile(Landroid/net/Uri;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/content/res/AssetFileDescriptor;" since="19" />
 		<method name="openFile(Landroid/net/Uri;Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;" />
+		<method name="openFile(Landroid/net/Uri;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/os/ParcelFileDescriptor;" since="19" />
 		<method name="openTypedAssetFileDescriptor(Landroid/net/Uri;Ljava/lang/String;Landroid/os/Bundle;)Landroid/content/res/AssetFileDescriptor;" since="11" />
+		<method name="openTypedAssetFileDescriptor(Landroid/net/Uri;Ljava/lang/String;Landroid/os/Bundle;Landroid/os/CancellationSignal;)Landroid/content/res/AssetFileDescriptor;" since="19" />
 		<method name="query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;" />
 		<method name="query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/database/Cursor;" since="16" />
 		<method name="release()Z" />
+		<method name="uncanonicalize(Landroid/net/Uri;)Landroid/net/Uri;" since="19" />
 		<method name="update(Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I" />
 	</class>
 	<class name="android/content/ContentProviderOperation" since="5">
@@ -5411,12 +5661,15 @@
 		<method name="call(Landroid/net/Uri;Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;" since="11" />
 		<method name="cancelSync(Landroid/accounts/Account;Ljava/lang/String;)V" since="5" />
 		<method name="cancelSync(Landroid/net/Uri;)V" />
+		<method name="canonicalize(Landroid/net/Uri;)Landroid/net/Uri;" since="19" />
 		<method name="delete(Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I" />
 		<method name="getCurrentSync()Landroid/content/SyncInfo;" since="8" />
 		<method name="getCurrentSyncs()Ljava/util/List;" since="11" />
 		<method name="getIsSyncable(Landroid/accounts/Account;Ljava/lang/String;)I" since="5" />
 		<method name="getMasterSyncAutomatically()Z" since="5" />
+		<method name="getOutgoingPersistedUriPermissions()Ljava/util/List;" since="19" />
 		<method name="getPeriodicSyncs(Landroid/accounts/Account;Ljava/lang/String;)Ljava/util/List;" since="8" />
+		<method name="getPersistedUriPermissions()Ljava/util/List;" since="19" />
 		<method name="getStreamTypes(Landroid/net/Uri;Ljava/lang/String;)[Ljava/lang/String;" since="11" />
 		<method name="getSyncAdapterTypes()[Landroid/content/SyncAdapterType;" since="5" />
 		<method name="getSyncAutomatically(Landroid/accounts/Account;Ljava/lang/String;)Z" since="5" />
@@ -5427,21 +5680,28 @@
 		<method name="notifyChange(Landroid/net/Uri;Landroid/database/ContentObserver;)V" />
 		<method name="notifyChange(Landroid/net/Uri;Landroid/database/ContentObserver;Z)V" />
 		<method name="openAssetFileDescriptor(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;" since="3" />
+		<method name="openAssetFileDescriptor(Landroid/net/Uri;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/content/res/AssetFileDescriptor;" since="19" />
 		<method name="openFileDescriptor(Landroid/net/Uri;Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;" />
+		<method name="openFileDescriptor(Landroid/net/Uri;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/os/ParcelFileDescriptor;" since="19" />
 		<method name="openInputStream(Landroid/net/Uri;)Ljava/io/InputStream;" />
 		<method name="openOutputStream(Landroid/net/Uri;)Ljava/io/OutputStream;" />
 		<method name="openOutputStream(Landroid/net/Uri;Ljava/lang/String;)Ljava/io/OutputStream;" since="3" />
 		<method name="openTypedAssetFileDescriptor(Landroid/net/Uri;Ljava/lang/String;Landroid/os/Bundle;)Landroid/content/res/AssetFileDescriptor;" since="11" />
+		<method name="openTypedAssetFileDescriptor(Landroid/net/Uri;Ljava/lang/String;Landroid/os/Bundle;Landroid/os/CancellationSignal;)Landroid/content/res/AssetFileDescriptor;" since="19" />
 		<method name="query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;" />
 		<method name="query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/database/Cursor;" since="16" />
 		<method name="registerContentObserver(Landroid/net/Uri;ZLandroid/database/ContentObserver;)V" />
+		<method name="releasePersistableUriPermission(Landroid/net/Uri;I)V" since="19" />
 		<method name="removePeriodicSync(Landroid/accounts/Account;Ljava/lang/String;Landroid/os/Bundle;)V" since="8" />
 		<method name="removeStatusChangeListener(Ljava/lang/Object;)V" since="5" />
 		<method name="requestSync(Landroid/accounts/Account;Ljava/lang/String;Landroid/os/Bundle;)V" since="5" />
+		<method name="requestSync(Landroid/content/SyncRequest;)V" since="19" />
 		<method name="setIsSyncable(Landroid/accounts/Account;Ljava/lang/String;I)V" since="5" />
 		<method name="setMasterSyncAutomatically(Z)V" since="5" />
 		<method name="setSyncAutomatically(Landroid/accounts/Account;Ljava/lang/String;Z)V" since="5" />
 		<method name="startSync(Landroid/net/Uri;Landroid/os/Bundle;)V" />
+		<method name="takePersistableUriPermission(Landroid/net/Uri;I)V" since="19" />
+		<method name="uncanonicalize(Landroid/net/Uri;)Landroid/net/Uri;" since="19" />
 		<method name="unregisterContentObserver(Landroid/database/ContentObserver;)V" />
 		<method name="update(Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I" />
 		<method name="validateSyncExtrasBundle(Landroid/os/Bundle;)V" />
@@ -5543,11 +5803,14 @@
 		<method name="getDatabasePath(Ljava/lang/String;)Ljava/io/File;" />
 		<method name="getDir(Ljava/lang/String;I)Ljava/io/File;" />
 		<method name="getExternalCacheDir()Ljava/io/File;" since="8" />
+		<method name="getExternalCacheDirs()[Ljava/io/File;" since="19" />
 		<method name="getExternalFilesDir(Ljava/lang/String;)Ljava/io/File;" since="8" />
+		<method name="getExternalFilesDirs(Ljava/lang/String;)[Ljava/io/File;" since="19" />
 		<method name="getFileStreamPath(Ljava/lang/String;)Ljava/io/File;" />
 		<method name="getFilesDir()Ljava/io/File;" />
 		<method name="getMainLooper()Landroid/os/Looper;" />
 		<method name="getObbDir()Ljava/io/File;" since="11" />
+		<method name="getObbDirs()[Ljava/io/File;" since="19" />
 		<method name="getPackageCodePath()Ljava/lang/String;" since="8" />
 		<method name="getPackageManager()Landroid/content/pm/PackageManager;" />
 		<method name="getPackageName()Ljava/lang/String;" />
@@ -5609,6 +5872,7 @@
 		<field name="ACCOUNT_SERVICE" since="5" />
 		<field name="ACTIVITY_SERVICE" />
 		<field name="ALARM_SERVICE" />
+		<field name="APP_OPS_SERVICE" since="19" />
 		<field name="AUDIO_SERVICE" />
 		<field name="BIND_ABOVE_CLIENT" since="14" />
 		<field name="BIND_ADJUST_WITH_ACTIVITY" since="14" />
@@ -5619,8 +5883,10 @@
 		<field name="BIND_NOT_FOREGROUND" since="8" />
 		<field name="BIND_WAIVE_PRIORITY" since="14" />
 		<field name="BLUETOOTH_SERVICE" since="18" />
+		<field name="CAPTIONING_SERVICE" since="19" />
 		<field name="CLIPBOARD_SERVICE" />
 		<field name="CONNECTIVITY_SERVICE" />
+		<field name="CONSUMER_IR_SERVICE" since="19" />
 		<field name="CONTEXT_IGNORE_SECURITY" />
 		<field name="CONTEXT_INCLUDE_CODE" />
 		<field name="CONTEXT_RESTRICTED" since="4" />
@@ -5644,6 +5910,7 @@
 		<field name="NOTIFICATION_SERVICE" />
 		<field name="NSD_SERVICE" since="16" />
 		<field name="POWER_SERVICE" />
+		<field name="PRINT_SERVICE" since="19" />
 		<field name="SEARCH_SERVICE" />
 		<field name="SENSOR_SERVICE" />
 		<field name="STORAGE_SERVICE" since="9" />
@@ -5883,6 +6150,7 @@
 		<field name="ACTION_CHOOSER" />
 		<field name="ACTION_CLOSE_SYSTEM_DIALOGS" />
 		<field name="ACTION_CONFIGURATION_CHANGED" />
+		<field name="ACTION_CREATE_DOCUMENT" since="19" />
 		<field name="ACTION_CREATE_SHORTCUT" />
 		<field name="ACTION_DATE_CHANGED" />
 		<field name="ACTION_DEFAULT" />
@@ -5925,6 +6193,7 @@
 		<field name="ACTION_MEDIA_UNMOUNTED" />
 		<field name="ACTION_MY_PACKAGE_REPLACED" since="12" />
 		<field name="ACTION_NEW_OUTGOING_CALL" />
+		<field name="ACTION_OPEN_DOCUMENT" since="19" />
 		<field name="ACTION_PACKAGE_ADDED" />
 		<field name="ACTION_PACKAGE_CHANGED" />
 		<field name="ACTION_PACKAGE_DATA_CLEARED" since="3" />
@@ -6033,6 +6302,7 @@
 		<field name="EXTRA_INTENT" />
 		<field name="EXTRA_KEY_EVENT" />
 		<field name="EXTRA_LOCAL_ONLY" since="11" />
+		<field name="EXTRA_MIME_TYPES" since="19" />
 		<field name="EXTRA_NOT_UNKNOWN_SOURCE" since="14" />
 		<field name="EXTRA_ORIGINATING_URI" since="17" />
 		<field name="EXTRA_PHONE_NUMBER" />
@@ -6047,6 +6317,7 @@
 		<field name="EXTRA_SHORTCUT_ICON_RESOURCE" />
 		<field name="EXTRA_SHORTCUT_INTENT" />
 		<field name="EXTRA_SHORTCUT_NAME" />
+		<field name="EXTRA_SHUTDOWN_USERSPACE_ONLY" since="19" />
 		<field name="EXTRA_STREAM" />
 		<field name="EXTRA_SUBJECT" />
 		<field name="EXTRA_TEMPLATE" />
@@ -6081,10 +6352,12 @@
 		<field name="FLAG_DEBUG_LOG_RESOLUTION" />
 		<field name="FLAG_EXCLUDE_STOPPED_PACKAGES" since="12" />
 		<field name="FLAG_FROM_BACKGROUND" />
+		<field name="FLAG_GRANT_PERSISTABLE_URI_PERMISSION" since="19" />
 		<field name="FLAG_GRANT_READ_URI_PERMISSION" />
 		<field name="FLAG_GRANT_WRITE_URI_PERMISSION" />
 		<field name="FLAG_INCLUDE_STOPPED_PACKAGES" since="12" />
 		<field name="FLAG_RECEIVER_FOREGROUND" since="16" />
+		<field name="FLAG_RECEIVER_NO_ABORT" since="19" />
 		<field name="FLAG_RECEIVER_REGISTERED_ONLY" />
 		<field name="FLAG_RECEIVER_REPLACE_PENDING" since="8" />
 		<field name="METADATA_DOCK_HOME" since="5" />
@@ -6117,6 +6390,7 @@
 		<method name="addDataAuthority(Ljava/lang/String;Ljava/lang/String;)V" />
 		<method name="addDataPath(Ljava/lang/String;I)V" />
 		<method name="addDataScheme(Ljava/lang/String;)V" />
+		<method name="addDataSchemeSpecificPart(Ljava/lang/String;I)V" since="19" />
 		<method name="addDataType(Ljava/lang/String;)V" />
 		<method name="authoritiesIterator()Ljava/util/Iterator;" />
 		<method name="categoriesIterator()Ljava/util/Iterator;" />
@@ -6124,6 +6398,7 @@
 		<method name="countCategories()I" />
 		<method name="countDataAuthorities()I" />
 		<method name="countDataPaths()I" />
+		<method name="countDataSchemeSpecificParts()I" since="19" />
 		<method name="countDataSchemes()I" />
 		<method name="countDataTypes()I" />
 		<method name="create(Ljava/lang/String;Ljava/lang/String;)Landroid/content/IntentFilter;" />
@@ -6133,6 +6408,7 @@
 		<method name="getDataAuthority(I)Landroid/content/IntentFilter$AuthorityEntry;" />
 		<method name="getDataPath(I)Landroid/os/PatternMatcher;" />
 		<method name="getDataScheme(I)Ljava/lang/String;" />
+		<method name="getDataSchemeSpecificPart(I)Landroid/os/PatternMatcher;" since="19" />
 		<method name="getDataType(I)Ljava/lang/String;" />
 		<method name="getPriority()I" />
 		<method name="hasAction(Ljava/lang/String;)Z" />
@@ -6140,6 +6416,7 @@
 		<method name="hasDataAuthority(Landroid/net/Uri;)Z" />
 		<method name="hasDataPath(Ljava/lang/String;)Z" />
 		<method name="hasDataScheme(Ljava/lang/String;)Z" />
+		<method name="hasDataSchemeSpecificPart(Ljava/lang/String;)Z" since="19" />
 		<method name="hasDataType(Ljava/lang/String;)Z" />
 		<method name="match(Landroid/content/ContentResolver;Landroid/content/Intent;ZLjava/lang/String;)I" />
 		<method name="match(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/net/Uri;Ljava/util/Set;Ljava/lang/String;)I" />
@@ -6149,6 +6426,7 @@
 		<method name="matchDataAuthority(Landroid/net/Uri;)I" />
 		<method name="pathsIterator()Ljava/util/Iterator;" />
 		<method name="readFromXml(Lorg/xmlpull/v1/XmlPullParser;)V" />
+		<method name="schemeSpecificPartsIterator()Ljava/util/Iterator;" since="19" />
 		<method name="schemesIterator()Ljava/util/Iterator;" />
 		<method name="setPriority(I)V" />
 		<method name="typesIterator()Ljava/util/Iterator;" />
@@ -6162,6 +6440,7 @@
 		<field name="MATCH_CATEGORY_PATH" />
 		<field name="MATCH_CATEGORY_PORT" />
 		<field name="MATCH_CATEGORY_SCHEME" />
+		<field name="MATCH_CATEGORY_SCHEME_SPECIFIC_PART" since="19" />
 		<field name="MATCH_CATEGORY_TYPE" />
 		<field name="NO_MATCH_ACTION" />
 		<field name="NO_MATCH_CATEGORY" />
@@ -6385,6 +6664,27 @@
 		<field name="authority" />
 		<field name="startTime" />
 	</class>
+	<class name="android/content/SyncRequest" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>()V" />
+		<field name="CREATOR" />
+	</class>
+	<class name="android/content/SyncRequest$Builder" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="build()Landroid/content/SyncRequest;" />
+		<method name="setDisallowMetered(Z)Landroid/content/SyncRequest$Builder;" />
+		<method name="setExpedited(Z)Landroid/content/SyncRequest$Builder;" />
+		<method name="setExtras(Landroid/os/Bundle;)Landroid/content/SyncRequest$Builder;" />
+		<method name="setIgnoreBackoff(Z)Landroid/content/SyncRequest$Builder;" />
+		<method name="setIgnoreSettings(Z)Landroid/content/SyncRequest$Builder;" />
+		<method name="setManual(Z)Landroid/content/SyncRequest$Builder;" />
+		<method name="setNoRetry(Z)Landroid/content/SyncRequest$Builder;" />
+		<method name="setSyncAdapter(Landroid/accounts/Account;Ljava/lang/String;)Landroid/content/SyncRequest$Builder;" />
+		<method name="syncOnce()Landroid/content/SyncRequest$Builder;" />
+		<method name="syncPeriodic(JJ)Landroid/content/SyncRequest$Builder;" />
+	</class>
 	<class name="android/content/SyncResult" since="5">
 		<extends name="java/lang/Object" />
 		<implements name="android/os/Parcelable" />
@@ -6435,6 +6735,17 @@
 		<method name="match(Landroid/net/Uri;)I" />
 		<field name="NO_MATCH" />
 	</class>
+	<class name="android/content/UriPermission" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>()V" />
+		<method name="getPersistedTime()J" />
+		<method name="getUri()Landroid/net/Uri;" />
+		<method name="isReadPermission()Z" />
+		<method name="isWritePermission()Z" />
+		<field name="CREATOR" />
+		<field name="INVALID_TIME" />
+	</class>
 	<class name="android/content/pm/ActivityInfo" since="1">
 		<extends name="android/content/pm/ComponentInfo" />
 		<implements name="android/os/Parcelable" />
@@ -6570,6 +6881,7 @@
 		<method name="&lt;init>(Landroid/content/pm/ComponentInfo;)V" />
 		<method name="&lt;init>(Landroid/os/Parcel;)V" />
 		<method name="getIconResource()I" />
+		<method name="getLogoResource()I" since="19" />
 		<method name="isEnabled()Z" since="11" />
 		<field name="applicationInfo" />
 		<field name="descriptionRes" since="8" />
@@ -6762,6 +7074,7 @@
 		<method name="queryInstrumentation(Ljava/lang/String;I)Ljava/util/List;" />
 		<method name="queryIntentActivities(Landroid/content/Intent;I)Ljava/util/List;" />
 		<method name="queryIntentActivityOptions(Landroid/content/ComponentName;[Landroid/content/Intent;Landroid/content/Intent;I)Ljava/util/List;" />
+		<method name="queryIntentContentProviders(Landroid/content/Intent;I)Ljava/util/List;" since="19" />
 		<method name="queryIntentServices(Landroid/content/Intent;I)Ljava/util/List;" />
 		<method name="queryPermissionsByGroup(Ljava/lang/String;I)Ljava/util/List;" />
 		<method name="removePackageFromPreferred(Ljava/lang/String;)V" />
@@ -6790,6 +7103,8 @@
 		<field name="FEATURE_CAMERA_AUTOFOCUS" since="7" />
 		<field name="FEATURE_CAMERA_FLASH" since="7" />
 		<field name="FEATURE_CAMERA_FRONT" since="9" />
+		<field name="FEATURE_CONSUMER_IR" since="19" />
+		<field name="FEATURE_DEVICE_ADMIN" since="19" />
 		<field name="FEATURE_FAKETOUCH" since="11" />
 		<field name="FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT" since="13" />
 		<field name="FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND" since="13" />
@@ -6801,6 +7116,7 @@
 		<field name="FEATURE_LOCATION_NETWORK" since="8" />
 		<field name="FEATURE_MICROPHONE" since="8" />
 		<field name="FEATURE_NFC" since="9" />
+		<field name="FEATURE_NFC_HOST_CARD_EMULATION" since="19" />
 		<field name="FEATURE_SCREEN_LANDSCAPE" since="13" />
 		<field name="FEATURE_SCREEN_PORTRAIT" since="13" />
 		<field name="FEATURE_SENSOR_ACCELEROMETER" since="8" />
@@ -6809,6 +7125,8 @@
 		<field name="FEATURE_SENSOR_GYROSCOPE" since="9" />
 		<field name="FEATURE_SENSOR_LIGHT" since="7" />
 		<field name="FEATURE_SENSOR_PROXIMITY" since="7" />
+		<field name="FEATURE_SENSOR_STEP_COUNTER" since="19" />
+		<field name="FEATURE_SENSOR_STEP_DETECTOR" since="19" />
 		<field name="FEATURE_SIP" since="9" />
 		<field name="FEATURE_SIP_VOIP" since="9" />
 		<field name="FEATURE_TELEPHONY" since="7" />
@@ -6951,6 +7269,7 @@
 		<implements name="android/os/Parcelable" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Landroid/content/pm/ProviderInfo;)V" />
+		<method name="dump(Landroid/util/Printer;Ljava/lang/String;)V" since="19" />
 		<field name="CREATOR" />
 		<field name="FLAG_SINGLE_USER" since="17" />
 		<field name="authority" />
@@ -6983,6 +7302,7 @@
 		<field name="nonLocalizedLabel" />
 		<field name="preferredOrder" />
 		<field name="priority" />
+		<field name="providerInfo" since="19" />
 		<field name="resolvePackageName" since="5" />
 		<field name="serviceInfo" />
 		<field name="specificIndex" />
@@ -7020,11 +7340,14 @@
 	<class name="android/content/res/AssetFileDescriptor" since="1">
 		<extends name="java/lang/Object" />
 		<implements name="android/os/Parcelable" since="3" />
+		<implements name="java/io/Closeable" since="19" />
 		<method name="&lt;init>(Landroid/os/ParcelFileDescriptor;JJ)V" />
+		<method name="&lt;init>(Landroid/os/ParcelFileDescriptor;JJLandroid/os/Bundle;)V" since="19" />
 		<method name="close()V" />
 		<method name="createInputStream()Ljava/io/FileInputStream;" since="3" />
 		<method name="createOutputStream()Ljava/io/FileOutputStream;" since="3" />
 		<method name="getDeclaredLength()J" since="3" />
+		<method name="getExtras()Landroid/os/Bundle;" since="19" />
 		<method name="getFileDescriptor()Ljava/io/FileDescriptor;" />
 		<method name="getLength()J" />
 		<method name="getParcelFileDescriptor()Landroid/os/ParcelFileDescriptor;" />
@@ -7105,6 +7428,7 @@
 		<field name="KEYBOARD_NOKEYS" />
 		<field name="KEYBOARD_QWERTY" />
 		<field name="KEYBOARD_UNDEFINED" />
+		<field name="MNC_ZERO" since="19" />
 		<field name="NAVIGATIONHIDDEN_NO" since="5" />
 		<field name="NAVIGATIONHIDDEN_UNDEFINED" since="5" />
 		<field name="NAVIGATIONHIDDEN_YES" since="5" />
@@ -7286,6 +7610,7 @@
 	<class name="android/content/res/XmlResourceParser" since="1">
 		<extends name="java/lang/Object" />
 		<implements name="android/util/AttributeSet" />
+		<implements name="java/lang/AutoCloseable" since="19" />
 		<implements name="org/xmlpull/v1/XmlPullParser" />
 		<method name="close()V" />
 	</class>
@@ -7374,6 +7699,7 @@
 		<method name="getFloat(I)F" />
 		<method name="getInt(I)I" />
 		<method name="getLong(I)J" />
+		<method name="getNotificationUri()Landroid/net/Uri;" since="19" />
 		<method name="getPosition()I" />
 		<method name="getShort(I)S" />
 		<method name="getString(I)Ljava/lang/String;" />
@@ -7579,6 +7905,7 @@
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(Landroid/database/MatrixCursor;)V" />
 		<method name="add(Ljava/lang/Object;)Landroid/database/MatrixCursor$RowBuilder;" />
+		<method name="add(Ljava/lang/String;Ljava/lang/Object;)Landroid/database/MatrixCursor$RowBuilder;" since="19" />
 	</class>
 	<class name="android/database/MergeCursor" since="1">
 		<extends name="android/database/AbstractCursor" />
@@ -8315,6 +8642,7 @@
 		<method name="eraseColor(I)V" />
 		<method name="extractAlpha()Landroid/graphics/Bitmap;" />
 		<method name="extractAlpha(Landroid/graphics/Paint;[I)Landroid/graphics/Bitmap;" />
+		<method name="getAllocationByteCount()I" since="19" />
 		<method name="getByteCount()I" since="12" />
 		<method name="getConfig()Landroid/graphics/Bitmap$Config;" />
 		<method name="getDensity()I" since="4" />
@@ -8337,13 +8665,18 @@
 		<method name="isPremultiplied()Z" since="17" />
 		<method name="isRecycled()Z" />
 		<method name="prepareToDraw()V" since="4" />
+		<method name="reconfigure(IILandroid/graphics/Bitmap$Config;)V" since="19" />
 		<method name="recycle()V" />
 		<method name="sameAs(Landroid/graphics/Bitmap;)Z" since="12" />
+		<method name="setConfig(Landroid/graphics/Bitmap$Config;)V" since="19" />
 		<method name="setDensity(I)V" since="4" />
 		<method name="setHasAlpha(Z)V" since="12" />
 		<method name="setHasMipMap(Z)V" since="17" />
+		<method name="setHeight(I)V" since="19" />
 		<method name="setPixel(III)V" />
 		<method name="setPixels([IIIIIII)V" />
+		<method name="setPremultiplied(Z)V" since="19" />
+		<method name="setWidth(I)V" since="19" />
 		<field name="CREATOR" />
 		<field name="DENSITY_NONE" since="4" />
 	</class>
@@ -8391,6 +8724,7 @@
 		<field name="inMutable" since="11" />
 		<field name="inPreferQualityOverSpeed" since="10" />
 		<field name="inPreferredConfig" />
+		<field name="inPremultiplied" since="19" />
 		<field name="inPurgeable" since="4" />
 		<field name="inSampleSize" />
 		<field name="inScaled" since="4" />
@@ -8656,6 +8990,7 @@
 		<field name="NV21" />
 		<field name="RGB_565" />
 		<field name="UNKNOWN" />
+		<field name="YUV_420_888" since="19" />
 		<field name="YUY2" />
 		<field name="YV12" since="9" />
 	</class>
@@ -8784,12 +9119,16 @@
 	</class>
 	<class name="android/graphics/NinePatch" since="1">
 		<extends name="java/lang/Object" />
+		<method name="&lt;init>(Landroid/graphics/Bitmap;[B)V" since="19" />
 		<method name="&lt;init>(Landroid/graphics/Bitmap;[BLjava/lang/String;)V" />
 		<method name="draw(Landroid/graphics/Canvas;Landroid/graphics/Rect;)V" />
 		<method name="draw(Landroid/graphics/Canvas;Landroid/graphics/Rect;Landroid/graphics/Paint;)V" />
 		<method name="draw(Landroid/graphics/Canvas;Landroid/graphics/RectF;)V" />
+		<method name="getBitmap()Landroid/graphics/Bitmap;" since="19" />
 		<method name="getDensity()I" since="4" />
 		<method name="getHeight()I" />
+		<method name="getName()Ljava/lang/String;" since="19" />
+		<method name="getPaint()Landroid/graphics/Paint;" since="19" />
 		<method name="getTransparentRegion(Landroid/graphics/Rect;)Landroid/graphics/Region;" />
 		<method name="getWidth()I" />
 		<method name="hasAlpha()Z" />
@@ -8890,6 +9229,7 @@
 		<field name="ANTI_ALIAS_FLAG" />
 		<field name="DEV_KERN_TEXT_FLAG" />
 		<field name="DITHER_FLAG" />
+		<field name="EMBEDDED_BITMAP_TEXT_FLAG" since="19" />
 		<field name="FAKE_BOLD_TEXT_FLAG" />
 		<field name="FILTER_BITMAP_FLAG" />
 		<field name="HINTING_OFF" since="14" />
@@ -8981,6 +9321,8 @@
 		<method name="moveTo(FF)V" />
 		<method name="offset(FF)V" />
 		<method name="offset(FFLandroid/graphics/Path;)V" />
+		<method name="op(Landroid/graphics/Path;Landroid/graphics/Path$Op;)Z" since="19" />
+		<method name="op(Landroid/graphics/Path;Landroid/graphics/Path;Landroid/graphics/Path$Op;)Z" since="19" />
 		<method name="quadTo(FFFF)V" />
 		<method name="rCubicTo(FFFFFF)V" />
 		<method name="rLineTo(FF)V" />
@@ -9011,6 +9353,16 @@
 		<field name="INVERSE_WINDING" />
 		<field name="WINDING" />
 	</class>
+	<class name="android/graphics/Path$Op" since="19">
+		<extends name="java/lang/Enum" />
+		<method name="valueOf(Ljava/lang/String;)Landroid/graphics/Path$Op;" />
+		<method name="values()[Landroid/graphics/Path$Op;" />
+		<field name="DIFFERENCE" />
+		<field name="INTERSECT" />
+		<field name="REVERSE_DIFFERENCE" />
+		<field name="UNION" />
+		<field name="XOR" />
+	</class>
 	<class name="android/graphics/PathDashPathEffect" since="1">
 		<extends name="android/graphics/PathEffect" />
 		<method name="&lt;init>(Landroid/graphics/Path;FFLandroid/graphics/PathDashPathEffect$Style;)V" />
@@ -9314,11 +9666,13 @@
 	<class name="android/graphics/SurfaceTexture" since="11">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(I)V" />
+		<method name="&lt;init>(IZ)V" since="19" />
 		<method name="attachToGLContext(I)V" since="16" />
 		<method name="detachFromGLContext()V" since="16" />
 		<method name="getTimestamp()J" since="14" />
 		<method name="getTransformMatrix([F)V" />
 		<method name="release()V" since="14" />
+		<method name="releaseTexImage()V" since="19" />
 		<method name="setDefaultBufferSize(II)V" since="15" />
 		<method name="setOnFrameAvailableListener(Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;)V" />
 		<method name="updateTexImage()V" />
@@ -9449,6 +9803,7 @@
 		<method name="createFromXml(Landroid/content/res/Resources;Lorg/xmlpull/v1/XmlPullParser;)Landroid/graphics/drawable/Drawable;" />
 		<method name="createFromXmlInner(Landroid/content/res/Resources;Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;)Landroid/graphics/drawable/Drawable;" />
 		<method name="draw(Landroid/graphics/Canvas;)V" />
+		<method name="getAlpha()I" since="19" />
 		<method name="getBounds()Landroid/graphics/Rect;" />
 		<method name="getCallback()Landroid/graphics/drawable/Drawable$Callback;" since="11" />
 		<method name="getChangingConfigurations()I" />
@@ -9465,6 +9820,7 @@
 		<method name="getTransparentRegion()Landroid/graphics/Region;" />
 		<method name="inflate(Landroid/content/res/Resources;Lorg/xmlpull/v1/XmlPullParser;Landroid/util/AttributeSet;)V" />
 		<method name="invalidateSelf()V" />
+		<method name="isAutoMirrored()Z" since="19" />
 		<method name="isStateful()Z" />
 		<method name="isVisible()Z" />
 		<method name="jumpToCurrentState()V" since="11" />
@@ -9475,6 +9831,7 @@
 		<method name="resolveOpacity(II)I" />
 		<method name="scheduleSelf(Ljava/lang/Runnable;J)V" />
 		<method name="setAlpha(I)V" />
+		<method name="setAutoMirrored(Z)V" since="19" />
 		<method name="setBounds(IIII)V" />
 		<method name="setBounds(Landroid/graphics/Rect;)V" />
 		<method name="setCallback(Landroid/graphics/drawable/Drawable$Callback;)V" />
@@ -9516,6 +9873,7 @@
 		<method name="addChild(Landroid/graphics/drawable/Drawable;)I" />
 		<method name="canConstantState()Z" />
 		<method name="computeConstantSize()V" since="11" />
+		<method name="getChild(I)Landroid/graphics/drawable/Drawable;" since="19" />
 		<method name="getChildCount()I" />
 		<method name="getChildren()[Landroid/graphics/drawable/Drawable;" />
 		<method name="getConstantHeight()I" />
@@ -9578,6 +9936,7 @@
 		<implements name="android/graphics/drawable/Drawable$Callback" />
 		<method name="&lt;init>(Landroid/graphics/drawable/Drawable;I)V" />
 		<method name="&lt;init>(Landroid/graphics/drawable/Drawable;IIII)V" />
+		<method name="getDrawable()Landroid/graphics/drawable/Drawable;" since="19" />
 	</class>
 	<class name="android/graphics/drawable/LayerDrawable" since="1">
 		<extends name="android/graphics/drawable/Drawable" />
@@ -9706,6 +10065,35 @@
 		<method name="onResize(FF)V" />
 		<method name="resize(FF)V" />
 	</class>
+	<class name="android/graphics/pdf/PdfDocument" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="close()V" />
+		<method name="finishPage(Landroid/graphics/pdf/PdfDocument$Page;)V" />
+		<method name="getPages()Ljava/util/List;" />
+		<method name="startPage(Landroid/graphics/pdf/PdfDocument$PageInfo;)Landroid/graphics/pdf/PdfDocument$Page;" />
+		<method name="writeTo(Ljava/io/OutputStream;)V" />
+	</class>
+	<class name="android/graphics/pdf/PdfDocument$Page" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getCanvas()Landroid/graphics/Canvas;" />
+		<method name="getInfo()Landroid/graphics/pdf/PdfDocument$PageInfo;" />
+	</class>
+	<class name="android/graphics/pdf/PdfDocument$PageInfo" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getContentRect()Landroid/graphics/Rect;" />
+		<method name="getPageHeight()I" />
+		<method name="getPageNumber()I" />
+		<method name="getPageWidth()I" />
+	</class>
+	<class name="android/graphics/pdf/PdfDocument$PageInfo$Builder" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(III)V" />
+		<method name="create()Landroid/graphics/pdf/PdfDocument$PageInfo;" />
+		<method name="setContentRect(Landroid/graphics/Rect;)Landroid/graphics/pdf/PdfDocument$PageInfo$Builder;" />
+	</class>
 	<class name="android/hardware/Camera" since="1">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -9960,6 +10348,19 @@
 		<field name="height" />
 		<field name="width" />
 	</class>
+	<class name="android/hardware/ConsumerIrManager" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getCarrierFrequencies()[Landroid/hardware/ConsumerIrManager$CarrierFrequencyRange;" />
+		<method name="hasIrEmitter()Z" />
+		<method name="transmit(I[I)V" />
+	</class>
+	<class name="android/hardware/ConsumerIrManager$CarrierFrequencyRange" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(Landroid/hardware/ConsumerIrManager;II)V" />
+		<method name="getMaxFrequency()I" />
+		<method name="getMinFrequency()I" />
+	</class>
 	<class name="android/hardware/GeomagneticField" since="3">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(FFFJ)V" />
@@ -9974,6 +10375,8 @@
 	<class name="android/hardware/Sensor" since="3">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
+		<method name="getFifoMaxEventCount()I" since="19" />
+		<method name="getFifoReservedEventCount()I" since="19" />
 		<method name="getMaximumRange()F" />
 		<method name="getMinDelay()I" since="9" />
 		<method name="getName()Ljava/lang/String;" />
@@ -9986,6 +10389,7 @@
 		<field name="TYPE_ALL" />
 		<field name="TYPE_AMBIENT_TEMPERATURE" since="14" />
 		<field name="TYPE_GAME_ROTATION_VECTOR" since="18" />
+		<field name="TYPE_GEOMAGNETIC_ROTATION_VECTOR" since="19" />
 		<field name="TYPE_GRAVITY" since="9" />
 		<field name="TYPE_GYROSCOPE" />
 		<field name="TYPE_GYROSCOPE_UNCALIBRATED" since="18" />
@@ -9999,6 +10403,8 @@
 		<field name="TYPE_RELATIVE_HUMIDITY" since="14" />
 		<field name="TYPE_ROTATION_VECTOR" since="9" />
 		<field name="TYPE_SIGNIFICANT_MOTION" since="18" />
+		<field name="TYPE_STEP_COUNTER" since="19" />
+		<field name="TYPE_STEP_DETECTOR" since="19" />
 		<field name="TYPE_TEMPERATURE" />
 	</class>
 	<class name="android/hardware/SensorEvent" since="3">
@@ -10014,6 +10420,11 @@
 		<method name="onAccuracyChanged(Landroid/hardware/Sensor;I)V" />
 		<method name="onSensorChanged(Landroid/hardware/SensorEvent;)V" />
 	</class>
+	<class name="android/hardware/SensorEventListener2" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/hardware/SensorEventListener" />
+		<method name="onFlushCompleted(Landroid/hardware/Sensor;)V" />
+	</class>
 	<class name="android/hardware/SensorListener" since="1">
 		<extends name="java/lang/Object" />
 		<method name="onAccuracyChanged(II)V" />
@@ -10023,6 +10434,7 @@
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
 		<method name="cancelTriggerSensor(Landroid/hardware/TriggerEventListener;Landroid/hardware/Sensor;)Z" since="18" />
+		<method name="flush(Landroid/hardware/SensorEventListener;)Z" since="19" />
 		<method name="getAltitude(FF)F" since="9" />
 		<method name="getAngleChange([F[F[F)V" since="9" />
 		<method name="getDefaultSensor(I)Landroid/hardware/Sensor;" since="3" />
@@ -10034,6 +10446,8 @@
 		<method name="getSensorList(I)Ljava/util/List;" since="3" />
 		<method name="getSensors()I" />
 		<method name="registerListener(Landroid/hardware/SensorEventListener;Landroid/hardware/Sensor;I)Z" since="3" />
+		<method name="registerListener(Landroid/hardware/SensorEventListener;Landroid/hardware/Sensor;II)Z" since="19" />
+		<method name="registerListener(Landroid/hardware/SensorEventListener;Landroid/hardware/Sensor;IILandroid/os/Handler;)Z" since="19" />
 		<method name="registerListener(Landroid/hardware/SensorEventListener;Landroid/hardware/Sensor;ILandroid/os/Handler;)Z" since="3" />
 		<method name="registerListener(Landroid/hardware/SensorListener;I)Z" />
 		<method name="registerListener(Landroid/hardware/SensorListener;II)Z" />
@@ -10116,12 +10530,16 @@
 	<class name="android/hardware/display/DisplayManager" since="17">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
+		<method name="createVirtualDisplay(Ljava/lang/String;IIILandroid/view/Surface;I)Landroid/hardware/display/VirtualDisplay;" since="19" />
 		<method name="getDisplay(I)Landroid/view/Display;" />
 		<method name="getDisplays()[Landroid/view/Display;" />
 		<method name="getDisplays(Ljava/lang/String;)[Landroid/view/Display;" />
 		<method name="registerDisplayListener(Landroid/hardware/display/DisplayManager$DisplayListener;Landroid/os/Handler;)V" />
 		<method name="unregisterDisplayListener(Landroid/hardware/display/DisplayManager$DisplayListener;)V" />
 		<field name="DISPLAY_CATEGORY_PRESENTATION" />
+		<field name="VIRTUAL_DISPLAY_FLAG_PRESENTATION" since="19" />
+		<field name="VIRTUAL_DISPLAY_FLAG_PUBLIC" since="19" />
+		<field name="VIRTUAL_DISPLAY_FLAG_SECURE" since="19" />
 	</class>
 	<class name="android/hardware/display/DisplayManager$DisplayListener" since="17">
 		<extends name="java/lang/Object" />
@@ -10129,6 +10547,12 @@
 		<method name="onDisplayChanged(I)V" />
 		<method name="onDisplayRemoved(I)V" />
 	</class>
+	<class name="android/hardware/display/VirtualDisplay" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getDisplay()Landroid/view/Display;" />
+		<method name="release()V" />
+	</class>
 	<class name="android/hardware/input/InputManager" since="16">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -10791,6 +11215,7 @@
 		<field name="KEY_PROVIDER_ENABLED" since="3" />
 		<field name="KEY_PROXIMITY_ENTERING" />
 		<field name="KEY_STATUS_CHANGED" since="3" />
+		<field name="MODE_CHANGED_ACTION" since="19" />
 		<field name="NETWORK_PROVIDER" />
 		<field name="PASSIVE_PROVIDER" since="8" />
 		<field name="PROVIDERS_CHANGED_ACTION" since="9" />
@@ -10813,6 +11238,16 @@
 		<field name="OUT_OF_SERVICE" />
 		<field name="TEMPORARILY_UNAVAILABLE" />
 	</class>
+	<class name="android/location/SettingInjectorService" since="19">
+		<extends name="android/app/Service" />
+		<method name="&lt;init>(Ljava/lang/String;)V" />
+		<method name="onGetEnabled()Z" />
+		<method name="onGetSummary()Ljava/lang/String;" />
+		<field name="ACTION_INJECTED_SETTING_CHANGED" />
+		<field name="ACTION_SERVICE_INTENT" />
+		<field name="ATTRIBUTES_NAME" />
+		<field name="META_DATA_NAME" />
+	</class>
 	<class name="android/media/AsyncPlayer" since="1">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
@@ -10872,6 +11307,7 @@
 		<method name="adjustStreamVolume(III)V" />
 		<method name="adjustSuggestedStreamVolume(III)V" />
 		<method name="adjustVolume(II)V" />
+		<method name="dispatchMediaKeyEvent(Landroid/view/KeyEvent;)V" since="19" />
 		<method name="getMode()I" />
 		<method name="getParameters(Ljava/lang/String;)Ljava/lang/String;" since="5" />
 		<method name="getProperty(Ljava/lang/String;)Ljava/lang/String;" since="17" />
@@ -10893,6 +11329,7 @@
 		<method name="registerMediaButtonEventReceiver(Landroid/app/PendingIntent;)V" since="18" />
 		<method name="registerMediaButtonEventReceiver(Landroid/content/ComponentName;)V" since="8" />
 		<method name="registerRemoteControlClient(Landroid/media/RemoteControlClient;)V" since="14" />
+		<method name="registerRemoteController(Landroid/media/RemoteController;)Z" since="19" />
 		<method name="requestAudioFocus(Landroid/media/AudioManager$OnAudioFocusChangeListener;II)I" since="8" />
 		<method name="setBluetoothA2dpOn(Z)V" since="3" />
 		<method name="setBluetoothScoOn(Z)V" />
@@ -10914,6 +11351,7 @@
 		<method name="unregisterMediaButtonEventReceiver(Landroid/app/PendingIntent;)V" since="18" />
 		<method name="unregisterMediaButtonEventReceiver(Landroid/content/ComponentName;)V" since="8" />
 		<method name="unregisterRemoteControlClient(Landroid/media/RemoteControlClient;)V" since="14" />
+		<method name="unregisterRemoteController(Landroid/media/RemoteController;)V" since="19" />
 		<field name="ACTION_AUDIO_BECOMING_NOISY" since="3" />
 		<field name="ACTION_SCO_AUDIO_STATE_CHANGED" since="8" />
 		<field name="ACTION_SCO_AUDIO_STATE_UPDATED" since="14" />
@@ -10922,6 +11360,7 @@
 		<field name="ADJUST_SAME" />
 		<field name="AUDIOFOCUS_GAIN" since="8" />
 		<field name="AUDIOFOCUS_GAIN_TRANSIENT" since="8" />
+		<field name="AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE" since="19" />
 		<field name="AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK" since="8" />
 		<field name="AUDIOFOCUS_LOSS" since="8" />
 		<field name="AUDIOFOCUS_LOSS_TRANSIENT" since="8" />
@@ -10943,6 +11382,7 @@
 		<field name="FX_FOCUS_NAVIGATION_RIGHT" />
 		<field name="FX_FOCUS_NAVIGATION_UP" />
 		<field name="FX_KEYPRESS_DELETE" since="3" />
+		<field name="FX_KEYPRESS_INVALID" since="19" />
 		<field name="FX_KEYPRESS_RETURN" since="3" />
 		<field name="FX_KEYPRESS_SPACEBAR" since="3" />
 		<field name="FX_KEYPRESS_STANDARD" since="3" />
@@ -11029,6 +11469,12 @@
 		<method name="onMarkerReached(Landroid/media/AudioRecord;)V" />
 		<method name="onPeriodicNotification(Landroid/media/AudioRecord;)V" />
 	</class>
+	<class name="android/media/AudioTimestamp" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<field name="framePosition" />
+		<field name="nanoTime" />
+	</class>
 	<class name="android/media/AudioTrack" since="3">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(IIIIII)V" />
@@ -11052,6 +11498,7 @@
 		<method name="getSampleRate()I" />
 		<method name="getState()I" />
 		<method name="getStreamType()I" />
+		<method name="getTimestamp(Landroid/media/AudioTimestamp;)Z" since="19" />
 		<method name="pause()V" />
 		<method name="play()V" />
 		<method name="release()V" />
@@ -11198,6 +11645,41 @@
 		<field name="EULER_Y" />
 		<field name="EULER_Z" />
 	</class>
+	<class name="android/media/Image" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="java/lang/AutoCloseable" />
+		<method name="&lt;init>()V" />
+		<method name="getFormat()I" />
+		<method name="getHeight()I" />
+		<method name="getPlanes()[Landroid/media/Image$Plane;" />
+		<method name="getTimestamp()J" />
+		<method name="getWidth()I" />
+	</class>
+	<class name="android/media/Image$Plane" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getBuffer()Ljava/nio/ByteBuffer;" />
+		<method name="getPixelStride()I" />
+		<method name="getRowStride()I" />
+	</class>
+	<class name="android/media/ImageReader" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="java/lang/AutoCloseable" />
+		<method name="&lt;init>()V" />
+		<method name="acquireLatestImage()Landroid/media/Image;" />
+		<method name="acquireNextImage()Landroid/media/Image;" />
+		<method name="getHeight()I" />
+		<method name="getImageFormat()I" />
+		<method name="getMaxImages()I" />
+		<method name="getSurface()Landroid/view/Surface;" />
+		<method name="getWidth()I" />
+		<method name="newInstance(IIII)Landroid/media/ImageReader;" />
+		<method name="setOnImageAvailableListener(Landroid/media/ImageReader$OnImageAvailableListener;Landroid/os/Handler;)V" />
+	</class>
+	<class name="android/media/ImageReader$OnImageAvailableListener" since="19">
+		<extends name="java/lang/Object" />
+		<method name="onImageAvailable(Landroid/media/ImageReader;)V" />
+	</class>
 	<class name="android/media/JetPlayer" since="3">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -11257,6 +11739,7 @@
 		<method name="queueSecureInputBuffer(IILandroid/media/MediaCodec$CryptoInfo;JI)V" />
 		<method name="release()V" />
 		<method name="releaseOutputBuffer(IZ)V" />
+		<method name="setParameters(Landroid/os/Bundle;)V" since="19" />
 		<method name="setVideoScalingMode(I)V" />
 		<method name="signalEndOfInputStream()V" since="18" />
 		<method name="start()V" />
@@ -11270,6 +11753,9 @@
 		<field name="INFO_OUTPUT_BUFFERS_CHANGED" />
 		<field name="INFO_OUTPUT_FORMAT_CHANGED" />
 		<field name="INFO_TRY_AGAIN_LATER" />
+		<field name="PARAMETER_KEY_REQUEST_SYNC_FRAME" since="19" />
+		<field name="PARAMETER_KEY_SUSPEND" since="19" />
+		<field name="PARAMETER_KEY_VIDEO_BITRATE" since="19" />
 		<field name="VIDEO_SCALING_MODE_SCALE_TO_FIT" />
 		<field name="VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING" />
 	</class>
@@ -11286,6 +11772,9 @@
 		<extends name="java/lang/RuntimeException" />
 		<method name="&lt;init>(ILjava/lang/String;)V" />
 		<method name="getErrorCode()I" />
+		<field name="ERROR_KEY_EXPIRED" since="19" />
+		<field name="ERROR_NO_KEY" since="19" />
+		<field name="ERROR_RESOURCE_BUSY" since="19" />
 	</class>
 	<class name="android/media/MediaCodec$CryptoInfo" since="16">
 		<extends name="java/lang/Object" />
@@ -11309,6 +11798,7 @@
 	<class name="android/media/MediaCodecInfo$CodecCapabilities" since="16">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
+		<method name="isFeatureSupported(Ljava/lang/String;)Z" since="19" />
 		<field name="COLOR_Format12bitRGB444" />
 		<field name="COLOR_Format16bitARGB1555" />
 		<field name="COLOR_Format16bitARGB4444" />
@@ -11355,6 +11845,7 @@
 		<field name="COLOR_FormatYUV444Interleaved" />
 		<field name="COLOR_QCOM_FormatYUV420SemiPlanar" />
 		<field name="COLOR_TI_FormatYUV420PackedSemiPlanar" />
+		<field name="FEATURE_AdaptivePlayback" since="19" />
 		<field name="colorFormats" />
 		<field name="profileLevels" />
 	</class>
@@ -11471,6 +11962,7 @@
 		<method name="getProvisionRequest()Landroid/media/MediaDrm$ProvisionRequest;" />
 		<method name="getSecureStops()Ljava/util/List;" />
 		<method name="isCryptoSchemeSupported(Ljava/util/UUID;)Z" />
+		<method name="isCryptoSchemeSupported(Ljava/util/UUID;Ljava/lang/String;)Z" since="19" />
 		<method name="openSession()[B" />
 		<method name="provideKeyResponse([B[B)[B" />
 		<method name="provideProvisionResponse([B)V" />
@@ -11557,6 +12049,7 @@
 		<method name="&lt;init>()V" />
 		<method name="containsKey(Ljava/lang/String;)Z" />
 		<method name="createAudioFormat(Ljava/lang/String;II)Landroid/media/MediaFormat;" />
+		<method name="createSubtitleFormat(Ljava/lang/String;Ljava/lang/String;)Landroid/media/MediaFormat;" since="19" />
 		<method name="createVideoFormat(Ljava/lang/String;II)Landroid/media/MediaFormat;" />
 		<method name="getByteBuffer(Ljava/lang/String;)Ljava/nio/ByteBuffer;" />
 		<method name="getFloat(Ljava/lang/String;)F" />
@@ -11578,12 +12071,40 @@
 		<field name="KEY_FRAME_RATE" />
 		<field name="KEY_HEIGHT" />
 		<field name="KEY_IS_ADTS" />
+		<field name="KEY_IS_AUTOSELECT" since="19" />
+		<field name="KEY_IS_DEFAULT" since="19" />
+		<field name="KEY_IS_FORCED_SUBTITLE" since="19" />
 		<field name="KEY_I_FRAME_INTERVAL" />
+		<field name="KEY_LANGUAGE" since="19" />
+		<field name="KEY_MAX_HEIGHT" since="19" />
 		<field name="KEY_MAX_INPUT_SIZE" />
+		<field name="KEY_MAX_WIDTH" since="19" />
 		<field name="KEY_MIME" />
+		<field name="KEY_PUSH_BLANK_BUFFERS_ON_STOP" since="19" />
+		<field name="KEY_REPEAT_PREVIOUS_FRAME_AFTER" since="19" />
 		<field name="KEY_SAMPLE_RATE" />
 		<field name="KEY_WIDTH" />
 	</class>
+	<class name="android/media/MediaMetadataEditor" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="addEditableKey(I)V" />
+		<method name="apply()V" />
+		<method name="clear()V" />
+		<method name="getBitmap(ILandroid/graphics/Bitmap;)Landroid/graphics/Bitmap;" />
+		<method name="getEditableKeys()[I" />
+		<method name="getLong(IJ)J" />
+		<method name="getObject(ILjava/lang/Object;)Ljava/lang/Object;" />
+		<method name="getString(ILjava/lang/String;)Ljava/lang/String;" />
+		<method name="putBitmap(ILandroid/graphics/Bitmap;)Landroid/media/MediaMetadataEditor;" />
+		<method name="putLong(IJ)Landroid/media/MediaMetadataEditor;" />
+		<method name="putObject(ILjava/lang/Object;)Landroid/media/MediaMetadataEditor;" />
+		<method name="putString(ILjava/lang/String;)Landroid/media/MediaMetadataEditor;" />
+		<method name="removeEditableKeys()V" />
+		<field name="BITMAP_KEY_ARTWORK" />
+		<field name="RATING_KEY_BY_OTHERS" />
+		<field name="RATING_KEY_BY_USER" />
+	</class>
 	<class name="android/media/MediaMetadataRetriever" since="10">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -11631,6 +12152,7 @@
 		<method name="&lt;init>(Ljava/lang/String;I)V" />
 		<method name="addTrack(Landroid/media/MediaFormat;)I" />
 		<method name="release()V" />
+		<method name="setLocation(FF)V" since="19" />
 		<method name="setOrientationHint(I)V" />
 		<method name="start()V" />
 		<method name="stop()V" />
@@ -11706,7 +12228,9 @@
 		<field name="MEDIA_INFO_BUFFERING_START" since="9" />
 		<field name="MEDIA_INFO_METADATA_UPDATE" since="5" />
 		<field name="MEDIA_INFO_NOT_SEEKABLE" since="3" />
+		<field name="MEDIA_INFO_SUBTITLE_TIMED_OUT" since="19" />
 		<field name="MEDIA_INFO_UNKNOWN" since="3" />
+		<field name="MEDIA_INFO_UNSUPPORTED_SUBTITLE" since="19" />
 		<field name="MEDIA_INFO_VIDEO_RENDERING_START" since="17" />
 		<field name="MEDIA_INFO_VIDEO_TRACK_LAGGING" since="3" />
 		<field name="MEDIA_MIMETYPE_TEXT_SUBRIP" since="16" />
@@ -11749,6 +12273,7 @@
 		<extends name="java/lang/Object" />
 		<implements name="android/os/Parcelable" />
 		<method name="&lt;init>()V" />
+		<method name="getFormat()Landroid/media/MediaFormat;" since="19" />
 		<method name="getLanguage()Ljava/lang/String;" />
 		<method name="getTrackType()I" />
 		<field name="MEDIA_TRACK_TYPE_AUDIO" />
@@ -11813,6 +12338,7 @@
 		<field name="CAMCORDER" since="7" />
 		<field name="DEFAULT" />
 		<field name="MIC" />
+		<field name="REMOTE_SUBMIX" since="19" />
 		<field name="VOICE_CALL" since="4" />
 		<field name="VOICE_COMMUNICATION" since="11" />
 		<field name="VOICE_DOWNLINK" since="4" />
@@ -12001,11 +12527,35 @@
 		<extends name="android/media/MediaDrmException" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 	</class>
+	<class name="android/media/Rating" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>()V" />
+		<method name="getPercentRating()F" />
+		<method name="getRatingStyle()I" />
+		<method name="getStarRating()F" />
+		<method name="hasHeart()Z" />
+		<method name="isRated()Z" />
+		<method name="isThumbUp()Z" />
+		<method name="newHeartRating(Z)Landroid/media/Rating;" />
+		<method name="newPercentageRating(F)Landroid/media/Rating;" />
+		<method name="newStarRating(IF)Landroid/media/Rating;" />
+		<method name="newThumbRating(Z)Landroid/media/Rating;" />
+		<method name="newUnratedRating(I)Landroid/media/Rating;" />
+		<field name="CREATOR" />
+		<field name="RATING_3_STARS" />
+		<field name="RATING_4_STARS" />
+		<field name="RATING_5_STARS" />
+		<field name="RATING_HEART" />
+		<field name="RATING_PERCENTAGE" />
+		<field name="RATING_THUMB_UP_DOWN" />
+	</class>
 	<class name="android/media/RemoteControlClient" since="14">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(Landroid/app/PendingIntent;)V" />
 		<method name="&lt;init>(Landroid/app/PendingIntent;Landroid/os/Looper;)V" />
 		<method name="editMetadata(Z)Landroid/media/RemoteControlClient$MetadataEditor;" />
+		<method name="setMetadataUpdateListener(Landroid/media/RemoteControlClient$OnMetadataUpdateListener;)V" since="19" />
 		<method name="setOnGetPlaybackPositionListener(Landroid/media/RemoteControlClient$OnGetPlaybackPositionListener;)V" since="18" />
 		<method name="setPlaybackPositionUpdateListener(Landroid/media/RemoteControlClient$OnPlaybackPositionUpdateListener;)V" since="18" />
 		<method name="setPlaybackState(I)V" />
@@ -12018,6 +12568,7 @@
 		<field name="FLAG_KEY_MEDIA_PLAY_PAUSE" />
 		<field name="FLAG_KEY_MEDIA_POSITION_UPDATE" since="18" />
 		<field name="FLAG_KEY_MEDIA_PREVIOUS" />
+		<field name="FLAG_KEY_MEDIA_RATING" since="19" />
 		<field name="FLAG_KEY_MEDIA_REWIND" />
 		<field name="FLAG_KEY_MEDIA_STOP" />
 		<field name="PLAYSTATE_BUFFERING" />
@@ -12031,6 +12582,7 @@
 		<field name="PLAYSTATE_STOPPED" />
 	</class>
 	<class name="android/media/RemoteControlClient$MetadataEditor" since="14">
+		<extends name="android/media/MediaMetadataEditor" since="19" />
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(Landroid/media/RemoteControlClient;)V" />
 		<method name="apply()V" />
@@ -12044,10 +12596,44 @@
 		<extends name="java/lang/Object" />
 		<method name="onGetPlaybackPosition()J" />
 	</class>
+	<class name="android/media/RemoteControlClient$OnMetadataUpdateListener" since="19">
+		<extends name="java/lang/Object" />
+		<method name="onMetadataUpdate(ILjava/lang/Object;)V" />
+	</class>
 	<class name="android/media/RemoteControlClient$OnPlaybackPositionUpdateListener" since="18">
 		<extends name="java/lang/Object" />
 		<method name="onPlaybackPositionUpdate(J)V" />
 	</class>
+	<class name="android/media/RemoteController" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(Landroid/content/Context;Landroid/media/RemoteController$OnClientUpdateListener;)V" />
+		<method name="&lt;init>(Landroid/content/Context;Landroid/media/RemoteController$OnClientUpdateListener;Landroid/os/Looper;)V" />
+		<method name="clearArtworkConfiguration()Z" />
+		<method name="editMetadata()Landroid/media/RemoteController$MetadataEditor;" />
+		<method name="getEstimatedMediaPosition()J" />
+		<method name="seekTo(J)Z" />
+		<method name="sendMediaKeyEvent(Landroid/view/KeyEvent;)Z" />
+		<method name="setArtworkConfiguration(II)Z" />
+		<method name="setSynchronizationMode(I)Z" />
+		<field name="POSITION_SYNCHRONIZATION_CHECK" />
+		<field name="POSITION_SYNCHRONIZATION_NONE" />
+	</class>
+	<class name="android/media/RemoteController$MetadataEditor" since="19">
+		<extends name="android/media/MediaMetadataEditor" />
+		<method name="&lt;init>(Landroid/media/RemoteController;)V" />
+	</class>
+	<class name="android/media/RemoteController$OnClientUpdateListener" since="19">
+		<extends name="java/lang/Object" />
+		<method name="onClientChange(Z)V" />
+		<method name="onClientMetadataUpdate(Landroid/media/RemoteController$MetadataEditor;)V" />
+		<method name="onClientPlaybackStateUpdate(I)V" />
+		<method name="onClientPlaybackStateUpdate(IJJF)V" />
+		<method name="onClientTransportControlUpdate(I)V" />
+	</class>
+	<class name="android/media/ResourceBusyException" since="19">
+		<extends name="android/media/MediaDrmException" />
+		<method name="&lt;init>(Ljava/lang/String;)V" />
+	</class>
 	<class name="android/media/Ringtone" since="1">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -12283,6 +12869,7 @@
 		<field name="EFFECT_TYPE_BASS_BOOST" since="18" />
 		<field name="EFFECT_TYPE_ENV_REVERB" since="18" />
 		<field name="EFFECT_TYPE_EQUALIZER" since="18" />
+		<field name="EFFECT_TYPE_LOUDNESS_ENHANCER" since="19" />
 		<field name="EFFECT_TYPE_NS" since="18" />
 		<field name="EFFECT_TYPE_PRESET_REVERB" since="18" />
 		<field name="EFFECT_TYPE_VIRTUALIZER" since="18" />
@@ -12439,6 +13026,13 @@
 		<field name="curPreset" />
 		<field name="numBands" />
 	</class>
+	<class name="android/media/audiofx/LoudnessEnhancer" since="19">
+		<extends name="android/media/audiofx/AudioEffect" />
+		<method name="&lt;init>(I)V" />
+		<method name="getTargetGain()F" />
+		<method name="setTargetGain(I)V" />
+		<field name="PARAM_TARGET_GAIN_MB" />
+	</class>
 	<class name="android/media/audiofx/NoiseSuppressor" since="16">
 		<extends name="android/media/audiofx/AudioEffect" />
 		<method name="&lt;init>()V" />
@@ -12502,6 +13096,8 @@
 		<method name="getEnabled()Z" />
 		<method name="getFft([B)I" />
 		<method name="getMaxCaptureRate()I" />
+		<method name="getMeasurementMode()I" since="19" />
+		<method name="getMeasurementPeakRms(Landroid/media/audiofx/Visualizer$MeasurementPeakRms;)I" since="19" />
 		<method name="getSamplingRate()I" />
 		<method name="getScalingMode()I" since="16" />
 		<method name="getWaveForm([B)I" />
@@ -12509,6 +13105,7 @@
 		<method name="setCaptureSize(I)I" />
 		<method name="setDataCaptureListener(Landroid/media/audiofx/Visualizer$OnDataCaptureListener;IZZ)I" />
 		<method name="setEnabled(Z)I" />
+		<method name="setMeasurementMode(I)I" since="19" />
 		<method name="setScalingMode(I)I" since="16" />
 		<field name="ALREADY_EXISTS" />
 		<field name="ERROR" />
@@ -12517,6 +13114,8 @@
 		<field name="ERROR_INVALID_OPERATION" />
 		<field name="ERROR_NO_INIT" />
 		<field name="ERROR_NO_MEMORY" />
+		<field name="MEASUREMENT_MODE_NONE" since="19" />
+		<field name="MEASUREMENT_MODE_PEAK_RMS" since="19" />
 		<field name="SCALING_MODE_AS_PLAYED" since="16" />
 		<field name="SCALING_MODE_NORMALIZED" since="16" />
 		<field name="STATE_ENABLED" />
@@ -12524,6 +13123,12 @@
 		<field name="STATE_UNINITIALIZED" />
 		<field name="SUCCESS" />
 	</class>
+	<class name="android/media/audiofx/Visualizer$MeasurementPeakRms" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<field name="mPeak" />
+		<field name="mRms" />
+	</class>
 	<class name="android/media/audiofx/Visualizer$OnDataCaptureListener" since="9">
 		<extends name="java/lang/Object" />
 		<method name="onFftDataCapture(Landroid/media/audiofx/Visualizer;[BI)V" />
@@ -12775,6 +13380,7 @@
 		<extends name="java/lang/Object" />
 		<implements name="java/io/Closeable" since="17" />
 		<method name="&lt;init>()V" />
+		<method name="&lt;init>(I)V" since="19" />
 		<method name="bind(Landroid/net/LocalSocketAddress;)V" />
 		<method name="close()V" />
 		<method name="connect(Landroid/net/LocalSocketAddress;)V" />
@@ -12800,6 +13406,9 @@
 		<method name="setSoTimeout(I)V" />
 		<method name="shutdownInput()V" />
 		<method name="shutdownOutput()V" />
+		<field name="SOCKET_DGRAM" since="19" />
+		<field name="SOCKET_SEQPACKET" since="19" />
+		<field name="SOCKET_STREAM" since="19" />
 	</class>
 	<class name="android/net/LocalSocketAddress" since="1">
 		<extends name="java/lang/Object" />
@@ -13650,6 +14259,8 @@
 		<method name="reconnect()Z" />
 		<method name="removeNetwork(I)Z" />
 		<method name="saveConfiguration()Z" />
+		<method name="setTdlsEnabled(Ljava/net/InetAddress;Z)V" since="19" />
+		<method name="setTdlsEnabledWithMacAddress(Ljava/lang/String;Z)V" since="19" />
 		<method name="setWifiEnabled(Z)Z" />
 		<method name="startScan()Z" />
 		<method name="updateNetwork(Landroid/net/wifi/WifiConfiguration;)I" />
@@ -13955,8 +14566,10 @@
 		<method name="&lt;init>()V" />
 		<method name="disableForegroundDispatch(Landroid/app/Activity;)V" since="10" />
 		<method name="disableForegroundNdefPush(Landroid/app/Activity;)V" since="10" />
+		<method name="disableReaderMode(Landroid/app/Activity;)V" since="19" />
 		<method name="enableForegroundDispatch(Landroid/app/Activity;Landroid/app/PendingIntent;[Landroid/content/IntentFilter;[[Ljava/lang/String;)V" since="10" />
 		<method name="enableForegroundNdefPush(Landroid/app/Activity;Landroid/nfc/NdefMessage;)V" since="10" />
+		<method name="enableReaderMode(Landroid/app/Activity;Landroid/nfc/NfcAdapter$ReaderCallback;ILandroid/os/Bundle;)V" since="19" />
 		<method name="getDefaultAdapter()Landroid/nfc/NfcAdapter;" />
 		<method name="getDefaultAdapter(Landroid/content/Context;)Landroid/nfc/NfcAdapter;" since="10" />
 		<method name="isEnabled()Z" />
@@ -13973,7 +14586,15 @@
 		<field name="EXTRA_ADAPTER_STATE" since="18" />
 		<field name="EXTRA_ID" />
 		<field name="EXTRA_NDEF_MESSAGES" />
+		<field name="EXTRA_READER_PRESENCE_CHECK_DELAY" since="19" />
 		<field name="EXTRA_TAG" since="10" />
+		<field name="FLAG_READER_NFC_A" since="19" />
+		<field name="FLAG_READER_NFC_B" since="19" />
+		<field name="FLAG_READER_NFC_BARCODE" since="19" />
+		<field name="FLAG_READER_NFC_F" since="19" />
+		<field name="FLAG_READER_NFC_V" since="19" />
+		<field name="FLAG_READER_NO_PLATFORM_SOUNDS" since="19" />
+		<field name="FLAG_READER_SKIP_NDEF_CHECK" since="19" />
 		<field name="STATE_OFF" since="18" />
 		<field name="STATE_ON" since="18" />
 		<field name="STATE_TURNING_OFF" since="18" />
@@ -13991,6 +14612,10 @@
 		<extends name="java/lang/Object" />
 		<method name="onNdefPushComplete(Landroid/nfc/NfcEvent;)V" />
 	</class>
+	<class name="android/nfc/NfcAdapter$ReaderCallback" since="19">
+		<extends name="java/lang/Object" />
+		<method name="onTagDiscovered(Landroid/nfc/Tag;)V" />
+	</class>
 	<class name="android/nfc/NfcEvent" since="14">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -14014,6 +14639,40 @@
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 	</class>
+	<class name="android/nfc/cardemulation/CardEmulation" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getInstance(Landroid/nfc/NfcAdapter;)Landroid/nfc/cardemulation/CardEmulation;" />
+		<method name="getSelectionModeForCategory(Ljava/lang/String;)I" />
+		<method name="isDefaultServiceForAid(Landroid/content/ComponentName;Ljava/lang/String;)Z" />
+		<method name="isDefaultServiceForCategory(Landroid/content/ComponentName;Ljava/lang/String;)Z" />
+		<field name="ACTION_CHANGE_DEFAULT" />
+		<field name="CATEGORY_OTHER" />
+		<field name="CATEGORY_PAYMENT" />
+		<field name="EXTRA_CATEGORY" />
+		<field name="EXTRA_SERVICE_COMPONENT" />
+		<field name="SELECTION_MODE_ALWAYS_ASK" />
+		<field name="SELECTION_MODE_ASK_IF_CONFLICT" />
+		<field name="SELECTION_MODE_PREFER_DEFAULT" />
+	</class>
+	<class name="android/nfc/cardemulation/HostApduService" since="19">
+		<extends name="android/app/Service" />
+		<method name="&lt;init>()V" />
+		<method name="notifyUnhandled()V" />
+		<method name="onDeactivated(I)V" />
+		<method name="processCommandApdu([BLandroid/os/Bundle;)[B" />
+		<method name="sendResponseApdu([B)V" />
+		<field name="DEACTIVATION_DESELECTED" />
+		<field name="DEACTIVATION_LINK_LOSS" />
+		<field name="SERVICE_INTERFACE" />
+		<field name="SERVICE_META_DATA" />
+	</class>
+	<class name="android/nfc/cardemulation/OffHostApduService" since="19">
+		<extends name="android/app/Service" />
+		<method name="&lt;init>()V" />
+		<field name="SERVICE_INTERFACE" />
+		<field name="SERVICE_META_DATA" />
+	</class>
 	<class name="android/nfc/tech/BasicTagTechnology" since="10">
 		<extends name="java/lang/Object" />
 		<implements name="android/nfc/tech/TagTechnology" />
@@ -16397,6 +17056,7 @@
 		<field name="JELLY_BEAN" since="16" />
 		<field name="JELLY_BEAN_MR1" since="17" />
 		<field name="JELLY_BEAN_MR2" since="18" />
+		<field name="KITKAT" since="19" />
 	</class>
 	<class name="android/os/Bundle" since="1">
 		<extends name="java/lang/Object" />
@@ -16612,9 +17272,12 @@
 		<method name="getOtherPrivateDirty(I)I" since="14" />
 		<method name="getOtherPss(I)I" since="14" />
 		<method name="getOtherSharedDirty(I)I" since="14" />
+		<method name="getTotalPrivateClean()I" since="19" />
 		<method name="getTotalPrivateDirty()I" since="5" />
 		<method name="getTotalPss()I" since="5" />
+		<method name="getTotalSharedClean()I" since="19" />
 		<method name="getTotalSharedDirty()I" since="5" />
+		<method name="getTotalSwappablePss()I" since="19" />
 		<method name="readFromParcel(Landroid/os/Parcel;)V" since="5" />
 		<field name="CREATOR" since="5" />
 		<field name="dalvikPrivateDirty" />
@@ -16668,10 +17331,12 @@
 		<method name="getExternalStoragePublicDirectory(Ljava/lang/String;)Ljava/io/File;" since="8" />
 		<method name="getExternalStorageState()Ljava/lang/String;" />
 		<method name="getRootDirectory()Ljava/io/File;" />
+		<method name="getStorageState(Ljava/io/File;)Ljava/lang/String;" since="19" />
 		<method name="isExternalStorageEmulated()Z" since="11" />
 		<method name="isExternalStorageRemovable()Z" since="9" />
 		<field name="DIRECTORY_ALARMS" since="8" />
 		<field name="DIRECTORY_DCIM" since="8" />
+		<field name="DIRECTORY_DOCUMENTS" since="19" />
 		<field name="DIRECTORY_DOWNLOADS" since="8" />
 		<field name="DIRECTORY_MOVIES" since="8" />
 		<field name="DIRECTORY_MUSIC" since="8" />
@@ -16686,6 +17351,7 @@
 		<field name="MEDIA_NOFS" since="3" />
 		<field name="MEDIA_REMOVED" />
 		<field name="MEDIA_SHARED" />
+		<field name="MEDIA_UNKNOWN" since="19" />
 		<field name="MEDIA_UNMOUNTABLE" />
 		<field name="MEDIA_UNMOUNTED" />
 	</class>
@@ -16985,8 +17651,14 @@
 		<implements name="java/io/Closeable" since="16" />
 		<method name="&lt;init>(Landroid/os/ParcelFileDescriptor;)V" />
 		<method name="adoptFd(I)Landroid/os/ParcelFileDescriptor;" since="13" />
+		<method name="canDetectErrors()Z" since="19" />
+		<method name="checkError()V" since="19" />
 		<method name="close()V" />
+		<method name="closeWithError(Ljava/lang/String;)V" since="19" />
 		<method name="createPipe()[Landroid/os/ParcelFileDescriptor;" since="9" />
+		<method name="createReliablePipe()[Landroid/os/ParcelFileDescriptor;" since="19" />
+		<method name="createReliableSocketPair()[Landroid/os/ParcelFileDescriptor;" since="19" />
+		<method name="createSocketPair()[Landroid/os/ParcelFileDescriptor;" since="19" />
 		<method name="detachFd()I" since="12" />
 		<method name="dup()Landroid/os/ParcelFileDescriptor;" since="14" />
 		<method name="dup(Ljava/io/FileDescriptor;)Landroid/os/ParcelFileDescriptor;" since="13" />
@@ -16997,6 +17669,8 @@
 		<method name="getFileDescriptor()Ljava/io/FileDescriptor;" />
 		<method name="getStatSize()J" since="3" />
 		<method name="open(Ljava/io/File;I)Landroid/os/ParcelFileDescriptor;" />
+		<method name="open(Ljava/io/File;ILandroid/os/Handler;Landroid/os/ParcelFileDescriptor$OnCloseListener;)Landroid/os/ParcelFileDescriptor;" since="19" />
+		<method name="parseMode(Ljava/lang/String;)I" since="19" />
 		<field name="CREATOR" />
 		<field name="MODE_APPEND" since="3" />
 		<field name="MODE_CREATE" />
@@ -17015,6 +17689,14 @@
 		<extends name="java/io/FileOutputStream" />
 		<method name="&lt;init>(Landroid/os/ParcelFileDescriptor;)V" />
 	</class>
+	<class name="android/os/ParcelFileDescriptor$FileDescriptorDetachedException" since="19">
+		<extends name="java/io/IOException" />
+		<method name="&lt;init>()V" />
+	</class>
+	<class name="android/os/ParcelFileDescriptor$OnCloseListener" since="19">
+		<extends name="java/lang/Object" />
+		<method name="onClose(Ljava/io/IOException;)V" />
+	</class>
 	<class name="android/os/ParcelFormatException" since="1">
 		<extends name="java/lang/RuntimeException" />
 		<method name="&lt;init>()V" />
@@ -17288,6 +17970,7 @@
 		<method name="isUserAGoat()Z" />
 		<method name="isUserRunning(Landroid/os/UserHandle;)Z" />
 		<method name="isUserRunningOrStopping(Landroid/os/UserHandle;)Z" />
+		<method name="setRestrictionsChallenge(Ljava/lang/String;)Z" since="19" />
 		<method name="setUserRestriction(Ljava/lang/String;Z)V" since="18" />
 		<method name="setUserRestrictions(Landroid/os/Bundle;)V" since="18" />
 		<method name="setUserRestrictions(Landroid/os/Bundle;Landroid/os/UserHandle;)V" since="18" />
@@ -17479,6 +18162,7 @@
 		<method name="onCreateView(Landroid/view/ViewGroup;)Landroid/view/View;" />
 		<method name="onDependencyChanged(Landroid/preference/Preference;Z)V" />
 		<method name="onGetDefaultValue(Landroid/content/res/TypedArray;I)Ljava/lang/Object;" />
+		<method name="onParentChanged(Landroid/preference/Preference;Z)V" since="19" />
 		<method name="onPrepareForRemoval()V" />
 		<method name="onRestoreInstanceState(Landroid/os/Parcelable;)V" />
 		<method name="onSaveInstanceState()Landroid/os/Parcelable;" />
@@ -17543,6 +18227,7 @@
 		<method name="hasHeaders()Z" since="11" />
 		<method name="invalidateHeaders()V" since="11" />
 		<method name="isMultiPane()Z" since="11" />
+		<method name="isValidFragment(Ljava/lang/String;)Z" since="19" />
 		<method name="loadHeadersFromResource(ILjava/util/List;)V" since="11" />
 		<method name="onBuildHeaders(Ljava/util/List;)V" since="11" />
 		<method name="onBuildStartFragmentIntent(Ljava/lang/String;Landroid/os/Bundle;II)Landroid/content/Intent;" since="14" />
@@ -17715,14 +18400,381 @@
 		<method name="setSummaryOn(I)V" />
 		<method name="setSummaryOn(Ljava/lang/CharSequence;)V" />
 	</class>
+	<class name="android/print/PageRange" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>(II)V" />
+		<method name="getEnd()I" />
+		<method name="getStart()I" />
+		<field name="ALL_PAGES" />
+		<field name="CREATOR" />
+	</class>
+	<class name="android/print/PrintAttributes" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>()V" />
+		<method name="getColorMode()I" />
+		<method name="getMediaSize()Landroid/print/PrintAttributes$MediaSize;" />
+		<method name="getMinMargins()Landroid/print/PrintAttributes$Margins;" />
+		<method name="getResolution()Landroid/print/PrintAttributes$Resolution;" />
+		<field name="COLOR_MODE_COLOR" />
+		<field name="COLOR_MODE_MONOCHROME" />
+		<field name="CREATOR" />
+	</class>
+	<class name="android/print/PrintAttributes$Builder" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="build()Landroid/print/PrintAttributes;" />
+		<method name="setColorMode(I)Landroid/print/PrintAttributes$Builder;" />
+		<method name="setMediaSize(Landroid/print/PrintAttributes$MediaSize;)Landroid/print/PrintAttributes$Builder;" />
+		<method name="setMinMargins(Landroid/print/PrintAttributes$Margins;)Landroid/print/PrintAttributes$Builder;" />
+		<method name="setResolution(Landroid/print/PrintAttributes$Resolution;)Landroid/print/PrintAttributes$Builder;" />
+	</class>
+	<class name="android/print/PrintAttributes$Margins" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(IIII)V" />
+		<method name="getBottomMils()I" />
+		<method name="getLeftMils()I" />
+		<method name="getRightMils()I" />
+		<method name="getTopMils()I" />
+		<field name="NO_MARGINS" />
+	</class>
+	<class name="android/print/PrintAttributes$MediaSize" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/String;II)V" />
+		<method name="asLandscape()Landroid/print/PrintAttributes$MediaSize;" />
+		<method name="asPortrait()Landroid/print/PrintAttributes$MediaSize;" />
+		<method name="getHeightMils()I" />
+		<method name="getId()Ljava/lang/String;" />
+		<method name="getLabel(Landroid/content/pm/PackageManager;)Ljava/lang/String;" />
+		<method name="getWidthMils()I" />
+		<method name="isPortrait()Z" />
+		<field name="ISO_A0" />
+		<field name="ISO_A1" />
+		<field name="ISO_A10" />
+		<field name="ISO_A2" />
+		<field name="ISO_A3" />
+		<field name="ISO_A4" />
+		<field name="ISO_A5" />
+		<field name="ISO_A6" />
+		<field name="ISO_A7" />
+		<field name="ISO_A8" />
+		<field name="ISO_A9" />
+		<field name="ISO_B0" />
+		<field name="ISO_B1" />
+		<field name="ISO_B10" />
+		<field name="ISO_B2" />
+		<field name="ISO_B3" />
+		<field name="ISO_B4" />
+		<field name="ISO_B5" />
+		<field name="ISO_B6" />
+		<field name="ISO_B7" />
+		<field name="ISO_B8" />
+		<field name="ISO_B9" />
+		<field name="ISO_C0" />
+		<field name="ISO_C1" />
+		<field name="ISO_C10" />
+		<field name="ISO_C2" />
+		<field name="ISO_C3" />
+		<field name="ISO_C4" />
+		<field name="ISO_C5" />
+		<field name="ISO_C6" />
+		<field name="ISO_C7" />
+		<field name="ISO_C8" />
+		<field name="ISO_C9" />
+		<field name="JIS_B0" />
+		<field name="JIS_B1" />
+		<field name="JIS_B10" />
+		<field name="JIS_B2" />
+		<field name="JIS_B3" />
+		<field name="JIS_B4" />
+		<field name="JIS_B5" />
+		<field name="JIS_B6" />
+		<field name="JIS_B7" />
+		<field name="JIS_B8" />
+		<field name="JIS_B9" />
+		<field name="JIS_EXEC" />
+		<field name="JPN_CHOU2" />
+		<field name="JPN_CHOU3" />
+		<field name="JPN_CHOU4" />
+		<field name="JPN_HAGAKI" />
+		<field name="JPN_KAHU" />
+		<field name="JPN_KAKU2" />
+		<field name="JPN_OUFUKU" />
+		<field name="JPN_YOU4" />
+		<field name="NA_FOOLSCAP" />
+		<field name="NA_GOVT_LETTER" />
+		<field name="NA_INDEX_3X5" />
+		<field name="NA_INDEX_4X6" />
+		<field name="NA_INDEX_5X8" />
+		<field name="NA_JUNIOR_LEGAL" />
+		<field name="NA_LEDGER" />
+		<field name="NA_LEGAL" />
+		<field name="NA_LETTER" />
+		<field name="NA_MONARCH" />
+		<field name="NA_QUARTO" />
+		<field name="NA_TABLOID" />
+		<field name="OM_DAI_PA_KAI" />
+		<field name="OM_JUURO_KU_KAI" />
+		<field name="OM_PA_KAI" />
+		<field name="PRC_1" />
+		<field name="PRC_10" />
+		<field name="PRC_16K" />
+		<field name="PRC_2" />
+		<field name="PRC_3" />
+		<field name="PRC_4" />
+		<field name="PRC_5" />
+		<field name="PRC_6" />
+		<field name="PRC_7" />
+		<field name="PRC_8" />
+		<field name="PRC_9" />
+		<field name="ROC_16K" />
+		<field name="ROC_8K" />
+		<field name="UNKNOWN_LANDSCAPE" />
+		<field name="UNKNOWN_PORTRAIT" />
+	</class>
+	<class name="android/print/PrintAttributes$Resolution" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/String;II)V" />
+		<method name="getHorizontalDpi()I" />
+		<method name="getId()Ljava/lang/String;" />
+		<method name="getLabel()Ljava/lang/String;" />
+		<method name="getVerticalDpi()I" />
+	</class>
+	<class name="android/print/PrintDocumentAdapter" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="onFinish()V" />
+		<method name="onLayout(Landroid/print/PrintAttributes;Landroid/print/PrintAttributes;Landroid/os/CancellationSignal;Landroid/print/PrintDocumentAdapter$LayoutResultCallback;Landroid/os/Bundle;)V" />
+		<method name="onStart()V" />
+		<method name="onWrite([Landroid/print/PageRange;Landroid/os/ParcelFileDescriptor;Landroid/os/CancellationSignal;Landroid/print/PrintDocumentAdapter$WriteResultCallback;)V" />
+		<field name="EXTRA_PRINT_PREVIEW" />
+	</class>
+	<class name="android/print/PrintDocumentAdapter$LayoutResultCallback" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="onLayoutCancelled()V" />
+		<method name="onLayoutFailed(Ljava/lang/CharSequence;)V" />
+		<method name="onLayoutFinished(Landroid/print/PrintDocumentInfo;Z)V" />
+	</class>
+	<class name="android/print/PrintDocumentAdapter$WriteResultCallback" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="onWriteCancelled()V" />
+		<method name="onWriteFailed(Ljava/lang/CharSequence;)V" />
+		<method name="onWriteFinished([Landroid/print/PageRange;)V" />
+	</class>
+	<class name="android/print/PrintDocumentInfo" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>()V" />
+		<method name="getContentType()I" />
+		<method name="getDataSize()J" />
+		<method name="getName()Ljava/lang/String;" />
+		<method name="getPageCount()I" />
+		<field name="CONTENT_TYPE_DOCUMENT" />
+		<field name="CONTENT_TYPE_PHOTO" />
+		<field name="CONTENT_TYPE_UNKNOWN" />
+		<field name="CREATOR" />
+		<field name="PAGE_COUNT_UNKNOWN" />
+	</class>
+	<class name="android/print/PrintDocumentInfo$Builder" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(Ljava/lang/String;)V" />
+		<method name="build()Landroid/print/PrintDocumentInfo;" />
+		<method name="setContentType(I)Landroid/print/PrintDocumentInfo$Builder;" />
+		<method name="setPageCount(I)Landroid/print/PrintDocumentInfo$Builder;" />
+	</class>
+	<class name="android/print/PrintJob" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="cancel()V" />
+		<method name="getId()Landroid/print/PrintJobId;" />
+		<method name="getInfo()Landroid/print/PrintJobInfo;" />
+		<method name="isBlocked()Z" />
+		<method name="isCancelled()Z" />
+		<method name="isCompleted()Z" />
+		<method name="isFailed()Z" />
+		<method name="isQueued()Z" />
+		<method name="isStarted()Z" />
+		<method name="restart()V" />
+	</class>
+	<class name="android/print/PrintJobId" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>()V" />
+		<field name="CREATOR" />
+	</class>
+	<class name="android/print/PrintJobInfo" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>()V" />
+		<method name="getAttributes()Landroid/print/PrintAttributes;" />
+		<method name="getCopies()I" />
+		<method name="getCreationTime()J" />
+		<method name="getId()Landroid/print/PrintJobId;" />
+		<method name="getLabel()Ljava/lang/String;" />
+		<method name="getPages()[Landroid/print/PageRange;" />
+		<method name="getPrinterId()Landroid/print/PrinterId;" />
+		<method name="getState()I" />
+		<field name="CREATOR" />
+		<field name="STATE_BLOCKED" />
+		<field name="STATE_CANCELED" />
+		<field name="STATE_COMPLETED" />
+		<field name="STATE_CREATED" />
+		<field name="STATE_FAILED" />
+		<field name="STATE_QUEUED" />
+		<field name="STATE_STARTED" />
+	</class>
+	<class name="android/print/PrintJobInfo$Builder" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(Landroid/print/PrintJobInfo;)V" />
+		<method name="build()Landroid/print/PrintJobInfo;" />
+		<method name="putAdvancedOption(Ljava/lang/String;I)V" />
+		<method name="putAdvancedOption(Ljava/lang/String;Ljava/lang/String;)V" />
+		<method name="setAttributes(Landroid/print/PrintAttributes;)V" />
+		<method name="setCopies(I)V" />
+		<method name="setPages([Landroid/print/PageRange;)V" />
+	</class>
+	<class name="android/print/PrintManager" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getPrintJobs()Ljava/util/List;" />
+		<method name="print(Ljava/lang/String;Landroid/print/PrintDocumentAdapter;Landroid/print/PrintAttributes;)Landroid/print/PrintJob;" />
+	</class>
+	<class name="android/print/PrinterCapabilitiesInfo" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>()V" />
+		<method name="getColorModes()I" />
+		<method name="getDefaults()Landroid/print/PrintAttributes;" />
+		<method name="getMediaSizes()Ljava/util/List;" />
+		<method name="getMinMargins()Landroid/print/PrintAttributes$Margins;" />
+		<method name="getResolutions()Ljava/util/List;" />
+		<field name="CREATOR" />
+	</class>
+	<class name="android/print/PrinterCapabilitiesInfo$Builder" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(Landroid/print/PrinterId;)V" />
+		<method name="addMediaSize(Landroid/print/PrintAttributes$MediaSize;Z)Landroid/print/PrinterCapabilitiesInfo$Builder;" />
+		<method name="addResolution(Landroid/print/PrintAttributes$Resolution;Z)Landroid/print/PrinterCapabilitiesInfo$Builder;" />
+		<method name="build()Landroid/print/PrinterCapabilitiesInfo;" />
+		<method name="setColorModes(II)Landroid/print/PrinterCapabilitiesInfo$Builder;" />
+		<method name="setMinMargins(Landroid/print/PrintAttributes$Margins;)Landroid/print/PrinterCapabilitiesInfo$Builder;" />
+	</class>
+	<class name="android/print/PrinterId" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>()V" />
+		<method name="getLocalId()Ljava/lang/String;" />
+		<field name="CREATOR" />
+	</class>
+	<class name="android/print/PrinterInfo" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/os/Parcelable" />
+		<method name="&lt;init>()V" />
+		<method name="getCapabilities()Landroid/print/PrinterCapabilitiesInfo;" />
+		<method name="getDescription()Ljava/lang/String;" />
+		<method name="getId()Landroid/print/PrinterId;" />
+		<method name="getName()Ljava/lang/String;" />
+		<method name="getStatus()I" />
+		<field name="CREATOR" />
+		<field name="STATUS_BUSY" />
+		<field name="STATUS_IDLE" />
+		<field name="STATUS_UNAVAILABLE" />
+	</class>
+	<class name="android/print/PrinterInfo$Builder" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(Landroid/print/PrinterId;Ljava/lang/String;I)V" />
+		<method name="&lt;init>(Landroid/print/PrinterInfo;)V" />
+		<method name="build()Landroid/print/PrinterInfo;" />
+		<method name="setCapabilities(Landroid/print/PrinterCapabilitiesInfo;)Landroid/print/PrinterInfo$Builder;" />
+		<method name="setDescription(Ljava/lang/String;)Landroid/print/PrinterInfo$Builder;" />
+		<method name="setName(Ljava/lang/String;)Landroid/print/PrinterInfo$Builder;" />
+		<method name="setStatus(I)Landroid/print/PrinterInfo$Builder;" />
+	</class>
+	<class name="android/print/pdf/PrintedPdfDocument" since="19">
+		<extends name="android/graphics/pdf/PdfDocument" />
+		<method name="&lt;init>(Landroid/content/Context;Landroid/print/PrintAttributes;)V" />
+		<method name="getPageContentRect()Landroid/graphics/Rect;" />
+		<method name="getPageHeight()I" />
+		<method name="getPageWidth()I" />
+		<method name="startPage(I)Landroid/graphics/pdf/PdfDocument$Page;" />
+	</class>
+	<class name="android/printservice/PrintDocument" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getData()Landroid/os/ParcelFileDescriptor;" />
+		<method name="getInfo()Landroid/print/PrintDocumentInfo;" />
+	</class>
+	<class name="android/printservice/PrintJob" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="block(Ljava/lang/String;)Z" />
+		<method name="cancel()Z" />
+		<method name="complete()Z" />
+		<method name="fail(Ljava/lang/String;)Z" />
+		<method name="getAdvancedIntOption(Ljava/lang/String;)I" />
+		<method name="getAdvancedStringOption(Ljava/lang/String;)Ljava/lang/String;" />
+		<method name="getDocument()Landroid/printservice/PrintDocument;" />
+		<method name="getId()Landroid/print/PrintJobId;" />
+		<method name="getInfo()Landroid/print/PrintJobInfo;" />
+		<method name="getTag()Ljava/lang/String;" />
+		<method name="hasAdvancedOption(Ljava/lang/String;)Z" />
+		<method name="isBlocked()Z" />
+		<method name="isCancelled()Z" />
+		<method name="isCompleted()Z" />
+		<method name="isFailed()Z" />
+		<method name="isQueued()Z" />
+		<method name="isStarted()Z" />
+		<method name="setTag(Ljava/lang/String;)Z" />
+		<method name="start()Z" />
+	</class>
+	<class name="android/printservice/PrintService" since="19">
+		<extends name="android/app/Service" />
+		<method name="&lt;init>()V" />
+		<method name="generatePrinterId(Ljava/lang/String;)Landroid/print/PrinterId;" />
+		<method name="getActivePrintJobs()Ljava/util/List;" />
+		<method name="onConnected()V" />
+		<method name="onCreatePrinterDiscoverySession()Landroid/printservice/PrinterDiscoverySession;" />
+		<method name="onDisconnected()V" />
+		<method name="onPrintJobQueued(Landroid/printservice/PrintJob;)V" />
+		<method name="onRequestCancelPrintJob(Landroid/printservice/PrintJob;)V" />
+		<field name="EXTRA_PRINT_JOB_INFO" />
+		<field name="SERVICE_INTERFACE" />
+		<field name="SERVICE_META_DATA" />
+	</class>
+	<class name="android/printservice/PrinterDiscoverySession" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="addPrinters(Ljava/util/List;)V" />
+		<method name="getPrinters()Ljava/util/List;" />
+		<method name="getTrackedPrinters()Ljava/util/List;" />
+		<method name="isDestroyed()Z" />
+		<method name="isPrinterDiscoveryStarted()Z" />
+		<method name="onDestroy()V" />
+		<method name="onStartPrinterDiscovery(Ljava/util/List;)V" />
+		<method name="onStartPrinterStateTracking(Landroid/print/PrinterId;)V" />
+		<method name="onStopPrinterDiscovery()V" />
+		<method name="onStopPrinterStateTracking(Landroid/print/PrinterId;)V" />
+		<method name="onValidatePrinters(Ljava/util/List;)V" />
+		<method name="removePrinters(Ljava/util/List;)V" />
+	</class>
 	<class name="android/provider/AlarmClock" since="9">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
 		<field name="ACTION_SET_ALARM" />
+		<field name="ACTION_SET_TIMER" since="19" />
+		<field name="ACTION_SHOW_ALARMS" since="19" />
+		<field name="EXTRA_DAYS" since="19" />
 		<field name="EXTRA_HOUR" />
+		<field name="EXTRA_LENGTH" since="19" />
 		<field name="EXTRA_MESSAGE" />
 		<field name="EXTRA_MINUTES" />
+		<field name="EXTRA_RINGTONE" since="19" />
 		<field name="EXTRA_SKIP_UI" since="11" />
+		<field name="EXTRA_VIBRATE" since="19" />
+		<field name="VALUE_RINGTONE_SILENT" since="19" />
 	</class>
 	<class name="android/provider/BaseColumns" since="1">
 		<extends name="java/lang/Object" />
@@ -18144,8 +19196,13 @@
 		<field name="MISSED_TYPE" />
 		<field name="NEW" />
 		<field name="NUMBER" />
+		<field name="NUMBER_PRESENTATION" since="19" />
 		<field name="OFFSET_PARAM_KEY" since="17" />
 		<field name="OUTGOING_TYPE" />
+		<field name="PRESENTATION_ALLOWED" since="19" />
+		<field name="PRESENTATION_PAYPHONE" since="19" />
+		<field name="PRESENTATION_RESTRICTED" since="19" />
+		<field name="PRESENTATION_UNKNOWN" since="19" />
 		<field name="TYPE" />
 	</class>
 	<class name="android/provider/Contacts" since="1">
@@ -19371,6 +20428,75 @@
 		<field name="CONTENT_DIRECTORY" />
 		<field name="CONTENT_URI" />
 	</class>
+	<class name="android/provider/DocumentsContract" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="buildChildDocumentsUri(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri;" />
+		<method name="buildDocumentUri(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri;" />
+		<method name="buildRecentDocumentsUri(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri;" />
+		<method name="buildRootUri(Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri;" />
+		<method name="buildRootsUri(Ljava/lang/String;)Landroid/net/Uri;" />
+		<method name="buildSearchDocumentsUri(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri;" />
+		<method name="deleteDocument(Landroid/content/ContentResolver;Landroid/net/Uri;)Z" />
+		<method name="getDocumentId(Landroid/net/Uri;)Ljava/lang/String;" />
+		<method name="getDocumentThumbnail(Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/graphics/Point;Landroid/os/CancellationSignal;)Landroid/graphics/Bitmap;" />
+		<method name="getRootId(Landroid/net/Uri;)Ljava/lang/String;" />
+		<method name="getSearchDocumentsQuery(Landroid/net/Uri;)Ljava/lang/String;" />
+		<method name="isDocumentUri(Landroid/content/Context;Landroid/net/Uri;)Z" />
+		<field name="EXTRA_ERROR" />
+		<field name="EXTRA_INFO" />
+		<field name="EXTRA_LOADING" />
+		<field name="PROVIDER_INTERFACE" />
+	</class>
+	<class name="android/provider/DocumentsContract$Document" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<field name="COLUMN_DISPLAY_NAME" />
+		<field name="COLUMN_DOCUMENT_ID" />
+		<field name="COLUMN_FLAGS" />
+		<field name="COLUMN_ICON" />
+		<field name="COLUMN_LAST_MODIFIED" />
+		<field name="COLUMN_MIME_TYPE" />
+		<field name="COLUMN_SIZE" />
+		<field name="COLUMN_SUMMARY" />
+		<field name="FLAG_DIR_PREFERS_GRID" />
+		<field name="FLAG_DIR_PREFERS_LAST_MODIFIED" />
+		<field name="FLAG_DIR_SUPPORTS_CREATE" />
+		<field name="FLAG_SUPPORTS_DELETE" />
+		<field name="FLAG_SUPPORTS_THUMBNAIL" />
+		<field name="FLAG_SUPPORTS_WRITE" />
+		<field name="MIME_TYPE_DIR" />
+	</class>
+	<class name="android/provider/DocumentsContract$Root" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<field name="COLUMN_AVAILABLE_BYTES" />
+		<field name="COLUMN_DOCUMENT_ID" />
+		<field name="COLUMN_FLAGS" />
+		<field name="COLUMN_ICON" />
+		<field name="COLUMN_MIME_TYPES" />
+		<field name="COLUMN_ROOT_ID" />
+		<field name="COLUMN_SUMMARY" />
+		<field name="COLUMN_TITLE" />
+		<field name="FLAG_LOCAL_ONLY" />
+		<field name="FLAG_SUPPORTS_CREATE" />
+		<field name="FLAG_SUPPORTS_RECENTS" />
+		<field name="FLAG_SUPPORTS_SEARCH" />
+	</class>
+	<class name="android/provider/DocumentsProvider" since="19">
+		<extends name="android/content/ContentProvider" />
+		<method name="&lt;init>()V" />
+		<method name="createDocument(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" />
+		<method name="deleteDocument(Ljava/lang/String;)V" />
+		<method name="getDocumentType(Ljava/lang/String;)Ljava/lang/String;" />
+		<method name="openDocument(Ljava/lang/String;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/os/ParcelFileDescriptor;" />
+		<method name="openDocumentThumbnail(Ljava/lang/String;Landroid/graphics/Point;Landroid/os/CancellationSignal;)Landroid/content/res/AssetFileDescriptor;" />
+		<method name="queryChildDocuments(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;" />
+		<method name="queryDocument(Ljava/lang/String;[Ljava/lang/String;)Landroid/database/Cursor;" />
+		<method name="queryRecentDocuments(Ljava/lang/String;[Ljava/lang/String;)Landroid/database/Cursor;" />
+		<method name="queryRoots([Ljava/lang/String;)Landroid/database/Cursor;" />
+		<method name="querySearchDocuments(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)Landroid/database/Cursor;" />
+	</class>
 	<class name="android/provider/LiveFolders" since="3">
 		<extends name="java/lang/Object" />
 		<implements name="android/provider/BaseColumns" />
@@ -19747,6 +20873,7 @@
 		<field name="ACTION_APPLICATION_DEVELOPMENT_SETTINGS" since="3" />
 		<field name="ACTION_APPLICATION_SETTINGS" />
 		<field name="ACTION_BLUETOOTH_SETTINGS" />
+		<field name="ACTION_CAPTIONING_SETTINGS" since="19" />
 		<field name="ACTION_DATA_ROAMING_SETTINGS" since="3" />
 		<field name="ACTION_DATE_SETTINGS" />
 		<field name="ACTION_DEVICE_INFO_SETTINGS" since="8" />
@@ -19762,7 +20889,9 @@
 		<field name="ACTION_MEMORY_CARD_SETTINGS" since="3" />
 		<field name="ACTION_NETWORK_OPERATOR_SETTINGS" since="3" />
 		<field name="ACTION_NFCSHARING_SETTINGS" since="14" />
+		<field name="ACTION_NFC_PAYMENT_SETTINGS" since="19" />
 		<field name="ACTION_NFC_SETTINGS" since="16" />
+		<field name="ACTION_PRINT_SETTINGS" since="19" />
 		<field name="ACTION_PRIVACY_SETTINGS" since="5" />
 		<field name="ACTION_QUICK_LAUNCH_SETTINGS" since="3" />
 		<field name="ACTION_SEARCH_SETTINGS" since="8" />
@@ -19879,6 +21008,11 @@
 		<field name="HTTP_PROXY" />
 		<field name="INPUT_METHOD_SELECTOR_VISIBILITY" since="11" />
 		<field name="INSTALL_NON_MARKET_APPS" />
+		<field name="LOCATION_MODE" since="19" />
+		<field name="LOCATION_MODE_BATTERY_SAVING" since="19" />
+		<field name="LOCATION_MODE_HIGH_ACCURACY" since="19" />
+		<field name="LOCATION_MODE_OFF" since="19" />
+		<field name="LOCATION_MODE_SENSORS_ONLY" since="19" />
 		<field name="LOCATION_PROVIDERS_ALLOWED" />
 		<field name="LOCK_PATTERN_ENABLED" since="8" />
 		<field name="LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED" since="8" />
@@ -20082,6 +21216,324 @@
 		<method name="set(Landroid/content/ContentProviderClient;Landroid/net/Uri;Landroid/accounts/Account;[B)V" />
 		<method name="update(Landroid/content/ContentProviderClient;Landroid/net/Uri;[B)V" />
 	</class>
+	<class name="android/provider/Telephony" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+	</class>
+	<class name="android/provider/Telephony$BaseMmsColumns" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<field name="CONTENT_CLASS" />
+		<field name="CONTENT_LOCATION" />
+		<field name="CONTENT_TYPE" />
+		<field name="DATE" />
+		<field name="DATE_SENT" />
+		<field name="DELIVERY_REPORT" />
+		<field name="DELIVERY_TIME" />
+		<field name="EXPIRY" />
+		<field name="LOCKED" />
+		<field name="MESSAGE_BOX" />
+		<field name="MESSAGE_BOX_ALL" />
+		<field name="MESSAGE_BOX_DRAFTS" />
+		<field name="MESSAGE_BOX_INBOX" />
+		<field name="MESSAGE_BOX_OUTBOX" />
+		<field name="MESSAGE_BOX_SENT" />
+		<field name="MESSAGE_CLASS" />
+		<field name="MESSAGE_ID" />
+		<field name="MESSAGE_SIZE" />
+		<field name="MESSAGE_TYPE" />
+		<field name="MMS_VERSION" />
+		<field name="PRIORITY" />
+		<field name="READ" />
+		<field name="READ_REPORT" />
+		<field name="READ_STATUS" />
+		<field name="REPORT_ALLOWED" />
+		<field name="RESPONSE_STATUS" />
+		<field name="RESPONSE_TEXT" />
+		<field name="RETRIEVE_STATUS" />
+		<field name="RETRIEVE_TEXT" />
+		<field name="RETRIEVE_TEXT_CHARSET" />
+		<field name="SEEN" />
+		<field name="STATUS" />
+		<field name="SUBJECT" />
+		<field name="SUBJECT_CHARSET" />
+		<field name="TEXT_ONLY" />
+		<field name="THREAD_ID" />
+		<field name="TRANSACTION_ID" />
+	</class>
+	<class name="android/provider/Telephony$CanonicalAddressesColumns" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<field name="ADDRESS" />
+	</class>
+	<class name="android/provider/Telephony$Carriers" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<method name="&lt;init>()V" />
+		<field name="APN" />
+		<field name="AUTH_TYPE" />
+		<field name="BEARER" />
+		<field name="CARRIER_ENABLED" />
+		<field name="CONTENT_URI" />
+		<field name="CURRENT" />
+		<field name="DEFAULT_SORT_ORDER" />
+		<field name="MCC" />
+		<field name="MMSC" />
+		<field name="MMSPORT" />
+		<field name="MMSPROXY" />
+		<field name="MNC" />
+		<field name="MVNO_MATCH_DATA" />
+		<field name="MVNO_TYPE" />
+		<field name="NAME" />
+		<field name="NUMERIC" />
+		<field name="PASSWORD" />
+		<field name="PORT" />
+		<field name="PROTOCOL" />
+		<field name="PROXY" />
+		<field name="ROAMING_PROTOCOL" />
+		<field name="SERVER" />
+		<field name="TYPE" />
+		<field name="USER" />
+	</class>
+	<class name="android/provider/Telephony$Mms" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/Telephony$BaseMmsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+		<field name="REPORT_REQUEST_URI" />
+		<field name="REPORT_STATUS_URI" />
+	</class>
+	<class name="android/provider/Telephony$Mms$Addr" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<method name="&lt;init>()V" />
+		<field name="ADDRESS" />
+		<field name="CHARSET" />
+		<field name="CONTACT_ID" />
+		<field name="MSG_ID" />
+		<field name="TYPE" />
+	</class>
+	<class name="android/provider/Telephony$Mms$Draft" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/Telephony$BaseMmsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+	</class>
+	<class name="android/provider/Telephony$Mms$Inbox" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/Telephony$BaseMmsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+	</class>
+	<class name="android/provider/Telephony$Mms$Intents" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_CHANGED_ACTION" />
+		<field name="DELETED_CONTENTS" />
+	</class>
+	<class name="android/provider/Telephony$Mms$Outbox" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/Telephony$BaseMmsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+	</class>
+	<class name="android/provider/Telephony$Mms$Part" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CHARSET" />
+		<field name="CONTENT_DISPOSITION" />
+		<field name="CONTENT_ID" />
+		<field name="CONTENT_LOCATION" />
+		<field name="CONTENT_TYPE" />
+		<field name="CT_START" />
+		<field name="CT_TYPE" />
+		<field name="FILENAME" />
+		<field name="MSG_ID" />
+		<field name="NAME" />
+		<field name="SEQ" />
+		<field name="TEXT" />
+		<field name="_DATA" />
+	</class>
+	<class name="android/provider/Telephony$Mms$Rate" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="SENT_TIME" />
+	</class>
+	<class name="android/provider/Telephony$Mms$Sent" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/Telephony$BaseMmsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+	</class>
+	<class name="android/provider/Telephony$MmsSms" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_CONVERSATIONS_URI" />
+		<field name="CONTENT_DRAFT_URI" />
+		<field name="CONTENT_FILTER_BYPHONE_URI" />
+		<field name="CONTENT_LOCKED_URI" />
+		<field name="CONTENT_UNDELIVERED_URI" />
+		<field name="CONTENT_URI" />
+		<field name="ERR_TYPE_GENERIC" />
+		<field name="ERR_TYPE_GENERIC_PERMANENT" />
+		<field name="ERR_TYPE_MMS_PROTO_PERMANENT" />
+		<field name="ERR_TYPE_MMS_PROTO_TRANSIENT" />
+		<field name="ERR_TYPE_SMS_PROTO_PERMANENT" />
+		<field name="ERR_TYPE_SMS_PROTO_TRANSIENT" />
+		<field name="ERR_TYPE_TRANSPORT_FAILURE" />
+		<field name="MMS_PROTO" />
+		<field name="NO_ERROR" />
+		<field name="SEARCH_URI" />
+		<field name="SMS_PROTO" />
+		<field name="TYPE_DISCRIMINATOR_COLUMN" />
+	</class>
+	<class name="android/provider/Telephony$MmsSms$PendingMessages" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DUE_TIME" />
+		<field name="ERROR_CODE" />
+		<field name="ERROR_TYPE" />
+		<field name="LAST_TRY" />
+		<field name="MSG_ID" />
+		<field name="MSG_TYPE" />
+		<field name="PROTO_TYPE" />
+		<field name="RETRY_INDEX" />
+	</class>
+	<class name="android/provider/Telephony$Sms" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<implements name="android/provider/Telephony$TextBasedSmsColumns" />
+		<method name="&lt;init>()V" />
+		<method name="getDefaultSmsPackage(Landroid/content/Context;)Ljava/lang/String;" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+	</class>
+	<class name="android/provider/Telephony$Sms$Conversations" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<implements name="android/provider/Telephony$TextBasedSmsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+		<field name="MESSAGE_COUNT" />
+		<field name="SNIPPET" />
+	</class>
+	<class name="android/provider/Telephony$Sms$Draft" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<implements name="android/provider/Telephony$TextBasedSmsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+	</class>
+	<class name="android/provider/Telephony$Sms$Inbox" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<implements name="android/provider/Telephony$TextBasedSmsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+	</class>
+	<class name="android/provider/Telephony$Sms$Intents" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getMessagesFromIntent(Landroid/content/Intent;)[Landroid/telephony/SmsMessage;" />
+		<field name="ACTION_CHANGE_DEFAULT" />
+		<field name="DATA_SMS_RECEIVED_ACTION" />
+		<field name="EXTRA_PACKAGE_NAME" />
+		<field name="RESULT_SMS_DUPLICATED" />
+		<field name="RESULT_SMS_GENERIC_ERROR" />
+		<field name="RESULT_SMS_HANDLED" />
+		<field name="RESULT_SMS_OUT_OF_MEMORY" />
+		<field name="RESULT_SMS_UNSUPPORTED" />
+		<field name="SIM_FULL_ACTION" />
+		<field name="SMS_CB_RECEIVED_ACTION" />
+		<field name="SMS_DELIVER_ACTION" />
+		<field name="SMS_EMERGENCY_CB_RECEIVED_ACTION" />
+		<field name="SMS_RECEIVED_ACTION" />
+		<field name="SMS_REJECTED_ACTION" />
+		<field name="SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION" />
+		<field name="WAP_PUSH_DELIVER_ACTION" />
+		<field name="WAP_PUSH_RECEIVED_ACTION" />
+	</class>
+	<class name="android/provider/Telephony$Sms$Outbox" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<implements name="android/provider/Telephony$TextBasedSmsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+	</class>
+	<class name="android/provider/Telephony$Sms$Sent" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<implements name="android/provider/Telephony$TextBasedSmsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="CONTENT_URI" />
+		<field name="DEFAULT_SORT_ORDER" />
+	</class>
+	<class name="android/provider/Telephony$TextBasedSmsColumns" since="19">
+		<extends name="java/lang/Object" />
+		<field name="ADDRESS" />
+		<field name="BODY" />
+		<field name="DATE" />
+		<field name="DATE_SENT" />
+		<field name="ERROR_CODE" />
+		<field name="LOCKED" />
+		<field name="MESSAGE_TYPE_ALL" />
+		<field name="MESSAGE_TYPE_DRAFT" />
+		<field name="MESSAGE_TYPE_FAILED" />
+		<field name="MESSAGE_TYPE_INBOX" />
+		<field name="MESSAGE_TYPE_OUTBOX" />
+		<field name="MESSAGE_TYPE_QUEUED" />
+		<field name="MESSAGE_TYPE_SENT" />
+		<field name="PERSON" />
+		<field name="PROTOCOL" />
+		<field name="READ" />
+		<field name="REPLY_PATH_PRESENT" />
+		<field name="SEEN" />
+		<field name="SERVICE_CENTER" />
+		<field name="STATUS" />
+		<field name="STATUS_COMPLETE" />
+		<field name="STATUS_FAILED" />
+		<field name="STATUS_NONE" />
+		<field name="STATUS_PENDING" />
+		<field name="SUBJECT" />
+		<field name="THREAD_ID" />
+		<field name="TYPE" />
+	</class>
+	<class name="android/provider/Telephony$Threads" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/Telephony$ThreadsColumns" />
+		<method name="&lt;init>()V" />
+		<field name="BROADCAST_THREAD" />
+		<field name="COMMON_THREAD" />
+		<field name="CONTENT_URI" />
+		<field name="OBSOLETE_THREADS_URI" />
+	</class>
+	<class name="android/provider/Telephony$ThreadsColumns" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="android/provider/BaseColumns" />
+		<field name="DATE" />
+		<field name="ERROR" />
+		<field name="HAS_ATTACHMENT" />
+		<field name="MESSAGE_COUNT" />
+		<field name="READ" />
+		<field name="RECIPIENT_IDS" />
+		<field name="SNIPPET" />
+		<field name="SNIPPET_CHARSET" />
+		<field name="TYPE" />
+	</class>
 	<class name="android/provider/UserDictionary" since="3">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -20216,6 +21668,7 @@
 		<method name="resize(I)V" />
 		<method name="setFromFieldPacker(IILandroid/renderscript/FieldPacker;)V" />
 		<method name="setFromFieldPacker(ILandroid/renderscript/FieldPacker;)V" />
+		<method name="setOnBufferAvailableListener(Landroid/renderscript/Allocation$OnBufferAvailableListener;)V" since="19" />
 		<method name="setSurface(Landroid/view/Surface;)V" since="16" />
 		<method name="syncAll(I)V" />
 		<field name="USAGE_GRAPHICS_CONSTANTS" />
@@ -20235,6 +21688,10 @@
 		<field name="MIPMAP_NONE" />
 		<field name="MIPMAP_ON_SYNC_TO_TEXTURE" />
 	</class>
+	<class name="android/renderscript/Allocation$OnBufferAvailableListener" since="19">
+		<extends name="java/lang/Object" />
+		<method name="onBufferAvailable(Landroid/renderscript/Allocation;)V" />
+	</class>
 	<class name="android/renderscript/AllocationAdapter" since="11">
 		<extends name="android/renderscript/Allocation" />
 		<method name="&lt;init>()V" />
@@ -20375,6 +21832,7 @@
 		<method name="U8_2(Landroid/renderscript/RenderScript;)Landroid/renderscript/Element;" since="14" />
 		<method name="U8_3(Landroid/renderscript/RenderScript;)Landroid/renderscript/Element;" since="14" />
 		<method name="U8_4(Landroid/renderscript/RenderScript;)Landroid/renderscript/Element;" />
+		<method name="YUV(Landroid/renderscript/RenderScript;)Landroid/renderscript/Element;" since="19" />
 		<method name="createPixel(Landroid/renderscript/RenderScript;Landroid/renderscript/Element$DataType;Landroid/renderscript/Element$DataKind;)Landroid/renderscript/Element;" />
 		<method name="createVector(Landroid/renderscript/RenderScript;Landroid/renderscript/Element$DataType;I)Landroid/renderscript/Element;" />
 		<method name="getBytesSize()I" since="16" />
@@ -21248,9 +22706,12 @@
 	<class name="android/renderscript/ScriptIntrinsicColorMatrix" since="17">
 		<extends name="android/renderscript/ScriptIntrinsic" />
 		<method name="&lt;init>()V" />
+		<method name="create(Landroid/renderscript/RenderScript;)Landroid/renderscript/ScriptIntrinsicColorMatrix;" since="19" />
 		<method name="create(Landroid/renderscript/RenderScript;Landroid/renderscript/Element;)Landroid/renderscript/ScriptIntrinsicColorMatrix;" />
 		<method name="forEach(Landroid/renderscript/Allocation;Landroid/renderscript/Allocation;)V" />
 		<method name="getKernelID()Landroid/renderscript/Script$KernelID;" />
+		<method name="setAdd(FFFF)V" since="19" />
+		<method name="setAdd(Landroid/renderscript/Float4;)V" since="19" />
 		<method name="setColorMatrix(Landroid/renderscript/Matrix3f;)V" />
 		<method name="setColorMatrix(Landroid/renderscript/Matrix4f;)V" />
 		<method name="setGreyscale()V" />
@@ -21277,6 +22738,17 @@
 		<method name="setCoefficients([F)V" />
 		<method name="setInput(Landroid/renderscript/Allocation;)V" />
 	</class>
+	<class name="android/renderscript/ScriptIntrinsicHistogram" since="19">
+		<extends name="android/renderscript/ScriptIntrinsic" />
+		<method name="&lt;init>()V" />
+		<method name="create(Landroid/renderscript/RenderScript;Landroid/renderscript/Element;)Landroid/renderscript/ScriptIntrinsicHistogram;" />
+		<method name="forEach(Landroid/renderscript/Allocation;)V" />
+		<method name="forEach_Dot(Landroid/renderscript/Allocation;)V" />
+		<method name="getFieldID_Input()Landroid/renderscript/Script$FieldID;" />
+		<method name="getKernelID_Separate()Landroid/renderscript/Script$KernelID;" />
+		<method name="setDotCoefficients(FFFF)V" />
+		<method name="setOutput(Landroid/renderscript/Allocation;)V" />
+	</class>
 	<class name="android/renderscript/ScriptIntrinsicLUT" since="17">
 		<extends name="android/renderscript/ScriptIntrinsic" />
 		<method name="&lt;init>()V" />
@@ -21399,41 +22871,6 @@
 		<implements name="android/sax/EndTextElementListener" />
 		<implements name="android/sax/StartElementListener" />
 	</class>
-	<class name="android/security/AndroidKeyPairGeneratorSpec" since="18">
-		<extends name="java/lang/Object" />
-		<implements name="java/security/spec/AlgorithmParameterSpec" />
-		<method name="&lt;init>()V" />
-		<method name="getContext()Landroid/content/Context;" />
-		<method name="getEndDate()Ljava/util/Date;" />
-		<method name="getKeystoreAlias()Ljava/lang/String;" />
-		<method name="getSerialNumber()Ljava/math/BigInteger;" />
-		<method name="getStartDate()Ljava/util/Date;" />
-		<method name="getSubjectDN()Ljavax/security/auth/x500/X500Principal;" />
-		<method name="isEncryptionRequired()Z" />
-	</class>
-	<class name="android/security/AndroidKeyPairGeneratorSpec$Builder" since="18">
-		<extends name="java/lang/Object" />
-		<method name="&lt;init>(Landroid/content/Context;)V" />
-		<method name="build()Landroid/security/AndroidKeyPairGeneratorSpec;" />
-		<method name="setAlias(Ljava/lang/String;)Landroid/security/AndroidKeyPairGeneratorSpec$Builder;" />
-		<method name="setEncryptionRequired()Landroid/security/AndroidKeyPairGeneratorSpec$Builder;" />
-		<method name="setEndDate(Ljava/util/Date;)Landroid/security/AndroidKeyPairGeneratorSpec$Builder;" />
-		<method name="setSerialNumber(Ljava/math/BigInteger;)Landroid/security/AndroidKeyPairGeneratorSpec$Builder;" />
-		<method name="setStartDate(Ljava/util/Date;)Landroid/security/AndroidKeyPairGeneratorSpec$Builder;" />
-		<method name="setSubject(Ljavax/security/auth/x500/X500Principal;)Landroid/security/AndroidKeyPairGeneratorSpec$Builder;" />
-	</class>
-	<class name="android/security/AndroidKeyStoreParameter" since="18">
-		<extends name="java/lang/Object" />
-		<implements name="java/security/KeyStore$ProtectionParameter" />
-		<method name="&lt;init>()V" />
-		<method name="isEncryptionRequired()Z" />
-	</class>
-	<class name="android/security/AndroidKeyStoreParameter$Builder" since="18">
-		<extends name="java/lang/Object" />
-		<method name="&lt;init>(Landroid/content/Context;)V" />
-		<method name="build()Landroid/security/AndroidKeyStoreParameter;" />
-		<method name="setEncryptionRequired()Landroid/security/AndroidKeyStoreParameter$Builder;" />
-	</class>
 	<class name="android/security/KeyChain" since="14">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -21463,8 +22900,11 @@
 		<extends name="java/lang/Object" />
 		<implements name="java/security/spec/AlgorithmParameterSpec" />
 		<method name="&lt;init>()V" />
+		<method name="getAlgorithmParameterSpec()Ljava/security/spec/AlgorithmParameterSpec;" since="19" />
 		<method name="getContext()Landroid/content/Context;" />
 		<method name="getEndDate()Ljava/util/Date;" />
+		<method name="getKeySize()I" since="19" />
+		<method name="getKeyType()Ljava/lang/String;" since="19" />
 		<method name="getKeystoreAlias()Ljava/lang/String;" />
 		<method name="getSerialNumber()Ljava/math/BigInteger;" />
 		<method name="getStartDate()Ljava/util/Date;" />
@@ -21475,9 +22915,12 @@
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(Landroid/content/Context;)V" />
 		<method name="build()Landroid/security/KeyPairGeneratorSpec;" />
+		<method name="setAlgorithmParameterSpec(Ljava/security/spec/AlgorithmParameterSpec;)Landroid/security/KeyPairGeneratorSpec$Builder;" since="19" />
 		<method name="setAlias(Ljava/lang/String;)Landroid/security/KeyPairGeneratorSpec$Builder;" />
 		<method name="setEncryptionRequired()Landroid/security/KeyPairGeneratorSpec$Builder;" />
 		<method name="setEndDate(Ljava/util/Date;)Landroid/security/KeyPairGeneratorSpec$Builder;" />
+		<method name="setKeySize(I)Landroid/security/KeyPairGeneratorSpec$Builder;" since="19" />
+		<method name="setKeyType(Ljava/lang/String;)Landroid/security/KeyPairGeneratorSpec$Builder;" since="19" />
 		<method name="setSerialNumber(Ljava/math/BigInteger;)Landroid/security/KeyPairGeneratorSpec$Builder;" />
 		<method name="setStartDate(Ljava/util/Date;)Landroid/security/KeyPairGeneratorSpec$Builder;" />
 		<method name="setSubject(Ljavax/security/auth/x500/X500Principal;)Landroid/security/KeyPairGeneratorSpec$Builder;" />
@@ -21705,6 +23148,7 @@
 	<class name="android/speech/tts/SynthesisRequest" since="14">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(Ljava/lang/String;Landroid/os/Bundle;)V" />
+		<method name="getCallerUid()I" since="19" />
 		<method name="getCountry()Ljava/lang/String;" />
 		<method name="getLanguage()Ljava/lang/String;" />
 		<method name="getParams()Landroid/os/Bundle;" />
@@ -22163,6 +23607,8 @@
 		<method name="getDeviceSoftwareVersion()Ljava/lang/String;" />
 		<method name="getGroupIdLevel1()Ljava/lang/String;" since="18" />
 		<method name="getLine1Number()Ljava/lang/String;" />
+		<method name="getMmsUAProfUrl()Ljava/lang/String;" since="19" />
+		<method name="getMmsUserAgent()Ljava/lang/String;" since="19" />
 		<method name="getNeighboringCellInfo()Ljava/util/List;" since="3" />
 		<method name="getNetworkCountryIso()Ljava/lang/String;" />
 		<method name="getNetworkOperator()Ljava/lang/String;" />
@@ -23253,46 +24699,6 @@
 		<method name="beforeTextChanged(Ljava/lang/CharSequence;III)V" />
 		<method name="onTextChanged(Ljava/lang/CharSequence;III)V" />
 	</class>
-	<class name="android/text/bidi/BidiFormatter" since="18">
-		<extends name="java/lang/Object" />
-		<method name="&lt;init>()V" />
-		<method name="dirAttr(Ljava/lang/String;)Ljava/lang/String;" />
-		<method name="dirAttr(Ljava/lang/String;Landroid/text/TextDirectionHeuristic;)Ljava/lang/String;" />
-		<method name="dirAttr(Z)Ljava/lang/String;" />
-		<method name="dirAttrValue(Ljava/lang/String;)Ljava/lang/String;" />
-		<method name="dirAttrValue(Ljava/lang/String;Landroid/text/TextDirectionHeuristic;)Ljava/lang/String;" />
-		<method name="dirAttrValue(Z)Ljava/lang/String;" />
-		<method name="endEdge()Ljava/lang/String;" />
-		<method name="getInstance()Landroid/text/bidi/BidiFormatter;" />
-		<method name="getInstance(Ljava/util/Locale;)Landroid/text/bidi/BidiFormatter;" />
-		<method name="getInstance(Z)Landroid/text/bidi/BidiFormatter;" />
-		<method name="getStereoReset()Z" />
-		<method name="isRtl(Ljava/lang/String;)Z" />
-		<method name="isRtlContext()Z" />
-		<method name="mark()Ljava/lang/String;" />
-		<method name="markAfter(Ljava/lang/String;)Ljava/lang/String;" />
-		<method name="markAfter(Ljava/lang/String;Landroid/text/TextDirectionHeuristic;)Ljava/lang/String;" />
-		<method name="markBefore(Ljava/lang/String;)Ljava/lang/String;" />
-		<method name="markBefore(Ljava/lang/String;Landroid/text/TextDirectionHeuristic;)Ljava/lang/String;" />
-		<method name="spanWrap(Ljava/lang/String;)Ljava/lang/String;" />
-		<method name="spanWrap(Ljava/lang/String;Landroid/text/TextDirectionHeuristic;)Ljava/lang/String;" />
-		<method name="spanWrap(Ljava/lang/String;Landroid/text/TextDirectionHeuristic;Z)Ljava/lang/String;" />
-		<method name="spanWrap(Ljava/lang/String;Z)Ljava/lang/String;" />
-		<method name="startEdge()Ljava/lang/String;" />
-		<method name="unicodeWrap(Ljava/lang/String;)Ljava/lang/String;" />
-		<method name="unicodeWrap(Ljava/lang/String;Landroid/text/TextDirectionHeuristic;)Ljava/lang/String;" />
-		<method name="unicodeWrap(Ljava/lang/String;Landroid/text/TextDirectionHeuristic;Z)Ljava/lang/String;" />
-		<method name="unicodeWrap(Ljava/lang/String;Z)Ljava/lang/String;" />
-	</class>
-	<class name="android/text/bidi/BidiFormatter$Builder" since="18">
-		<extends name="java/lang/Object" />
-		<method name="&lt;init>()V" />
-		<method name="&lt;init>(Ljava/util/Locale;)V" />
-		<method name="&lt;init>(Z)V" />
-		<method name="build()Landroid/text/bidi/BidiFormatter;" />
-		<method name="setTextDirectionHeuristic(Landroid/text/TextDirectionHeuristic;)Landroid/text/bidi/BidiFormatter$Builder;" />
-		<method name="stereoReset(Z)Landroid/text/bidi/BidiFormatter$Builder;" />
-	</class>
 	<class name="android/text/format/DateFormat" since="3">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -23548,6 +24954,8 @@
 		<method name="getMetaState(JI)I" since="3" />
 		<method name="getMetaState(Ljava/lang/CharSequence;)I" />
 		<method name="getMetaState(Ljava/lang/CharSequence;I)I" />
+		<method name="getMetaState(Ljava/lang/CharSequence;ILandroid/view/KeyEvent;)I" since="19" />
+		<method name="getMetaState(Ljava/lang/CharSequence;Landroid/view/KeyEvent;)I" since="19" />
 		<method name="handleKeyDown(JILandroid/view/KeyEvent;)J" since="3" />
 		<method name="handleKeyUp(JILandroid/view/KeyEvent;)J" since="3" />
 		<method name="isMetaTracker(Ljava/lang/CharSequence;Ljava/lang/Object;)Z" />
@@ -24017,6 +25425,125 @@
 		<method name="tokenize(Ljava/lang/CharSequence;)[Landroid/text/util/Rfc822Token;" />
 		<method name="tokenize(Ljava/lang/CharSequence;Ljava/util/Collection;)V" since="8" />
 	</class>
+	<class name="android/transition/AutoTransition" since="19">
+		<extends name="android/transition/TransitionSet" />
+		<method name="&lt;init>()V" />
+	</class>
+	<class name="android/transition/ChangeBounds" since="19">
+		<extends name="android/transition/Transition" />
+		<method name="&lt;init>()V" />
+		<method name="setReparent(Z)V" />
+		<method name="setResizeClip(Z)V" />
+	</class>
+	<class name="android/transition/Fade" since="19">
+		<extends name="android/transition/Visibility" />
+		<method name="&lt;init>()V" />
+		<method name="&lt;init>(I)V" />
+		<field name="IN" />
+		<field name="OUT" />
+	</class>
+	<class name="android/transition/Scene" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>(Landroid/view/ViewGroup;)V" />
+		<method name="&lt;init>(Landroid/view/ViewGroup;Landroid/view/ViewGroup;)V" />
+		<method name="enter()V" />
+		<method name="exit()V" />
+		<method name="getSceneForLayout(Landroid/view/ViewGroup;ILandroid/content/Context;)Landroid/transition/Scene;" />
+		<method name="getSceneRoot()Landroid/view/ViewGroup;" />
+		<method name="setEnterAction(Ljava/lang/Runnable;)V" />
+		<method name="setExitAction(Ljava/lang/Runnable;)V" />
+	</class>
+	<class name="android/transition/Transition" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="java/lang/Cloneable" />
+		<method name="&lt;init>()V" />
+		<method name="addListener(Landroid/transition/Transition$TransitionListener;)Landroid/transition/Transition;" />
+		<method name="addTarget(I)Landroid/transition/Transition;" />
+		<method name="addTarget(Landroid/view/View;)Landroid/transition/Transition;" />
+		<method name="captureEndValues(Landroid/transition/TransitionValues;)V" />
+		<method name="captureStartValues(Landroid/transition/TransitionValues;)V" />
+		<method name="clone()Landroid/transition/Transition;" />
+		<method name="createAnimator(Landroid/view/ViewGroup;Landroid/transition/TransitionValues;Landroid/transition/TransitionValues;)Landroid/animation/Animator;" />
+		<method name="excludeChildren(IZ)Landroid/transition/Transition;" />
+		<method name="excludeChildren(Landroid/view/View;Z)Landroid/transition/Transition;" />
+		<method name="excludeChildren(Ljava/lang/Class;Z)Landroid/transition/Transition;" />
+		<method name="excludeTarget(IZ)Landroid/transition/Transition;" />
+		<method name="excludeTarget(Landroid/view/View;Z)Landroid/transition/Transition;" />
+		<method name="excludeTarget(Ljava/lang/Class;Z)Landroid/transition/Transition;" />
+		<method name="getDuration()J" />
+		<method name="getInterpolator()Landroid/animation/TimeInterpolator;" />
+		<method name="getName()Ljava/lang/String;" />
+		<method name="getStartDelay()J" />
+		<method name="getTargetIds()Ljava/util/List;" />
+		<method name="getTargets()Ljava/util/List;" />
+		<method name="getTransitionProperties()[Ljava/lang/String;" />
+		<method name="getTransitionValues(Landroid/view/View;Z)Landroid/transition/TransitionValues;" />
+		<method name="removeListener(Landroid/transition/Transition$TransitionListener;)Landroid/transition/Transition;" />
+		<method name="removeTarget(I)Landroid/transition/Transition;" />
+		<method name="removeTarget(Landroid/view/View;)Landroid/transition/Transition;" />
+		<method name="setDuration(J)Landroid/transition/Transition;" />
+		<method name="setInterpolator(Landroid/animation/TimeInterpolator;)Landroid/transition/Transition;" />
+		<method name="setStartDelay(J)Landroid/transition/Transition;" />
+	</class>
+	<class name="android/transition/Transition$TransitionListener" since="19">
+		<extends name="java/lang/Object" />
+		<method name="onTransitionCancel(Landroid/transition/Transition;)V" />
+		<method name="onTransitionEnd(Landroid/transition/Transition;)V" />
+		<method name="onTransitionPause(Landroid/transition/Transition;)V" />
+		<method name="onTransitionResume(Landroid/transition/Transition;)V" />
+		<method name="onTransitionStart(Landroid/transition/Transition;)V" />
+	</class>
+	<class name="android/transition/TransitionInflater" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="from(Landroid/content/Context;)Landroid/transition/TransitionInflater;" />
+		<method name="inflateTransition(I)Landroid/transition/Transition;" />
+		<method name="inflateTransitionManager(ILandroid/view/ViewGroup;)Landroid/transition/TransitionManager;" />
+	</class>
+	<class name="android/transition/TransitionManager" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="beginDelayedTransition(Landroid/view/ViewGroup;)V" />
+		<method name="beginDelayedTransition(Landroid/view/ViewGroup;Landroid/transition/Transition;)V" />
+		<method name="go(Landroid/transition/Scene;)V" />
+		<method name="go(Landroid/transition/Scene;Landroid/transition/Transition;)V" />
+		<method name="setTransition(Landroid/transition/Scene;Landroid/transition/Scene;Landroid/transition/Transition;)V" />
+		<method name="setTransition(Landroid/transition/Scene;Landroid/transition/Transition;)V" />
+		<method name="transitionTo(Landroid/transition/Scene;)V" />
+	</class>
+	<class name="android/transition/TransitionSet" since="19">
+		<extends name="android/transition/Transition" />
+		<method name="&lt;init>()V" />
+		<method name="addListener(Landroid/transition/Transition$TransitionListener;)Landroid/transition/TransitionSet;" />
+		<method name="addTarget(I)Landroid/transition/TransitionSet;" />
+		<method name="addTarget(Landroid/view/View;)Landroid/transition/TransitionSet;" />
+		<method name="addTransition(Landroid/transition/Transition;)Landroid/transition/TransitionSet;" />
+		<method name="clone()Landroid/transition/TransitionSet;" />
+		<method name="getOrdering()I" />
+		<method name="removeListener(Landroid/transition/Transition$TransitionListener;)Landroid/transition/TransitionSet;" />
+		<method name="removeTarget(I)Landroid/transition/TransitionSet;" />
+		<method name="removeTarget(Landroid/view/View;)Landroid/transition/TransitionSet;" />
+		<method name="removeTransition(Landroid/transition/Transition;)Landroid/transition/TransitionSet;" />
+		<method name="setDuration(J)Landroid/transition/TransitionSet;" />
+		<method name="setInterpolator(Landroid/animation/TimeInterpolator;)Landroid/transition/TransitionSet;" />
+		<method name="setOrdering(I)Landroid/transition/TransitionSet;" />
+		<method name="setStartDelay(J)Landroid/transition/TransitionSet;" />
+		<field name="ORDERING_SEQUENTIAL" />
+		<field name="ORDERING_TOGETHER" />
+	</class>
+	<class name="android/transition/TransitionValues" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<field name="values" />
+		<field name="view" />
+	</class>
+	<class name="android/transition/Visibility" since="19">
+		<extends name="android/transition/Transition" />
+		<method name="&lt;init>()V" />
+		<method name="isVisible(Landroid/transition/TransitionValues;)Z" />
+		<method name="onAppear(Landroid/view/ViewGroup;Landroid/transition/TransitionValues;ILandroid/transition/TransitionValues;I)Landroid/animation/Animator;" />
+		<method name="onDisappear(Landroid/view/ViewGroup;Landroid/transition/TransitionValues;ILandroid/transition/TransitionValues;I)Landroid/animation/Animator;" />
+	</class>
 	<class name="android/util/AndroidException" since="1">
 		<extends name="java/lang/Exception" />
 		<method name="&lt;init>()V" />
@@ -24031,6 +25558,22 @@
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/Throwable;)V" since="11" />
 	</class>
+	<class name="android/util/ArrayMap" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="java/util/Map" />
+		<method name="&lt;init>()V" />
+		<method name="&lt;init>(I)V" />
+		<method name="&lt;init>(Landroid/util/ArrayMap;)V" />
+		<method name="containsAll(Ljava/util/Collection;)Z" />
+		<method name="ensureCapacity(I)V" />
+		<method name="keyAt(I)Ljava/lang/Object;" />
+		<method name="putAll(Landroid/util/ArrayMap;)V" />
+		<method name="removeAll(Ljava/util/Collection;)Z" />
+		<method name="removeAt(I)Ljava/lang/Object;" />
+		<method name="retainAll(Ljava/util/Collection;)Z" />
+		<method name="setValueAt(ILjava/lang/Object;)Ljava/lang/Object;" />
+		<method name="valueAt(I)Ljava/lang/Object;" />
+	</class>
 	<class name="android/util/AtomicFile" since="17">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(Ljava/io/File;)V" />
@@ -24116,6 +25659,7 @@
 		<method name="equals(Landroid/util/DisplayMetrics;)Z" since="17" />
 		<method name="setTo(Landroid/util/DisplayMetrics;)V" />
 		<method name="setToDefaults()V" />
+		<field name="DENSITY_400" since="19" />
 		<field name="DENSITY_DEFAULT" since="4" />
 		<field name="DENSITY_HIGH" since="4" />
 		<field name="DENSITY_LOW" since="4" />
@@ -24233,6 +25777,14 @@
 		<method name="value(Ljava/lang/String;)Landroid/util/JsonWriter;" />
 		<method name="value(Z)Landroid/util/JsonWriter;" />
 	</class>
+	<class name="android/util/LayoutDirection" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<field name="INHERIT" />
+		<field name="LOCALE" />
+		<field name="LTR" />
+		<field name="RTL" />
+	</class>
 	<class name="android/util/Log" since="1">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -24378,15 +25930,6 @@
 		<method name="of(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;)Landroid/util/Property;" />
 		<method name="set(Ljava/lang/Object;Ljava/lang/Object;)V" />
 	</class>
-	<class name="android/util/PropertyValueModel" since="18">
-		<extends name="android/util/ValueModel" />
-		<method name="&lt;init>()V" />
-		<method name="getHost()Ljava/lang/Object;" />
-		<method name="getProperty()Landroid/util/Property;" />
-		<method name="of(Ljava/lang/Object;Landroid/util/Property;)Landroid/util/PropertyValueModel;" />
-		<method name="of(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;)Landroid/util/PropertyValueModel;" />
-		<method name="of(Ljava/lang/Object;Ljava/lang/String;)Landroid/util/PropertyValueModel;" />
-	</class>
 	<class name="android/util/SparseArray" since="1">
 		<extends name="java/lang/Object" />
 		<implements name="java/lang/Cloneable" since="14" />
@@ -24404,6 +25947,7 @@
 		<method name="put(ILjava/lang/Object;)V" />
 		<method name="remove(I)V" />
 		<method name="removeAt(I)V" since="11" />
+		<method name="removeAtRange(II)V" since="19" />
 		<method name="setValueAt(ILjava/lang/Object;)V" />
 		<method name="size()I" />
 		<method name="valueAt(I)Ljava/lang/Object;" />
@@ -24560,14 +26104,6 @@
 		<field name="string" />
 		<field name="type" />
 	</class>
-	<class name="android/util/ValueModel" since="18">
-		<extends name="java/lang/Object" />
-		<method name="&lt;init>()V" />
-		<method name="get()Ljava/lang/Object;" />
-		<method name="getType()Ljava/lang/Class;" />
-		<method name="set(Ljava/lang/Object;)V" />
-		<field name="EMPTY" />
-	</class>
 	<class name="android/util/Xml" since="1">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -24700,6 +26236,8 @@
 		<method name="getWidth()I" />
 		<method name="isValid()Z" since="17" />
 		<field name="DEFAULT_DISPLAY" />
+		<field name="FLAG_PRESENTATION" since="19" />
+		<field name="FLAG_PRIVATE" since="19" />
 		<field name="FLAG_SECURE" since="17" />
 		<field name="FLAG_SUPPORTS_PROTECTED_BUFFERS" since="17" />
 	</class>
@@ -24823,6 +26361,7 @@
 		<extends name="java/lang/Object" />
 		<implements name="android/os/Parcelable" />
 		<method name="&lt;init>()V" />
+		<method name="getControllerNumber()I" since="19" />
 		<method name="getDescriptor()Ljava/lang/String;" since="16" />
 		<method name="getDevice(I)Landroid/view/InputDevice;" />
 		<method name="getDeviceIds()[I" />
@@ -24833,8 +26372,11 @@
 		<method name="getMotionRange(II)Landroid/view/InputDevice$MotionRange;" since="12" />
 		<method name="getMotionRanges()Ljava/util/List;" since="12" />
 		<method name="getName()Ljava/lang/String;" />
+		<method name="getProductId()I" since="19" />
 		<method name="getSources()I" />
+		<method name="getVendorId()I" since="19" />
 		<method name="getVibrator()Landroid/os/Vibrator;" since="16" />
+		<method name="hasKeys([I)[Z" since="19" />
 		<method name="isVirtual()Z" since="16" />
 		<field name="CREATOR" />
 		<field name="KEYBOARD_TYPE_ALPHABETIC" />
@@ -25152,6 +26694,7 @@
 		<field name="KEYCODE_LEFT_BRACKET" />
 		<field name="KEYCODE_M" />
 		<field name="KEYCODE_MANNER_MODE" since="14" />
+		<field name="KEYCODE_MEDIA_AUDIO_TRACK" since="19" />
 		<field name="KEYCODE_MEDIA_CLOSE" since="11" />
 		<field name="KEYCODE_MEDIA_EJECT" since="11" />
 		<field name="KEYCODE_MEDIA_FAST_FORWARD" since="3" />
@@ -25428,6 +26971,7 @@
 		<extends name="java/lang/Object" />
 		<implements name="android/os/Parcelable" />
 		<method name="&lt;init>()V" />
+		<method name="actionToString(I)Ljava/lang/String;" since="19" />
 		<method name="addBatch(JFFFFI)V" />
 		<method name="addBatch(J[Landroid/view/MotionEvent$PointerCoords;I)V" since="9" />
 		<method name="axisFromString(Ljava/lang/String;)I" since="12" />
@@ -25641,6 +27185,7 @@
 	<class name="android/view/ScaleGestureDetector" since="8">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(Landroid/content/Context;Landroid/view/ScaleGestureDetector$OnScaleGestureListener;)V" />
+		<method name="&lt;init>(Landroid/content/Context;Landroid/view/ScaleGestureDetector$OnScaleGestureListener;Landroid/os/Handler;)V" since="19" />
 		<method name="getCurrentSpan()F" />
 		<method name="getCurrentSpanX()F" since="11" />
 		<method name="getCurrentSpanY()F" since="11" />
@@ -25653,7 +27198,9 @@
 		<method name="getScaleFactor()F" />
 		<method name="getTimeDelta()J" />
 		<method name="isInProgress()Z" />
+		<method name="isQuickScaleEnabled()Z" since="19" />
 		<method name="onTouchEvent(Landroid/view/MotionEvent;)Z" />
+		<method name="setQuickScaleEnabled(Z)V" since="19" />
 	</class>
 	<class name="android/view/ScaleGestureDetector$OnScaleGestureListener" since="8">
 		<extends name="java/lang/Object" />
@@ -25736,6 +27283,7 @@
 	</class>
 	<class name="android/view/Surface$OutOfResourcesException" since="1">
 		<extends name="java/lang/Exception" />
+		<extends name="java/lang/RuntimeException" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 	</class>
@@ -25860,9 +27408,13 @@
 		<method name="buildDrawingCache(Z)V" since="4" />
 		<method name="buildLayer()V" since="12" />
 		<method name="callOnClick()Z" since="15" />
+		<method name="canResolveLayoutDirection()Z" since="19" />
+		<method name="canResolveTextAlignment()Z" since="19" />
+		<method name="canResolveTextDirection()Z" since="19" />
 		<method name="canScrollHorizontally(I)Z" since="14" />
 		<method name="canScrollVertically(I)Z" since="14" />
 		<method name="cancelLongPress()V" />
+		<method name="cancelPendingInputEvents()V" since="19" />
 		<method name="checkInputConnectionProxy(Landroid/view/View;)Z" since="3" />
 		<method name="clearAnimation()V" />
 		<method name="clearFocus()V" />
@@ -25913,6 +27465,7 @@
 		<method name="focusSearch(I)Landroid/view/View;" />
 		<method name="forceLayout()V" />
 		<method name="generateViewId()I" since="17" />
+		<method name="getAccessibilityLiveRegion()I" since="19" />
 		<method name="getAccessibilityNodeProvider()Landroid/view/accessibility/AccessibilityNodeProvider;" since="16" />
 		<method name="getAlpha()F" since="11" />
 		<method name="getAnimation()Landroid/view/animation/Animation;" />
@@ -26045,6 +27598,7 @@
 		<method name="invalidate(IIII)V" />
 		<method name="invalidate(Landroid/graphics/Rect;)V" />
 		<method name="isActivated()Z" since="11" />
+		<method name="isAttachedToWindow()Z" since="19" />
 		<method name="isClickable()Z" />
 		<method name="isDirty()Z" since="11" />
 		<method name="isDrawingCacheEnabled()Z" />
@@ -26061,6 +27615,8 @@
 		<method name="isInEditMode()Z" since="3" />
 		<method name="isInLayout()Z" since="18" />
 		<method name="isInTouchMode()Z" />
+		<method name="isLaidOut()Z" since="19" />
+		<method name="isLayoutDirectionResolved()Z" since="19" />
 		<method name="isLayoutRequested()Z" />
 		<method name="isLongClickable()Z" />
 		<method name="isOpaque()Z" since="7" />
@@ -26074,6 +27630,8 @@
 		<method name="isSelected()Z" />
 		<method name="isShown()Z" />
 		<method name="isSoundEffectsEnabled()Z" />
+		<method name="isTextAlignmentResolved()Z" since="19" />
+		<method name="isTextDirectionResolved()Z" since="19" />
 		<method name="isVerticalFadingEdgeEnabled()Z" />
 		<method name="isVerticalScrollBarEnabled()Z" />
 		<method name="jumpDrawablesToCurrentState()V" since="11" />
@@ -26085,6 +27643,7 @@
 		<method name="onAnimationEnd()V" />
 		<method name="onAnimationStart()V" />
 		<method name="onAttachedToWindow()V" />
+		<method name="onCancelPendingInputEvents()V" since="19" />
 		<method name="onCheckIsTextEditor()Z" since="3" />
 		<method name="onConfigurationChanged(Landroid/content/res/Configuration;)V" since="8" />
 		<method name="onCreateContextMenu(Landroid/view/ContextMenu;)V" />
@@ -26160,6 +27719,7 @@
 		<method name="scrollBy(II)V" />
 		<method name="scrollTo(II)V" />
 		<method name="setAccessibilityDelegate(Landroid/view/View$AccessibilityDelegate;)V" since="14" />
+		<method name="setAccessibilityLiveRegion(I)V" since="19" />
 		<method name="setActivated(Z)V" since="11" />
 		<method name="setAlpha(F)V" since="11" />
 		<method name="setAnimation(Landroid/view/animation/Animation;)V" />
@@ -26264,6 +27824,9 @@
 		<method name="verifyDrawable(Landroid/graphics/drawable/Drawable;)Z" />
 		<method name="willNotCacheDrawing()Z" />
 		<method name="willNotDraw()Z" />
+		<field name="ACCESSIBILITY_LIVE_REGION_ASSERTIVE" since="19" />
+		<field name="ACCESSIBILITY_LIVE_REGION_NONE" since="19" />
+		<field name="ACCESSIBILITY_LIVE_REGION_POLITE" since="19" />
 		<field name="ALPHA" since="14" />
 		<field name="DRAWING_CACHE_QUALITY_AUTO" />
 		<field name="DRAWING_CACHE_QUALITY_HIGH" />
@@ -26295,6 +27858,7 @@
 		<field name="HAPTIC_FEEDBACK_ENABLED" since="3" />
 		<field name="IMPORTANT_FOR_ACCESSIBILITY_AUTO" since="16" />
 		<field name="IMPORTANT_FOR_ACCESSIBILITY_NO" since="16" />
+		<field name="IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS" since="19" />
 		<field name="IMPORTANT_FOR_ACCESSIBILITY_YES" since="16" />
 		<field name="INVISIBLE" />
 		<field name="KEEP_SCREEN_ON" />
@@ -26327,6 +27891,7 @@
 		<field name="PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET" />
 		<field name="PRESSED_SELECTED_STATE_SET" />
 		<field name="PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET" />
+		<field name="PRESSED_STATE_SET" since="19" />
 		<field name="PRESSED_WINDOW_FOCUSED_STATE_SET" />
 		<field name="ROTATION" since="14" />
 		<field name="ROTATION_X" since="14" />
@@ -26349,6 +27914,8 @@
 		<field name="STATUS_BAR_VISIBLE" since="11" />
 		<field name="SYSTEM_UI_FLAG_FULLSCREEN" since="16" />
 		<field name="SYSTEM_UI_FLAG_HIDE_NAVIGATION" since="14" />
+		<field name="SYSTEM_UI_FLAG_IMMERSIVE" since="19" />
+		<field name="SYSTEM_UI_FLAG_IMMERSIVE_STICKY" since="19" />
 		<field name="SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN" since="16" />
 		<field name="SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION" since="16" />
 		<field name="SYSTEM_UI_FLAG_LAYOUT_STABLE" since="16" />
@@ -26735,17 +28302,28 @@
 	<class name="android/view/ViewParent" since="1">
 		<extends name="java/lang/Object" />
 		<method name="bringChildToFront(Landroid/view/View;)V" />
+		<method name="canResolveLayoutDirection()Z" since="19" />
+		<method name="canResolveTextAlignment()Z" since="19" />
+		<method name="canResolveTextDirection()Z" since="19" />
 		<method name="childDrawableStateChanged(Landroid/view/View;)V" />
+		<method name="childHasTransientStateChanged(Landroid/view/View;Z)V" since="19" />
 		<method name="clearChildFocus(Landroid/view/View;)V" />
 		<method name="createContextMenu(Landroid/view/ContextMenu;)V" />
 		<method name="focusSearch(Landroid/view/View;I)Landroid/view/View;" />
 		<method name="focusableViewAvailable(Landroid/view/View;)V" />
 		<method name="getChildVisibleRect(Landroid/view/View;Landroid/graphics/Rect;Landroid/graphics/Point;)Z" />
+		<method name="getLayoutDirection()I" since="19" />
 		<method name="getParent()Landroid/view/ViewParent;" />
 		<method name="getParentForAccessibility()Landroid/view/ViewParent;" since="16" />
+		<method name="getTextAlignment()I" since="19" />
+		<method name="getTextDirection()I" since="19" />
 		<method name="invalidateChild(Landroid/view/View;Landroid/graphics/Rect;)V" />
 		<method name="invalidateChildInParent([ILandroid/graphics/Rect;)Landroid/view/ViewParent;" />
+		<method name="isLayoutDirectionResolved()Z" since="19" />
 		<method name="isLayoutRequested()Z" />
+		<method name="isTextAlignmentResolved()Z" since="19" />
+		<method name="isTextDirectionResolved()Z" since="19" />
+		<method name="notifySubtreeAccessibilityStateChanged(Landroid/view/View;Landroid/view/View;I)V" since="19" />
 		<method name="recomputeViewAttributes(Landroid/view/View;)V" />
 		<method name="requestChildFocus(Landroid/view/View;Landroid/view/View;)V" />
 		<method name="requestChildRectangleOnScreen(Landroid/view/View;Landroid/graphics/Rect;Z)Z" since="3" />
@@ -26780,6 +28358,7 @@
 		<method name="setInterpolator(Landroid/animation/TimeInterpolator;)Landroid/view/ViewPropertyAnimator;" />
 		<method name="setListener(Landroid/animation/Animator$AnimatorListener;)Landroid/view/ViewPropertyAnimator;" />
 		<method name="setStartDelay(J)Landroid/view/ViewPropertyAnimator;" since="14" />
+		<method name="setUpdateListener(Landroid/animation/ValueAnimator$AnimatorUpdateListener;)Landroid/view/ViewPropertyAnimator;" since="19" />
 		<method name="start()V" since="14" />
 		<method name="translationX(F)Landroid/view/ViewPropertyAnimator;" />
 		<method name="translationXBy(F)Landroid/view/ViewPropertyAnimator;" />
@@ -26895,6 +28474,7 @@
 		<method name="hasChildren()Z" />
 		<method name="hasFeature(I)Z" since="11" />
 		<method name="hasSoftInputMode()Z" since="3" />
+		<method name="injectInputEvent(Landroid/view/InputEvent;)V" since="19" />
 		<method name="invalidatePanelMenu(I)V" since="11" />
 		<method name="isActive()Z" />
 		<method name="isFloating()Z" />
@@ -26930,7 +28510,10 @@
 		<method name="setFlags(II)V" />
 		<method name="setFormat(I)V" />
 		<method name="setGravity(I)V" />
+		<method name="setIcon(I)V" since="19" />
 		<method name="setLayout(II)V" />
+		<method name="setLocalFocus(ZZ)V" since="19" />
+		<method name="setLogo(I)V" since="19" />
 		<method name="setSoftInputMode(I)V" since="3" />
 		<method name="setTitle(Ljava/lang/CharSequence;)V" />
 		<method name="setTitleColor(I)V" />
@@ -27068,6 +28651,7 @@
 		<field name="FLAG_LAYOUT_IN_OVERSCAN" since="18" />
 		<field name="FLAG_LAYOUT_IN_SCREEN" />
 		<field name="FLAG_LAYOUT_NO_LIMITS" />
+		<field name="FLAG_LOCAL_FOCUS_MODE" since="19" />
 		<field name="FLAG_NOT_FOCUSABLE" />
 		<field name="FLAG_NOT_TOUCHABLE" />
 		<field name="FLAG_NOT_TOUCH_MODAL" />
@@ -27077,6 +28661,8 @@
 		<field name="FLAG_SHOW_WHEN_LOCKED" since="5" />
 		<field name="FLAG_SPLIT_TOUCH" since="11" />
 		<field name="FLAG_TOUCHABLE_WHEN_WAKING" />
+		<field name="FLAG_TRANSLUCENT_NAVIGATION" since="19" />
+		<field name="FLAG_TRANSLUCENT_STATUS" since="19" />
 		<field name="FLAG_TURN_SCREEN_ON" since="5" />
 		<field name="FLAG_WATCH_OUTSIDE_TOUCH" since="3" />
 		<field name="FORMAT_CHANGED" />
@@ -27124,6 +28710,7 @@
 		<field name="TYPE_KEYGUARD_DIALOG" />
 		<field name="TYPE_PHONE" />
 		<field name="TYPE_PRIORITY_PHONE" />
+		<field name="TYPE_PRIVATE_PRESENTATION" since="19" />
 		<field name="TYPE_SEARCH_BAR" />
 		<field name="TYPE_STATUS_BAR" />
 		<field name="TYPE_STATUS_BAR_PANEL" />
@@ -27167,6 +28754,7 @@
 		<method name="getAddedCount()I" />
 		<method name="getBeforeText()Ljava/lang/CharSequence;" />
 		<method name="getClassName()Ljava/lang/CharSequence;" />
+		<method name="getContentChangeTypes()I" since="19" />
 		<method name="getContentDescription()Ljava/lang/CharSequence;" />
 		<method name="getCurrentItemIndex()I" />
 		<method name="getEventTime()J" />
@@ -27194,6 +28782,7 @@
 		<method name="setBeforeText(Ljava/lang/CharSequence;)V" />
 		<method name="setChecked(Z)V" />
 		<method name="setClassName(Ljava/lang/CharSequence;)V" />
+		<method name="setContentChangeTypes(I)V" since="19" />
 		<method name="setContentDescription(Ljava/lang/CharSequence;)V" />
 		<method name="setCurrentItemIndex(I)V" />
 		<method name="setEnabled(Z)V" />
@@ -27207,6 +28796,10 @@
 		<method name="setParcelableData(Landroid/os/Parcelable;)V" />
 		<method name="setPassword(Z)V" />
 		<method name="setRemovedCount(I)V" />
+		<field name="CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION" since="19" />
+		<field name="CONTENT_CHANGE_TYPE_SUBTREE" since="19" />
+		<field name="CONTENT_CHANGE_TYPE_TEXT" since="19" />
+		<field name="CONTENT_CHANGE_TYPE_UNDEFINED" since="19" />
 		<field name="CREATOR" />
 		<field name="INVALID_POSITION" />
 		<field name="MAX_TEXT_LENGTH" />
@@ -27243,6 +28836,7 @@
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
 		<method name="addAccessibilityStateChangeListener(Landroid/view/accessibility/AccessibilityManager$AccessibilityStateChangeListener;)Z" since="14" />
+		<method name="addTouchExplorationStateChangeListener(Landroid/view/accessibility/AccessibilityManager$TouchExplorationStateChangeListener;)Z" since="19" />
 		<method name="getAccessibilityServiceList()Ljava/util/List;" />
 		<method name="getEnabledAccessibilityServiceList(I)Ljava/util/List;" since="14" />
 		<method name="getInstalledAccessibilityServiceList()Ljava/util/List;" since="14" />
@@ -27250,12 +28844,17 @@
 		<method name="isEnabled()Z" />
 		<method name="isTouchExplorationEnabled()Z" since="14" />
 		<method name="removeAccessibilityStateChangeListener(Landroid/view/accessibility/AccessibilityManager$AccessibilityStateChangeListener;)Z" since="14" />
+		<method name="removeTouchExplorationStateChangeListener(Landroid/view/accessibility/AccessibilityManager$TouchExplorationStateChangeListener;)Z" since="19" />
 		<method name="sendAccessibilityEvent(Landroid/view/accessibility/AccessibilityEvent;)V" />
 	</class>
 	<class name="android/view/accessibility/AccessibilityManager$AccessibilityStateChangeListener" since="14">
 		<extends name="java/lang/Object" />
 		<method name="onAccessibilityStateChanged(Z)V" />
 	</class>
+	<class name="android/view/accessibility/AccessibilityManager$TouchExplorationStateChangeListener" since="19">
+		<extends name="java/lang/Object" />
+		<method name="onTouchExplorationStateChanged(Z)V" />
+	</class>
 	<class name="android/view/accessibility/AccessibilityNodeInfo" since="14">
 		<extends name="java/lang/Object" />
 		<implements name="android/os/Parcelable" />
@@ -27263,6 +28862,7 @@
 		<method name="addAction(I)V" />
 		<method name="addChild(Landroid/view/View;)V" />
 		<method name="addChild(Landroid/view/View;I)V" since="16" />
+		<method name="canOpenPopup()Z" since="19" />
 		<method name="findAccessibilityNodeInfosByText(Ljava/lang/String;)Ljava/util/List;" />
 		<method name="findAccessibilityNodeInfosByViewId(Ljava/lang/String;)Ljava/util/List;" since="18" />
 		<method name="findFocus(I)Landroid/view/accessibility/AccessibilityNodeInfo;" since="16" />
@@ -27273,12 +28873,18 @@
 		<method name="getChild(I)Landroid/view/accessibility/AccessibilityNodeInfo;" />
 		<method name="getChildCount()I" />
 		<method name="getClassName()Ljava/lang/CharSequence;" />
+		<method name="getCollectionInfo()Landroid/view/accessibility/AccessibilityNodeInfo$CollectionInfo;" since="19" />
+		<method name="getCollectionItemInfo()Landroid/view/accessibility/AccessibilityNodeInfo$CollectionItemInfo;" since="19" />
 		<method name="getContentDescription()Ljava/lang/CharSequence;" />
+		<method name="getExtras()Landroid/os/Bundle;" since="19" />
+		<method name="getInputType()I" since="19" />
 		<method name="getLabelFor()Landroid/view/accessibility/AccessibilityNodeInfo;" since="17" />
 		<method name="getLabeledBy()Landroid/view/accessibility/AccessibilityNodeInfo;" since="17" />
+		<method name="getLiveRegion()I" since="19" />
 		<method name="getMovementGranularities()I" since="16" />
 		<method name="getPackageName()Ljava/lang/CharSequence;" />
 		<method name="getParent()Landroid/view/accessibility/AccessibilityNodeInfo;" />
+		<method name="getRangeInfo()Landroid/view/accessibility/AccessibilityNodeInfo$RangeInfo;" since="19" />
 		<method name="getText()Ljava/lang/CharSequence;" />
 		<method name="getTextSelectionEnd()I" since="18" />
 		<method name="getTextSelectionStart()I" since="18" />
@@ -27288,11 +28894,14 @@
 		<method name="isCheckable()Z" />
 		<method name="isChecked()Z" />
 		<method name="isClickable()Z" />
+		<method name="isContentInvalid()Z" since="19" />
+		<method name="isDismissable()Z" since="19" />
 		<method name="isEditable()Z" since="18" />
 		<method name="isEnabled()Z" />
 		<method name="isFocusable()Z" />
 		<method name="isFocused()Z" />
 		<method name="isLongClickable()Z" />
+		<method name="isMultiLine()Z" since="19" />
 		<method name="isPassword()Z" />
 		<method name="isScrollable()Z" />
 		<method name="isSelected()Z" />
@@ -27308,25 +28917,34 @@
 		<method name="setAccessibilityFocused(Z)V" since="16" />
 		<method name="setBoundsInParent(Landroid/graphics/Rect;)V" />
 		<method name="setBoundsInScreen(Landroid/graphics/Rect;)V" />
+		<method name="setCanOpenPopup(Z)V" since="19" />
 		<method name="setCheckable(Z)V" />
 		<method name="setChecked(Z)V" />
 		<method name="setClassName(Ljava/lang/CharSequence;)V" />
 		<method name="setClickable(Z)V" />
+		<method name="setCollectionInfo(Landroid/view/accessibility/AccessibilityNodeInfo$CollectionInfo;)V" since="19" />
+		<method name="setCollectionItemInfo(Landroid/view/accessibility/AccessibilityNodeInfo$CollectionItemInfo;)V" since="19" />
 		<method name="setContentDescription(Ljava/lang/CharSequence;)V" />
+		<method name="setContentInvalid(Z)V" since="19" />
+		<method name="setDismissable(Z)V" since="19" />
 		<method name="setEditable(Z)V" since="18" />
 		<method name="setEnabled(Z)V" />
 		<method name="setFocusable(Z)V" />
 		<method name="setFocused(Z)V" />
+		<method name="setInputType(I)V" since="19" />
 		<method name="setLabelFor(Landroid/view/View;)V" since="17" />
 		<method name="setLabelFor(Landroid/view/View;I)V" since="17" />
 		<method name="setLabeledBy(Landroid/view/View;)V" since="17" />
 		<method name="setLabeledBy(Landroid/view/View;I)V" since="17" />
+		<method name="setLiveRegion(I)V" since="19" />
 		<method name="setLongClickable(Z)V" />
 		<method name="setMovementGranularities(I)V" since="16" />
+		<method name="setMultiLine(Z)V" since="19" />
 		<method name="setPackageName(Ljava/lang/CharSequence;)V" />
 		<method name="setParent(Landroid/view/View;)V" />
 		<method name="setParent(Landroid/view/View;I)V" since="16" />
 		<method name="setPassword(Z)V" />
+		<method name="setRangeInfo(Landroid/view/accessibility/AccessibilityNodeInfo$RangeInfo;)V" since="19" />
 		<method name="setScrollable(Z)V" />
 		<method name="setSelected(Z)V" />
 		<method name="setSource(Landroid/view/View;)V" />
@@ -27345,8 +28963,11 @@
 		<field name="ACTION_CLEAR_FOCUS" />
 		<field name="ACTION_CLEAR_SELECTION" />
 		<field name="ACTION_CLICK" since="16" />
+		<field name="ACTION_COLLAPSE" since="19" />
 		<field name="ACTION_COPY" since="18" />
 		<field name="ACTION_CUT" since="18" />
+		<field name="ACTION_DISMISS" since="19" />
+		<field name="ACTION_EXPAND" since="19" />
 		<field name="ACTION_FOCUS" />
 		<field name="ACTION_LONG_CLICK" since="16" />
 		<field name="ACTION_NEXT_AT_MOVEMENT_GRANULARITY" since="16" />
@@ -27367,11 +28988,42 @@
 		<field name="MOVEMENT_GRANULARITY_PARAGRAPH" since="16" />
 		<field name="MOVEMENT_GRANULARITY_WORD" since="16" />
 	</class>
+	<class name="android/view/accessibility/AccessibilityNodeInfo$CollectionInfo" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getColumnCount()I" />
+		<method name="getRowCount()I" />
+		<method name="isHierarchical()Z" />
+		<method name="obtain(IIZ)Landroid/view/accessibility/AccessibilityNodeInfo$CollectionInfo;" />
+	</class>
+	<class name="android/view/accessibility/AccessibilityNodeInfo$CollectionItemInfo" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getColumnIndex()I" />
+		<method name="getColumnSpan()I" />
+		<method name="getRowIndex()I" />
+		<method name="getRowSpan()I" />
+		<method name="isHeading()Z" />
+		<method name="obtain(IIIIZ)Landroid/view/accessibility/AccessibilityNodeInfo$CollectionItemInfo;" />
+	</class>
+	<class name="android/view/accessibility/AccessibilityNodeInfo$RangeInfo" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getCurrent()F" />
+		<method name="getMax()F" />
+		<method name="getMin()F" />
+		<method name="getType()I" />
+		<method name="obtain(IFFF)Landroid/view/accessibility/AccessibilityNodeInfo$RangeInfo;" />
+		<field name="RANGE_TYPE_FLOAT" />
+		<field name="RANGE_TYPE_INT" />
+		<field name="RANGE_TYPE_PERCENT" />
+	</class>
 	<class name="android/view/accessibility/AccessibilityNodeProvider" since="16">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
 		<method name="createAccessibilityNodeInfo(I)Landroid/view/accessibility/AccessibilityNodeInfo;" />
 		<method name="findAccessibilityNodeInfosByText(Ljava/lang/String;I)Ljava/util/List;" />
+		<method name="findFocus(I)Landroid/view/accessibility/AccessibilityNodeInfo;" since="19" />
 		<method name="performAction(IILandroid/os/Bundle;)Z" />
 	</class>
 	<class name="android/view/accessibility/AccessibilityRecord" since="14">
@@ -27424,6 +29076,36 @@
 		<method name="setSource(Landroid/view/View;I)V" since="16" />
 		<method name="setToIndex(I)V" />
 	</class>
+	<class name="android/view/accessibility/CaptioningManager" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="addCaptioningChangeListener(Landroid/view/accessibility/CaptioningManager$CaptioningChangeListener;)V" />
+		<method name="getFontScale()F" />
+		<method name="getLocale()Ljava/util/Locale;" />
+		<method name="getUserStyle()Landroid/view/accessibility/CaptioningManager$CaptionStyle;" />
+		<method name="isEnabled()Z" />
+		<method name="removeCaptioningChangeListener(Landroid/view/accessibility/CaptioningManager$CaptioningChangeListener;)V" />
+	</class>
+	<class name="android/view/accessibility/CaptioningManager$CaptionStyle" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="getTypeface()Landroid/graphics/Typeface;" />
+		<field name="EDGE_TYPE_DROP_SHADOW" />
+		<field name="EDGE_TYPE_NONE" />
+		<field name="EDGE_TYPE_OUTLINE" />
+		<field name="backgroundColor" />
+		<field name="edgeColor" />
+		<field name="edgeType" />
+		<field name="foregroundColor" />
+	</class>
+	<class name="android/view/accessibility/CaptioningManager$CaptioningChangeListener" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="onEnabledChanged(Z)V" />
+		<method name="onFontScaleChanged(F)V" />
+		<method name="onLocaleChanged(Ljava/util/Locale;)V" />
+		<method name="onUserStyleChanged(Landroid/view/accessibility/CaptioningManager$CaptionStyle;)V" />
+	</class>
 	<class name="android/view/animation/AccelerateDecelerateInterpolator" since="1">
 		<extends name="java/lang/Object" />
 		<implements name="android/view/animation/Interpolator" />
@@ -27896,6 +29578,7 @@
 		<method name="setCurrentInputMethodSubtype(Landroid/view/inputmethod/InputMethodSubtype;)Z" since="11" />
 		<method name="setInputMethod(Landroid/os/IBinder;Ljava/lang/String;)V" />
 		<method name="setInputMethodAndSubtype(Landroid/os/IBinder;Ljava/lang/String;Landroid/view/inputmethod/InputMethodSubtype;)V" since="11" />
+		<method name="shouldOfferSwitchingToNextInputMethod(Landroid/os/IBinder;)Z" since="19" />
 		<method name="showInputMethodAndSubtypeEnabler(Ljava/lang/String;)V" since="11" />
 		<method name="showInputMethodPicker()V" />
 		<method name="showSoftInput(Landroid/view/View;I)Z" />
@@ -27951,10 +29634,25 @@
 		<method name="getLocale()Ljava/lang/String;" />
 		<method name="getMode()Ljava/lang/String;" />
 		<method name="getNameResId()I" />
+		<method name="isAsciiCapable()Z" since="19" />
 		<method name="isAuxiliary()Z" since="14" />
 		<method name="overridesImplicitlyEnabledSubtype()Z" since="14" />
 		<field name="CREATOR" />
 	</class>
+	<class name="android/view/inputmethod/InputMethodSubtype$InputMethodSubtypeBuilder" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="build()Landroid/view/inputmethod/InputMethodSubtype;" />
+		<method name="setIsAsciiCapable(Z)Landroid/view/inputmethod/InputMethodSubtype$InputMethodSubtypeBuilder;" />
+		<method name="setIsAuxiliary(Z)Landroid/view/inputmethod/InputMethodSubtype$InputMethodSubtypeBuilder;" />
+		<method name="setOverridesImplicitlyEnabledSubtype(Z)Landroid/view/inputmethod/InputMethodSubtype$InputMethodSubtypeBuilder;" />
+		<method name="setSubtypeExtraValue(Ljava/lang/String;)Landroid/view/inputmethod/InputMethodSubtype$InputMethodSubtypeBuilder;" />
+		<method name="setSubtypeIconResId(I)Landroid/view/inputmethod/InputMethodSubtype$InputMethodSubtypeBuilder;" />
+		<method name="setSubtypeId(I)Landroid/view/inputmethod/InputMethodSubtype$InputMethodSubtypeBuilder;" />
+		<method name="setSubtypeLocale(Ljava/lang/String;)Landroid/view/inputmethod/InputMethodSubtype$InputMethodSubtypeBuilder;" />
+		<method name="setSubtypeMode(Ljava/lang/String;)Landroid/view/inputmethod/InputMethodSubtype$InputMethodSubtypeBuilder;" />
+		<method name="setSubtypeNameResId(I)Landroid/view/inputmethod/InputMethodSubtype$InputMethodSubtypeBuilder;" />
+	</class>
 	<class name="android/view/textservice/SentenceSuggestionsInfo" since="16">
 		<extends name="java/lang/Object" />
 		<implements name="android/os/Parcelable" />
@@ -28497,6 +30195,7 @@
 		<field name="NARROW_COLUMNS" />
 		<field name="NORMAL" />
 		<field name="SINGLE_COLUMN" />
+		<field name="TEXT_AUTOSIZING" since="19" />
 	</class>
 	<class name="android/webkit/WebSettings$PluginState" since="8">
 		<extends name="java/lang/Enum" />
@@ -28589,12 +30288,14 @@
 		<method name="clearSslPreferences()V" />
 		<method name="clearView()V" />
 		<method name="copyBackForwardList()Landroid/webkit/WebBackForwardList;" />
+		<method name="createPrintDocumentAdapter()Landroid/print/PrintDocumentAdapter;" since="19" />
 		<method name="debugDump()V" />
 		<method name="destroy()V" />
 		<method name="disablePlatformNotifications()V" />
 		<method name="documentHasImages(Landroid/os/Message;)V" />
 		<method name="emulateShiftHeld()V" since="8" />
 		<method name="enablePlatformNotifications()V" />
+		<method name="evaluateJavascript(Ljava/lang/String;Landroid/webkit/ValueCallback;)V" since="19" />
 		<method name="findAddress(Ljava/lang/String;)Ljava/lang/String;" />
 		<method name="findAll(Ljava/lang/String;)I" since="3" />
 		<method name="findAllAsync(Ljava/lang/String;)V" since="16" />
@@ -28656,6 +30357,7 @@
 		<method name="setPictureListener(Landroid/webkit/WebView$PictureListener;)V" />
 		<method name="setVerticalScrollbarOverlay(Z)V" />
 		<method name="setWebChromeClient(Landroid/webkit/WebChromeClient;)V" />
+		<method name="setWebContentsDebuggingEnabled(Z)V" since="19" />
 		<method name="setWebViewClient(Landroid/webkit/WebViewClient;)V" />
 		<method name="showFindDialog(Ljava/lang/String;Z)Z" since="11" />
 		<method name="stopLoading()V" />
@@ -28756,6 +30458,7 @@
 		<method name="&lt;init>(Landroid/content/Context;)V" />
 		<method name="&lt;init>(Landroid/content/Context;Landroid/util/AttributeSet;)V" />
 		<method name="&lt;init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V" />
+		<method name="canScrollList(I)Z" since="19" />
 		<method name="clearChoices()V" since="11" />
 		<method name="clearTextFilter()V" />
 		<method name="deferNotifyDataSetChanged()V" since="14" />
@@ -28785,11 +30488,13 @@
 		<method name="isStackFromBottom()Z" />
 		<method name="isTextFilterEnabled()Z" />
 		<method name="layoutChildren()V" />
+		<method name="onInitializeAccessibilityNodeInfoForItem(Landroid/view/View;ILandroid/view/accessibility/AccessibilityNodeInfo;)V" since="19" />
 		<method name="onRemoteAdapterConnected()Z" since="11" />
 		<method name="onRemoteAdapterDisconnected()V" since="11" />
 		<method name="pointToPosition(II)I" />
 		<method name="pointToRowId(II)J" />
 		<method name="reclaimViews(Ljava/util/List;)V" />
+		<method name="scrollListBy(I)V" since="19" />
 		<method name="setAdapter(Landroid/widget/ListAdapter;)V" since="11" />
 		<method name="setCacheColorHint(I)V" />
 		<method name="setChoiceMode(I)V" since="11" />
@@ -29465,6 +31170,7 @@
 		<method name="&lt;init>(Landroid/content/Context;Landroid/util/AttributeSet;)V" />
 		<method name="&lt;init>(Landroid/view/ViewGroup$LayoutParams;)V" />
 		<method name="&lt;init>(Landroid/view/ViewGroup$MarginLayoutParams;)V" />
+		<method name="&lt;init>(Landroid/widget/FrameLayout$LayoutParams;)V" since="19" />
 		<field name="gravity" />
 	</class>
 	<class name="android/widget/Gallery" since="1">
@@ -29715,6 +31421,7 @@
 		<method name="&lt;init>(Landroid/content/Context;Landroid/util/AttributeSet;)V" />
 		<method name="&lt;init>(Landroid/view/ViewGroup$LayoutParams;)V" />
 		<method name="&lt;init>(Landroid/view/ViewGroup$MarginLayoutParams;)V" />
+		<method name="&lt;init>(Landroid/widget/LinearLayout$LayoutParams;)V" since="19" />
 		<method name="debug(Ljava/lang/String;)Ljava/lang/String;" />
 		<field name="gravity" />
 		<field name="weight" />
@@ -29732,6 +31439,7 @@
 		<method name="&lt;init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V" />
 		<method name="&lt;init>(Landroid/content/Context;Landroid/util/AttributeSet;II)V" />
 		<method name="clearListSelection()V" />
+		<method name="createDragToOpenListener(Landroid/view/View;)Landroid/view/View$OnTouchListener;" since="19" />
 		<method name="dismiss()V" />
 		<method name="getAnchorView()Landroid/view/View;" />
 		<method name="getAnimationStyle()I" />
@@ -29761,6 +31469,7 @@
 		<method name="setAnimationStyle(I)V" />
 		<method name="setBackgroundDrawable(Landroid/graphics/drawable/Drawable;)V" />
 		<method name="setContentWidth(I)V" />
+		<method name="setDropDownGravity(I)V" since="19" />
 		<method name="setHeight(I)V" />
 		<method name="setHorizontalOffset(I)V" />
 		<method name="setInputMethodMode(I)V" />
@@ -29793,6 +31502,8 @@
 		<method name="addFooterView(Landroid/view/View;Ljava/lang/Object;Z)V" />
 		<method name="addHeaderView(Landroid/view/View;)V" />
 		<method name="addHeaderView(Landroid/view/View;Ljava/lang/Object;Z)V" />
+		<method name="areFooterDividersEnabled()Z" since="19" />
+		<method name="areHeaderDividersEnabled()Z" since="19" />
 		<method name="clearChoices()V" />
 		<method name="findViewTraversal(I)Landroid/view/View;" />
 		<method name="findViewWithTagTraversal(Ljava/lang/Object;)Landroid/view/View;" />
@@ -29948,7 +31659,9 @@
 	<class name="android/widget/PopupMenu" since="11">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>(Landroid/content/Context;Landroid/view/View;)V" />
+		<method name="&lt;init>(Landroid/content/Context;Landroid/view/View;I)V" since="19" />
 		<method name="dismiss()V" />
+		<method name="getDragToOpenListener()Landroid/view/View$OnTouchListener;" since="19" />
 		<method name="getMenu()Landroid/view/Menu;" />
 		<method name="getMenuInflater()Landroid/view/MenuInflater;" />
 		<method name="inflate(I)V" since="14" />
@@ -30010,6 +31723,7 @@
 		<method name="setWindowLayoutMode(II)V" since="3" />
 		<method name="showAsDropDown(Landroid/view/View;)V" />
 		<method name="showAsDropDown(Landroid/view/View;II)V" />
+		<method name="showAsDropDown(Landroid/view/View;III)V" since="19" />
 		<method name="showAtLocation(Landroid/view/View;III)V" />
 		<method name="update()V" since="3" />
 		<method name="update(II)V" since="4" />
@@ -30153,6 +31867,7 @@
 		<method name="&lt;init>(Landroid/content/Context;Landroid/util/AttributeSet;)V" />
 		<method name="&lt;init>(Landroid/view/ViewGroup$LayoutParams;)V" />
 		<method name="&lt;init>(Landroid/view/ViewGroup$MarginLayoutParams;)V" />
+		<method name="&lt;init>(Landroid/widget/RelativeLayout$LayoutParams;)V" since="19" />
 		<method name="addRule(I)V" />
 		<method name="addRule(II)V" />
 		<method name="debug(Ljava/lang/String;)Ljava/lang/String;" />
@@ -30932,17 +32647,13 @@
 		<method name="getText1()Landroid/widget/TextView;" />
 		<method name="getText2()Landroid/widget/TextView;" />
 	</class>
-	<class name="android/widget/ValueEditor" since="18">
-		<extends name="java/lang/Object" />
-		<method name="getValueModel()Landroid/util/ValueModel;" />
-		<method name="setValueModel(Landroid/util/ValueModel;)V" />
-	</class>
 	<class name="android/widget/VideoView" since="1">
 		<extends name="android/view/SurfaceView" />
 		<implements name="android/widget/MediaController$MediaPlayerControl" />
 		<method name="&lt;init>(Landroid/content/Context;)V" />
 		<method name="&lt;init>(Landroid/content/Context;Landroid/util/AttributeSet;)V" />
 		<method name="&lt;init>(Landroid/content/Context;Landroid/util/AttributeSet;I)V" />
+		<method name="addSubtitleSource(Ljava/io/InputStream;Landroid/media/MediaFormat;)V" since="19" />
 		<method name="resolveAdjustedSize(II)I" />
 		<method name="resume()V" since="8" />
 		<method name="setMediaController(Landroid/widget/MediaController;)V" />
@@ -31916,6 +33627,7 @@
 	</class>
 	<class name="java/io/Closeable" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/lang/AutoCloseable" since="19" />
 		<method name="close()V" />
 	</class>
 	<class name="java/io/Console" since="9">
@@ -32208,6 +33920,7 @@
 	<class name="java/io/ObjectInput" since="1">
 		<extends name="java/lang/Object" />
 		<implements name="java/io/DataInput" />
+		<implements name="java/lang/AutoCloseable" since="19" />
 		<method name="available()I" />
 		<method name="close()V" />
 		<method name="read()I" />
@@ -32256,6 +33969,7 @@
 	<class name="java/io/ObjectOutput" since="1">
 		<extends name="java/lang/Object" />
 		<implements name="java/io/DataOutput" />
+		<implements name="java/lang/AutoCloseable" since="19" />
 		<method name="close()V" />
 		<method name="flush()V" />
 		<method name="writeObject(Ljava/lang/Object;)V" />
@@ -32708,8 +34422,13 @@
 		<method name="&lt;init>(I)V" />
 		<method name="&lt;init>(J)V" />
 		<method name="&lt;init>(Ljava/lang/Object;)V" />
+		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/Throwable;)V" since="19" />
 		<method name="&lt;init>(Z)V" />
 	</class>
+	<class name="java/lang/AutoCloseable" since="19">
+		<extends name="java/lang/Object" />
+		<method name="close()V" />
+	</class>
 	<class name="java/lang/Boolean" since="1">
 		<extends name="java/lang/Object" />
 		<implements name="java/io/Serializable" />
@@ -32717,6 +34436,7 @@
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 		<method name="&lt;init>(Z)V" />
 		<method name="booleanValue()Z" />
+		<method name="compare(ZZ)I" since="19" />
 		<method name="compareTo(Ljava/lang/Boolean;)I" />
 		<method name="getBoolean(Ljava/lang/String;)Z" />
 		<method name="parseBoolean(Ljava/lang/String;)Z" />
@@ -32732,6 +34452,7 @@
 		<implements name="java/lang/Comparable" />
 		<method name="&lt;init>(B)V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
+		<method name="compare(BB)I" since="19" />
 		<method name="compareTo(Ljava/lang/Byte;)I" />
 		<method name="decode(Ljava/lang/String;)Ljava/lang/Byte;" />
 		<method name="parseByte(Ljava/lang/String;)B" />
@@ -32766,16 +34487,21 @@
 		<method name="codePointBefore([CII)I" />
 		<method name="codePointCount(Ljava/lang/CharSequence;II)I" />
 		<method name="codePointCount([CII)I" />
+		<method name="compare(CC)I" since="19" />
 		<method name="compareTo(Ljava/lang/Character;)I" />
 		<method name="digit(CI)I" />
 		<method name="digit(II)I" />
 		<method name="forDigit(II)C" />
 		<method name="getDirectionality(C)B" />
 		<method name="getDirectionality(I)B" />
+		<method name="getName(I)Ljava/lang/String;" since="19" />
 		<method name="getNumericValue(C)I" />
 		<method name="getNumericValue(I)I" />
 		<method name="getType(C)I" />
 		<method name="getType(I)I" />
+		<method name="highSurrogate(I)C" since="19" />
+		<method name="isAlphabetic(I)Z" since="19" />
+		<method name="isBmpCodePoint(I)Z" since="19" />
 		<method name="isDefined(C)Z" />
 		<method name="isDefined(I)Z" />
 		<method name="isDigit(C)Z" />
@@ -32785,6 +34511,7 @@
 		<method name="isISOControl(I)Z" />
 		<method name="isIdentifierIgnorable(C)Z" />
 		<method name="isIdentifierIgnorable(I)Z" />
+		<method name="isIdeographic(I)Z" since="19" />
 		<method name="isJavaIdentifierPart(C)Z" />
 		<method name="isJavaIdentifierPart(I)Z" />
 		<method name="isJavaIdentifierStart(C)Z" />
@@ -32804,6 +34531,7 @@
 		<method name="isSpaceChar(C)Z" />
 		<method name="isSpaceChar(I)Z" />
 		<method name="isSupplementaryCodePoint(I)Z" />
+		<method name="isSurrogate(C)Z" since="19" />
 		<method name="isSurrogatePair(CC)Z" />
 		<method name="isTitleCase(C)Z" />
 		<method name="isTitleCase(I)Z" />
@@ -32816,6 +34544,7 @@
 		<method name="isValidCodePoint(I)Z" />
 		<method name="isWhitespace(C)Z" />
 		<method name="isWhitespace(I)Z" />
+		<method name="lowSurrogate(I)C" since="19" />
 		<method name="offsetByCodePoints(Ljava/lang/CharSequence;II)I" />
 		<method name="offsetByCodePoints([CIIII)I" />
 		<method name="reverseBytes(C)C" />
@@ -32907,48 +34636,84 @@
 		<method name="of(C)Ljava/lang/Character$UnicodeBlock;" />
 		<method name="of(I)Ljava/lang/Character$UnicodeBlock;" />
 		<field name="AEGEAN_NUMBERS" />
+		<field name="ALCHEMICAL_SYMBOLS" since="19" />
 		<field name="ALPHABETIC_PRESENTATION_FORMS" />
+		<field name="ANCIENT_GREEK_MUSICAL_NOTATION" since="19" />
+		<field name="ANCIENT_GREEK_NUMBERS" since="19" />
+		<field name="ANCIENT_SYMBOLS" since="19" />
 		<field name="ARABIC" />
 		<field name="ARABIC_PRESENTATION_FORMS_A" />
 		<field name="ARABIC_PRESENTATION_FORMS_B" />
+		<field name="ARABIC_SUPPLEMENT" since="19" />
 		<field name="ARMENIAN" />
 		<field name="ARROWS" />
+		<field name="AVESTAN" since="19" />
+		<field name="BALINESE" since="19" />
+		<field name="BAMUM" since="19" />
+		<field name="BAMUM_SUPPLEMENT" since="19" />
 		<field name="BASIC_LATIN" />
+		<field name="BATAK" since="19" />
 		<field name="BENGALI" />
 		<field name="BLOCK_ELEMENTS" />
 		<field name="BOPOMOFO" />
 		<field name="BOPOMOFO_EXTENDED" />
 		<field name="BOX_DRAWING" />
+		<field name="BRAHMI" since="19" />
 		<field name="BRAILLE_PATTERNS" />
+		<field name="BUGINESE" since="19" />
 		<field name="BUHID" />
 		<field name="BYZANTINE_MUSICAL_SYMBOLS" />
+		<field name="CARIAN" since="19" />
+		<field name="CHAM" since="19" />
 		<field name="CHEROKEE" />
 		<field name="CJK_COMPATIBILITY" />
 		<field name="CJK_COMPATIBILITY_FORMS" />
 		<field name="CJK_COMPATIBILITY_IDEOGRAPHS" />
 		<field name="CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT" />
 		<field name="CJK_RADICALS_SUPPLEMENT" />
+		<field name="CJK_STROKES" since="19" />
 		<field name="CJK_SYMBOLS_AND_PUNCTUATION" />
 		<field name="CJK_UNIFIED_IDEOGRAPHS" />
 		<field name="CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A" />
 		<field name="CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B" />
+		<field name="CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C" since="19" />
+		<field name="CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D" since="19" />
 		<field name="COMBINING_DIACRITICAL_MARKS" />
+		<field name="COMBINING_DIACRITICAL_MARKS_SUPPLEMENT" since="19" />
 		<field name="COMBINING_HALF_MARKS" />
 		<field name="COMBINING_MARKS_FOR_SYMBOLS" />
+		<field name="COMMON_INDIC_NUMBER_FORMS" since="19" />
 		<field name="CONTROL_PICTURES" />
+		<field name="COPTIC" since="19" />
+		<field name="COUNTING_ROD_NUMERALS" since="19" />
+		<field name="CUNEIFORM" since="19" />
+		<field name="CUNEIFORM_NUMBERS_AND_PUNCTUATION" since="19" />
 		<field name="CURRENCY_SYMBOLS" />
 		<field name="CYPRIOT_SYLLABARY" />
 		<field name="CYRILLIC" />
+		<field name="CYRILLIC_EXTENDED_A" since="19" />
+		<field name="CYRILLIC_EXTENDED_B" since="19" />
 		<field name="CYRILLIC_SUPPLEMENTARY" />
 		<field name="DESERET" />
 		<field name="DEVANAGARI" />
+		<field name="DEVANAGARI_EXTENDED" since="19" />
 		<field name="DINGBATS" />
+		<field name="DOMINO_TILES" since="19" />
+		<field name="EGYPTIAN_HIEROGLYPHS" since="19" />
+		<field name="EMOTICONS" since="19" />
 		<field name="ENCLOSED_ALPHANUMERICS" />
+		<field name="ENCLOSED_ALPHANUMERIC_SUPPLEMENT" since="19" />
 		<field name="ENCLOSED_CJK_LETTERS_AND_MONTHS" />
+		<field name="ENCLOSED_IDEOGRAPHIC_SUPPLEMENT" since="19" />
 		<field name="ETHIOPIC" />
+		<field name="ETHIOPIC_EXTENDED" since="19" />
+		<field name="ETHIOPIC_EXTENDED_A" since="19" />
+		<field name="ETHIOPIC_SUPPLEMENT" since="19" />
 		<field name="GENERAL_PUNCTUATION" />
 		<field name="GEOMETRIC_SHAPES" />
 		<field name="GEORGIAN" />
+		<field name="GEORGIAN_SUPPLEMENT" since="19" />
+		<field name="GLAGOLITIC" since="19" />
 		<field name="GOTHIC" />
 		<field name="GREEK" />
 		<field name="GREEK_EXTENDED" />
@@ -32957,6 +34722,8 @@
 		<field name="HALFWIDTH_AND_FULLWIDTH_FORMS" />
 		<field name="HANGUL_COMPATIBILITY_JAMO" />
 		<field name="HANGUL_JAMO" />
+		<field name="HANGUL_JAMO_EXTENDED_A" since="19" />
+		<field name="HANGUL_JAMO_EXTENDED_B" since="19" />
 		<field name="HANGUL_SYLLABLES" />
 		<field name="HANUNOO" />
 		<field name="HEBREW" />
@@ -32964,12 +34731,20 @@
 		<field name="HIGH_SURROGATES" />
 		<field name="HIRAGANA" />
 		<field name="IDEOGRAPHIC_DESCRIPTION_CHARACTERS" />
+		<field name="IMPERIAL_ARAMAIC" since="19" />
+		<field name="INSCRIPTIONAL_PAHLAVI" since="19" />
+		<field name="INSCRIPTIONAL_PARTHIAN" since="19" />
 		<field name="IPA_EXTENSIONS" />
+		<field name="JAVANESE" since="19" />
+		<field name="KAITHI" since="19" />
+		<field name="KANA_SUPPLEMENT" since="19" />
 		<field name="KANBUN" />
 		<field name="KANGXI_RADICALS" />
 		<field name="KANNADA" />
 		<field name="KATAKANA" />
 		<field name="KATAKANA_PHONETIC_EXTENSIONS" />
+		<field name="KAYAH_LI" since="19" />
+		<field name="KHAROSHTHI" since="19" />
 		<field name="KHMER" />
 		<field name="KHMER_SYMBOLS" />
 		<field name="LAO" />
@@ -32977,58 +34752,96 @@
 		<field name="LATIN_EXTENDED_A" />
 		<field name="LATIN_EXTENDED_ADDITIONAL" />
 		<field name="LATIN_EXTENDED_B" />
+		<field name="LATIN_EXTENDED_C" since="19" />
+		<field name="LATIN_EXTENDED_D" since="19" />
+		<field name="LEPCHA" since="19" />
 		<field name="LETTERLIKE_SYMBOLS" />
 		<field name="LIMBU" />
 		<field name="LINEAR_B_IDEOGRAMS" />
 		<field name="LINEAR_B_SYLLABARY" />
+		<field name="LISU" since="19" />
 		<field name="LOW_SURROGATES" />
+		<field name="LYCIAN" since="19" />
+		<field name="LYDIAN" since="19" />
+		<field name="MAHJONG_TILES" since="19" />
 		<field name="MALAYALAM" />
+		<field name="MANDAIC" since="19" />
 		<field name="MATHEMATICAL_ALPHANUMERIC_SYMBOLS" />
 		<field name="MATHEMATICAL_OPERATORS" />
+		<field name="MEETEI_MAYEK" since="19" />
 		<field name="MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A" />
 		<field name="MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B" />
 		<field name="MISCELLANEOUS_SYMBOLS" />
 		<field name="MISCELLANEOUS_SYMBOLS_AND_ARROWS" />
+		<field name="MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS" since="19" />
 		<field name="MISCELLANEOUS_TECHNICAL" />
+		<field name="MODIFIER_TONE_LETTERS" since="19" />
 		<field name="MONGOLIAN" />
 		<field name="MUSICAL_SYMBOLS" />
 		<field name="MYANMAR" />
+		<field name="MYANMAR_EXTENDED_A" since="19" />
+		<field name="NEW_TAI_LUE" since="19" />
+		<field name="NKO" since="19" />
 		<field name="NUMBER_FORMS" />
 		<field name="OGHAM" />
 		<field name="OLD_ITALIC" />
+		<field name="OLD_PERSIAN" since="19" />
+		<field name="OLD_SOUTH_ARABIAN" since="19" />
+		<field name="OLD_TURKIC" since="19" />
+		<field name="OL_CHIKI" since="19" />
 		<field name="OPTICAL_CHARACTER_RECOGNITION" />
 		<field name="ORIYA" />
 		<field name="OSMANYA" />
+		<field name="PHAGS_PA" since="19" />
+		<field name="PHAISTOS_DISC" since="19" />
+		<field name="PHOENICIAN" since="19" />
 		<field name="PHONETIC_EXTENSIONS" />
+		<field name="PHONETIC_EXTENSIONS_SUPPLEMENT" since="19" />
+		<field name="PLAYING_CARDS" since="19" />
 		<field name="PRIVATE_USE_AREA" />
+		<field name="REJANG" since="19" />
+		<field name="RUMI_NUMERAL_SYMBOLS" since="19" />
 		<field name="RUNIC" />
+		<field name="SAMARITAN" since="19" />
+		<field name="SAURASHTRA" since="19" />
 		<field name="SHAVIAN" />
 		<field name="SINHALA" />
 		<field name="SMALL_FORM_VARIANTS" />
 		<field name="SPACING_MODIFIER_LETTERS" />
 		<field name="SPECIALS" />
+		<field name="SUNDANESE" since="19" />
 		<field name="SUPERSCRIPTS_AND_SUBSCRIPTS" />
 		<field name="SUPPLEMENTAL_ARROWS_A" />
 		<field name="SUPPLEMENTAL_ARROWS_B" />
 		<field name="SUPPLEMENTAL_MATHEMATICAL_OPERATORS" />
+		<field name="SUPPLEMENTAL_PUNCTUATION" since="19" />
 		<field name="SUPPLEMENTARY_PRIVATE_USE_AREA_A" />
 		<field name="SUPPLEMENTARY_PRIVATE_USE_AREA_B" />
 		<field name="SURROGATES_AREA" />
+		<field name="SYLOTI_NAGRI" since="19" />
 		<field name="SYRIAC" />
 		<field name="TAGALOG" />
 		<field name="TAGBANWA" />
 		<field name="TAGS" />
 		<field name="TAI_LE" />
+		<field name="TAI_THAM" since="19" />
+		<field name="TAI_VIET" since="19" />
 		<field name="TAI_XUAN_JING_SYMBOLS" />
 		<field name="TAMIL" />
 		<field name="TELUGU" />
 		<field name="THAANA" />
 		<field name="THAI" />
 		<field name="TIBETAN" />
+		<field name="TIFINAGH" since="19" />
+		<field name="TRANSPORT_AND_MAP_SYMBOLS" since="19" />
 		<field name="UGARITIC" />
 		<field name="UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS" />
+		<field name="UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED" since="19" />
+		<field name="VAI" since="19" />
 		<field name="VARIATION_SELECTORS" />
 		<field name="VARIATION_SELECTORS_SUPPLEMENT" />
+		<field name="VEDIC_EXTENSIONS" since="19" />
+		<field name="VERTICAL_FORMS" since="19" />
 		<field name="YIJING_HEXAGRAM_SYMBOLS" />
 		<field name="YI_RADICALS" />
 		<field name="YI_SYLLABLES" />
@@ -33143,6 +34956,7 @@
 	</class>
 	<class name="java/lang/ClassNotFoundException" since="1">
 		<extends name="java/lang/Exception" />
+		<extends name="java/lang/ReflectiveOperationException" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/Throwable;)V" />
@@ -33279,6 +35093,7 @@
 	</class>
 	<class name="java/lang/IllegalAccessException" since="1">
 		<extends name="java/lang/Exception" />
+		<extends name="java/lang/ReflectiveOperationException" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 	</class>
@@ -33328,6 +35143,7 @@
 	</class>
 	<class name="java/lang/InstantiationException" since="1">
 		<extends name="java/lang/Exception" />
+		<extends name="java/lang/ReflectiveOperationException" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 	</class>
@@ -33337,6 +35153,7 @@
 		<method name="&lt;init>(I)V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 		<method name="bitCount(I)I" />
+		<method name="compare(II)I" since="19" />
 		<method name="compareTo(Ljava/lang/Integer;)I" />
 		<method name="decode(Ljava/lang/String;)Ljava/lang/Integer;" />
 		<method name="getInteger(Ljava/lang/String;)Ljava/lang/Integer;" />
@@ -33384,6 +35201,7 @@
 		<extends name="java/lang/Error" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
+		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/Throwable;)V" since="19" />
 	</class>
 	<class name="java/lang/Long" since="1">
 		<extends name="java/lang/Number" />
@@ -33391,6 +35209,7 @@
 		<method name="&lt;init>(J)V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 		<method name="bitCount(J)I" />
+		<method name="compare(JJ)I" since="19" />
 		<method name="compareTo(Ljava/lang/Long;)I" />
 		<method name="decode(Ljava/lang/String;)Ljava/lang/Long;" />
 		<method name="getLong(Ljava/lang/String;)Ljava/lang/Long;" />
@@ -33497,6 +35316,7 @@
 	</class>
 	<class name="java/lang/NoSuchFieldException" since="1">
 		<extends name="java/lang/Exception" />
+		<extends name="java/lang/ReflectiveOperationException" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 	</class>
@@ -33507,6 +35327,7 @@
 	</class>
 	<class name="java/lang/NoSuchMethodException" since="1">
 		<extends name="java/lang/Exception" />
+		<extends name="java/lang/ReflectiveOperationException" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 	</class>
@@ -33599,6 +35420,13 @@
 		<extends name="java/lang/Object" />
 		<method name="read(Ljava/nio/CharBuffer;)I" />
 	</class>
+	<class name="java/lang/ReflectiveOperationException" since="19">
+		<extends name="java/lang/Exception" />
+		<method name="&lt;init>()V" />
+		<method name="&lt;init>(Ljava/lang/String;)V" />
+		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/Throwable;)V" />
+		<method name="&lt;init>(Ljava/lang/Throwable;)V" />
+	</class>
 	<class name="java/lang/Runnable" since="1">
 		<extends name="java/lang/Object" />
 		<method name="run()V" />
@@ -33643,6 +35471,10 @@
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/String;)V" />
 	</class>
+	<class name="java/lang/SafeVarargs" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="java/lang/annotation/Annotation" />
+	</class>
 	<class name="java/lang/SecurityException" since="1">
 		<extends name="java/lang/RuntimeException" />
 		<method name="&lt;init>()V" />
@@ -33701,6 +35533,7 @@
 		<implements name="java/lang/Comparable" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 		<method name="&lt;init>(S)V" />
+		<method name="compare(SS)I" since="19" />
 		<method name="compareTo(Ljava/lang/Short;)I" />
 		<method name="decode(Ljava/lang/String;)Ljava/lang/Short;" />
 		<method name="parseShort(Ljava/lang/String;)S" />
@@ -33979,6 +35812,7 @@
 		<method name="getenv(Ljava/lang/String;)Ljava/lang/String;" />
 		<method name="identityHashCode(Ljava/lang/Object;)I" />
 		<method name="inheritedChannel()Ljava/nio/channels/Channel;" />
+		<method name="lineSeparator()Ljava/lang/String;" since="19" />
 		<method name="load(Ljava/lang/String;)V" />
 		<method name="loadLibrary(Ljava/lang/String;)V" />
 		<method name="mapLibraryName(Ljava/lang/String;)Ljava/lang/String;" />
@@ -34111,12 +35945,15 @@
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/Throwable;)V" />
+		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/Throwable;ZZ)V" since="19" />
 		<method name="&lt;init>(Ljava/lang/Throwable;)V" />
+		<method name="addSuppressed(Ljava/lang/Throwable;)V" since="19" />
 		<method name="fillInStackTrace()Ljava/lang/Throwable;" />
 		<method name="getCause()Ljava/lang/Throwable;" />
 		<method name="getLocalizedMessage()Ljava/lang/String;" />
 		<method name="getMessage()Ljava/lang/String;" />
 		<method name="getStackTrace()[Ljava/lang/StackTraceElement;" />
+		<method name="getSuppressed()[Ljava/lang/Throwable;" since="19" />
 		<method name="initCause(Ljava/lang/Throwable;)Ljava/lang/Throwable;" />
 		<method name="printStackTrace()V" />
 		<method name="printStackTrace(Ljava/io/PrintStream;)V" />
@@ -34355,6 +36192,7 @@
 	</class>
 	<class name="java/lang/reflect/InvocationTargetException" since="1">
 		<extends name="java/lang/Exception" />
+		<extends name="java/lang/ReflectiveOperationException" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/Throwable;)V" />
 		<method name="&lt;init>(Ljava/lang/Throwable;Ljava/lang/String;)V" />
@@ -34394,6 +36232,10 @@
 	<class name="java/lang/reflect/Modifier" since="1">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
+		<method name="classModifiers()I" since="19" />
+		<method name="constructorModifiers()I" since="19" />
+		<method name="fieldModifiers()I" since="19" />
+		<method name="interfaceModifiers()I" since="19" />
 		<method name="isAbstract(I)Z" />
 		<method name="isFinal(I)Z" />
 		<method name="isInterface(I)Z" />
@@ -34406,6 +36248,7 @@
 		<method name="isSynchronized(I)Z" />
 		<method name="isTransient(I)Z" />
 		<method name="isVolatile(I)Z" />
+		<method name="methodModifiers()I" since="19" />
 		<method name="toString(I)Ljava/lang/String;" />
 		<field name="ABSTRACT" />
 		<field name="FINAL" />
@@ -34737,6 +36580,7 @@
 	</class>
 	<class name="java/net/DatagramSocket" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/io/Closeable" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(I)V" />
 		<method name="&lt;init>(ILjava/net/InetAddress;)V" />
@@ -34856,6 +36700,7 @@
 		<method name="getResponseMessage()Ljava/lang/String;" />
 		<method name="setChunkedStreamingMode(I)V" />
 		<method name="setFixedLengthStreamingMode(I)V" />
+		<method name="setFixedLengthStreamingMode(J)V" since="19" />
 		<method name="setFollowRedirects(Z)V" />
 		<method name="setInstanceFollowRedirects(Z)V" />
 		<method name="setRequestMethod(Ljava/lang/String;)V" />
@@ -34898,6 +36743,7 @@
 		<field name="HTTP_VERSION" />
 		<field name="chunkLength" />
 		<field name="fixedContentLength" />
+		<field name="fixedContentLengthLong" since="19" />
 		<field name="instanceFollowRedirects" />
 		<field name="method" />
 		<field name="responseCode" />
@@ -34939,6 +36785,7 @@
 		<method name="getHostAddress()Ljava/lang/String;" />
 		<method name="getHostName()Ljava/lang/String;" />
 		<method name="getLocalHost()Ljava/net/InetAddress;" />
+		<method name="getLoopbackAddress()Ljava/net/InetAddress;" since="19" />
 		<method name="isAnyLocalAddress()Z" />
 		<method name="isLinkLocalAddress()Z" />
 		<method name="isLoopbackAddress()Z" />
@@ -34960,6 +36807,7 @@
 		<method name="createUnresolved(Ljava/lang/String;I)Ljava/net/InetSocketAddress;" />
 		<method name="getAddress()Ljava/net/InetAddress;" />
 		<method name="getHostName()Ljava/lang/String;" />
+		<method name="getHostString()Ljava/lang/String;" since="19" />
 		<method name="getPort()I" />
 		<method name="isUnresolved()Z" />
 	</class>
@@ -35017,10 +36865,12 @@
 	<class name="java/net/NetworkInterface" since="1">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
+		<method name="getByIndex(I)Ljava/net/NetworkInterface;" since="19" />
 		<method name="getByInetAddress(Ljava/net/InetAddress;)Ljava/net/NetworkInterface;" />
 		<method name="getByName(Ljava/lang/String;)Ljava/net/NetworkInterface;" />
 		<method name="getDisplayName()Ljava/lang/String;" />
 		<method name="getHardwareAddress()[B" since="9" />
+		<method name="getIndex()I" since="19" />
 		<method name="getInetAddresses()Ljava/util/Enumeration;" />
 		<method name="getInterfaceAddresses()Ljava/util/List;" since="9" />
 		<method name="getMTU()I" since="9" />
@@ -35097,6 +36947,7 @@
 	</class>
 	<class name="java/net/ServerSocket" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/io/Closeable" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(I)V" />
 		<method name="&lt;init>(II)V" />
@@ -35124,6 +36975,7 @@
 	</class>
 	<class name="java/net/Socket" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/io/Closeable" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;I)V" />
 		<method name="&lt;init>(Ljava/lang/String;ILjava/net/InetAddress;I)V" />
@@ -35561,6 +37413,7 @@
 		<method name="put([C)Ljava/nio/CharBuffer;" />
 		<method name="put([CII)Ljava/nio/CharBuffer;" />
 		<method name="slice()Ljava/nio/CharBuffer;" />
+		<method name="subSequence(II)Ljava/nio/CharBuffer;" since="19" />
 		<method name="wrap(Ljava/lang/CharSequence;)Ljava/nio/CharBuffer;" />
 		<method name="wrap(Ljava/lang/CharSequence;II)Ljava/nio/CharBuffer;" />
 		<method name="wrap([C)Ljava/nio/CharBuffer;" />
@@ -35810,6 +37663,7 @@
 	</class>
 	<class name="java/nio/channels/FileLock" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/lang/AutoCloseable" since="19" />
 		<method name="&lt;init>(Ljava/nio/channels/FileChannel;JJZ)V" />
 		<method name="channel()Ljava/nio/channels/FileChannel;" />
 		<method name="isShared()Z" />
@@ -35932,6 +37786,7 @@
 	</class>
 	<class name="java/nio/channels/Selector" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/io/Closeable" since="19" />
 		<method name="&lt;init>()V" />
 		<method name="close()V" />
 		<method name="isOpen()Z" />
@@ -36133,6 +37988,16 @@
 		<method name="&lt;init>(I)V" />
 		<method name="getInputLength()I" />
 	</class>
+	<class name="java/nio/charset/StandardCharsets" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<field name="ISO_8859_1" />
+		<field name="US_ASCII" />
+		<field name="UTF_16" />
+		<field name="UTF_16BE" />
+		<field name="UTF_16LE" />
+		<field name="UTF_8" />
+	</class>
 	<class name="java/nio/charset/UnmappableCharacterException" since="1">
 		<extends name="java/nio/charset/CharacterCodingException" />
 		<method name="&lt;init>(I)V" />
@@ -37843,6 +39708,7 @@
 	</class>
 	<class name="java/sql/Connection" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/lang/AutoCloseable" since="19" />
 		<implements name="java/sql/Wrapper" since="9" />
 		<method name="clearWarnings()V" />
 		<method name="close()V" />
@@ -38279,6 +40145,7 @@
 	</class>
 	<class name="java/sql/ResultSet" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/lang/AutoCloseable" since="19" />
 		<implements name="java/sql/Wrapper" since="9" />
 		<method name="absolute(I)Z" />
 		<method name="afterLast()V" />
@@ -38788,6 +40655,7 @@
 	</class>
 	<class name="java/sql/Statement" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/lang/AutoCloseable" since="19" />
 		<implements name="java/sql/Wrapper" since="9" />
 		<method name="addBatch(Ljava/lang/String;)V" />
 		<method name="cancel()V" />
@@ -39608,11 +41476,19 @@
 		<method name="nextClearBit(I)I" />
 		<method name="nextSetBit(I)I" />
 		<method name="or(Ljava/util/BitSet;)V" />
+		<method name="previousClearBit(I)I" since="19" />
+		<method name="previousSetBit(I)I" since="19" />
 		<method name="set(I)V" />
 		<method name="set(II)V" />
 		<method name="set(IIZ)V" />
 		<method name="set(IZ)V" />
 		<method name="size()I" />
+		<method name="toByteArray()[B" since="19" />
+		<method name="toLongArray()[J" since="19" />
+		<method name="valueOf(Ljava/nio/ByteBuffer;)Ljava/util/BitSet;" since="19" />
+		<method name="valueOf(Ljava/nio/LongBuffer;)Ljava/util/BitSet;" since="19" />
+		<method name="valueOf([B)Ljava/util/BitSet;" since="19" />
+		<method name="valueOf([J)Ljava/util/BitSet;" since="19" />
 		<method name="xor(Ljava/util/BitSet;)V" />
 	</class>
 	<class name="java/util/Calendar" since="1">
@@ -39746,7 +41622,10 @@
 		<method name="checkedSortedSet(Ljava/util/SortedSet;Ljava/lang/Class;)Ljava/util/SortedSet;" />
 		<method name="copy(Ljava/util/List;Ljava/util/List;)V" />
 		<method name="disjoint(Ljava/util/Collection;Ljava/util/Collection;)Z" />
+		<method name="emptyEnumeration()Ljava/util/Enumeration;" since="19" />
+		<method name="emptyIterator()Ljava/util/Iterator;" since="19" />
 		<method name="emptyList()Ljava/util/List;" />
+		<method name="emptyListIterator()Ljava/util/ListIterator;" since="19" />
 		<method name="emptyMap()Ljava/util/Map;" />
 		<method name="emptySet()Ljava/util/Set;" />
 		<method name="enumeration(Ljava/util/Collection;)Ljava/util/Enumeration;" />
@@ -39798,13 +41677,18 @@
 		<extends name="java/lang/RuntimeException" />
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
+		<method name="&lt;init>(Ljava/lang/String;Ljava/lang/Throwable;)V" since="19" />
+		<method name="&lt;init>(Ljava/lang/Throwable;)V" since="19" />
 	</class>
 	<class name="java/util/Currency" since="1">
 		<extends name="java/lang/Object" />
 		<implements name="java/io/Serializable" />
 		<method name="&lt;init>()V" />
+		<method name="getAvailableCurrencies()Ljava/util/Set;" since="19" />
 		<method name="getCurrencyCode()Ljava/lang/String;" />
 		<method name="getDefaultFractionDigits()I" />
+		<method name="getDisplayName()Ljava/lang/String;" since="19" />
+		<method name="getDisplayName(Ljava/util/Locale;)Ljava/lang/String;" since="19" />
 		<method name="getInstance(Ljava/lang/String;)Ljava/util/Currency;" />
 		<method name="getInstance(Ljava/util/Locale;)Ljava/util/Currency;" />
 		<method name="getSymbol()Ljava/lang/String;" />
@@ -40289,6 +42173,19 @@
 		<method name="&lt;init>()V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 	</class>
+	<class name="java/util/Objects" since="19">
+		<extends name="java/lang/Object" />
+		<method name="&lt;init>()V" />
+		<method name="compare(Ljava/lang/Object;Ljava/lang/Object;Ljava/util/Comparator;)I" />
+		<method name="deepEquals(Ljava/lang/Object;Ljava/lang/Object;)Z" />
+		<method name="equals(Ljava/lang/Object;Ljava/lang/Object;)Z" />
+		<method name="hash([Ljava/lang/Object;)I" />
+		<method name="hashCode(Ljava/lang/Object;)I" />
+		<method name="requireNonNull(Ljava/lang/Object;)Ljava/lang/Object;" />
+		<method name="requireNonNull(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;" />
+		<method name="toString(Ljava/lang/Object;)Ljava/lang/String;" />
+		<method name="toString(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;" />
+	</class>
 	<class name="java/util/Observable" since="1">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
@@ -40419,6 +42316,7 @@
 	</class>
 	<class name="java/util/Scanner" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/io/Closeable" since="19" />
 		<implements name="java/util/Iterator" />
 		<method name="&lt;init>(Ljava/io/File;)V" />
 		<method name="&lt;init>(Ljava/io/File;Ljava/lang/String;)V" />
@@ -41786,6 +43684,7 @@
 		<method name="getAnonymousLogger()Ljava/util/logging/Logger;" />
 		<method name="getAnonymousLogger(Ljava/lang/String;)Ljava/util/logging/Logger;" />
 		<method name="getFilter()Ljava/util/logging/Filter;" />
+		<method name="getGlobal()Ljava/util/logging/Logger;" since="19" />
 		<method name="getHandlers()[Ljava/util/logging/Handler;" />
 		<method name="getLevel()Ljava/util/logging/Level;" />
 		<method name="getLogger(Ljava/lang/String;)Ljava/util/logging/Logger;" />
@@ -42074,6 +43973,7 @@
 		<method name="&lt;init>(IZ)V" />
 		<method name="deflate([B)I" />
 		<method name="deflate([BII)I" />
+		<method name="deflate([BIII)I" since="19" />
 		<method name="end()V" />
 		<method name="finish()V" />
 		<method name="finished()Z" />
@@ -42096,8 +43996,11 @@
 		<field name="DEFAULT_STRATEGY" />
 		<field name="DEFLATED" />
 		<field name="FILTERED" />
+		<field name="FULL_FLUSH" since="19" />
 		<field name="HUFFMAN_ONLY" />
 		<field name="NO_COMPRESSION" />
+		<field name="NO_FLUSH" since="19" />
+		<field name="SYNC_FLUSH" since="19" />
 	</class>
 	<class name="java/util/zip/DeflaterInputStream" since="9">
 		<extends name="java/io/FilterInputStream" />
@@ -42112,6 +44015,9 @@
 		<method name="&lt;init>(Ljava/io/OutputStream;)V" />
 		<method name="&lt;init>(Ljava/io/OutputStream;Ljava/util/zip/Deflater;)V" />
 		<method name="&lt;init>(Ljava/io/OutputStream;Ljava/util/zip/Deflater;I)V" />
+		<method name="&lt;init>(Ljava/io/OutputStream;Ljava/util/zip/Deflater;IZ)V" since="19" />
+		<method name="&lt;init>(Ljava/io/OutputStream;Ljava/util/zip/Deflater;Z)V" since="19" />
+		<method name="&lt;init>(Ljava/io/OutputStream;Z)V" since="19" />
 		<method name="deflate()V" />
 		<method name="finish()V" />
 		<field name="buf" />
@@ -42129,6 +44035,8 @@
 		<extends name="java/util/zip/DeflaterOutputStream" />
 		<method name="&lt;init>(Ljava/io/OutputStream;)V" />
 		<method name="&lt;init>(Ljava/io/OutputStream;I)V" />
+		<method name="&lt;init>(Ljava/io/OutputStream;IZ)V" since="19" />
+		<method name="&lt;init>(Ljava/io/OutputStream;Z)V" since="19" />
 		<field name="crc" />
 	</class>
 	<class name="java/util/zip/Inflater" since="1">
@@ -42207,11 +44115,13 @@
 	</class>
 	<class name="java/util/zip/ZipFile" since="1">
 		<extends name="java/lang/Object" />
+		<implements name="java/io/Closeable" since="19" />
 		<method name="&lt;init>(Ljava/io/File;)V" />
 		<method name="&lt;init>(Ljava/io/File;I)V" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 		<method name="close()V" />
 		<method name="entries()Ljava/util/Enumeration;" />
+		<method name="getComment()Ljava/lang/String;" since="19" />
 		<method name="getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;" />
 		<method name="getInputStream(Ljava/util/zip/ZipEntry;)Ljava/io/InputStream;" />
 		<method name="getName()Ljava/lang/String;" />
@@ -42237,6 +44147,11 @@
 		<field name="DEFLATED" />
 		<field name="STORED" />
 	</class>
+	<class name="javax/crypto/AEADBadTagException" since="19">
+		<extends name="javax/crypto/BadPaddingException" />
+		<method name="&lt;init>()V" />
+		<method name="&lt;init>(Ljava/lang/String;)V" />
+	</class>
 	<class name="javax/crypto/BadPaddingException" since="1">
 		<extends name="java/security/GeneralSecurityException" />
 		<method name="&lt;init>()V" />
@@ -42278,6 +44193,9 @@
 		<method name="update([BII)[B" />
 		<method name="update([BII[B)I" />
 		<method name="update([BII[BI)I" />
+		<method name="updateAAD(Ljava/nio/ByteBuffer;)V" since="19" />
+		<method name="updateAAD([B)V" since="19" />
+		<method name="updateAAD([BII)V" since="19" />
 		<method name="wrap(Ljava/security/Key;)[B" />
 		<field name="DECRYPT_MODE" />
 		<field name="ENCRYPT_MODE" />
@@ -42317,6 +44235,8 @@
 		<method name="engineUpdate(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I" />
 		<method name="engineUpdate([BII)[B" />
 		<method name="engineUpdate([BII[BI)I" />
+		<method name="engineUpdateAAD(Ljava/nio/ByteBuffer;)V" since="19" />
+		<method name="engineUpdateAAD([BII)V" since="19" />
 		<method name="engineWrap(Ljava/security/Key;)[B" />
 	</class>
 	<class name="javax/crypto/EncryptedPrivateKeyInfo" since="1">
@@ -42578,6 +44498,14 @@
 		<method name="getP()Ljava/math/BigInteger;" />
 		<method name="getY()Ljava/math/BigInteger;" />
 	</class>
+	<class name="javax/crypto/spec/GCMParameterSpec" since="19">
+		<extends name="java/lang/Object" />
+		<implements name="java/security/spec/AlgorithmParameterSpec" />
+		<method name="&lt;init>(I[B)V" />
+		<method name="&lt;init>(I[BII)V" />
+		<method name="getIV()[B" />
+		<method name="getTLen()I" />
+	</class>
 	<class name="javax/crypto/spec/IvParameterSpec" since="1">
 		<extends name="java/lang/Object" />
 		<implements name="java/security/spec/AlgorithmParameterSpec" />
@@ -48048,6 +49976,7 @@
 	<class name="org/json/JSONArray" since="1">
 		<extends name="java/lang/Object" />
 		<method name="&lt;init>()V" />
+		<method name="&lt;init>(Ljava/lang/Object;)V" since="19" />
 		<method name="&lt;init>(Ljava/lang/String;)V" />
 		<method name="&lt;init>(Ljava/util/Collection;)V" />
 		<method name="&lt;init>(Lorg/json/JSONTokener;)V" />
@@ -48085,6 +50014,7 @@
 		<method name="put(J)Lorg/json/JSONArray;" />
 		<method name="put(Ljava/lang/Object;)Lorg/json/JSONArray;" />
 		<method name="put(Z)Lorg/json/JSONArray;" />
+		<method name="remove(I)Ljava/lang/Object;" since="19" />
 		<method name="toJSONObject(Lorg/json/JSONArray;)Lorg/json/JSONObject;" />
 		<method name="toString(I)Ljava/lang/String;" />
 	</class>
@@ -48137,6 +50067,7 @@
 		<method name="remove(Ljava/lang/String;)Ljava/lang/Object;" />
 		<method name="toJSONArray(Lorg/json/JSONArray;)Lorg/json/JSONArray;" />
 		<method name="toString(I)Ljava/lang/String;" />
+		<method name="wrap(Ljava/lang/Object;)Ljava/lang/Object;" since="19" />
 		<field name="NULL" />
 	</class>
 	<class name="org/json/JSONStringer" since="1">
diff --git a/sdk/build_tools_source.prop_template b/sdk/build_tools_source.prop_template
new file mode 100644
index 0000000..c9bfc2f
--- /dev/null
+++ b/sdk/build_tools_source.prop_template
@@ -0,0 +1,3 @@
+Pkg.UserSrc=false
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.2
+
diff --git a/sdk/build_tools_source.properties b/sdk/build_tools_source.properties
deleted file mode 100644
index 7d096cc..0000000
--- a/sdk/build_tools_source.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-Pkg.UserSrc=false
-Pkg.Revision=18.1.1
-
diff --git a/sdk/images_armeabi_source.prop_template b/sdk/images_armeabi_source.prop_template
index 8644d10..906e378 100644
--- a/sdk/images_armeabi_source.prop_template
+++ b/sdk/images_armeabi_source.prop_template
@@ -1,6 +1,6 @@
 Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
 Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=2
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
 SystemImage.Abi=armeabi
diff --git a/sdk/images_x86_source.prop_template b/sdk/images_x86_source.prop_template
index a587cd1..90024ea 100644
--- a/sdk/images_x86_source.prop_template
+++ b/sdk/images_x86_source.prop_template
@@ -1,6 +1,6 @@
 Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
 Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=2
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
 SystemImage.Abi=x86
diff --git a/sdk/plat_tools_source.prop_template b/sdk/plat_tools_source.prop_template
new file mode 100644
index 0000000..b83af7f
--- /dev/null
+++ b/sdk/plat_tools_source.prop_template
@@ -0,0 +1,3 @@
+Pkg.UserSrc=false
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.1
+
diff --git a/sdk/plat_tools_source.properties b/sdk/plat_tools_source.properties
deleted file mode 100644
index 1ac7da0..0000000
--- a/sdk/plat_tools_source.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-Pkg.UserSrc=false
-Pkg.Revision=18.0.1
-
diff --git a/sdk/platform_source.prop_template b/sdk/platform_source.prop_template
index 39160b6..09a2d81 100644
--- a/sdk/platform_source.prop_template
+++ b/sdk/platform_source.prop_template
@@ -1,10 +1,10 @@
 Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
 Pkg.UserSrc=false
 Platform.Version=${PLATFORM_VERSION}
-Platform.CodeName=Jelly Bean
-Pkg.Revision=3
+Platform.CodeName=KitKat
+Pkg.Revision=2
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
-Layoutlib.Api=12
+Layoutlib.Api=10
 Layoutlib.Revision=1
-Platform.MinToolsRev=21
+Platform.MinToolsRev=22
diff --git a/sdk/source_source.prop_template b/sdk/source_source.prop_template
index d3cdfd5..523d6bd 100644
--- a/sdk/source_source.prop_template
+++ b/sdk/source_source.prop_template
@@ -1,4 +1,4 @@
 Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=2
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
diff --git a/sdk/support_source.prop_template b/sdk/support_source.prop_template
new file mode 100644
index 0000000..f897712
--- /dev/null
+++ b/sdk/support_source.prop_template
@@ -0,0 +1,8 @@
+Pkg.UserSrc=false
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.1
+Extra.Vendor=android
+Extra.VendorId=android
+Extra.VendorDisplay=Android
+Extra.NameDisplay=Android Support Library
+Extra.Path=support
+Extra.OldPaths=compatibility
diff --git a/sdk/support_source.properties b/sdk/support_source.properties
deleted file mode 100644
index 1617096..0000000
--- a/sdk/support_source.properties
+++ /dev/null
@@ -1,8 +0,0 @@
-Pkg.UserSrc=false
-Pkg.Revision=18
-Extra.Vendor=android
-Extra.VendorId=android
-Extra.VendorDisplay=Android
-Extra.NameDisplay=Android Support Library
-Extra.Path=support
-Extra.OldPaths=compatibility
diff --git a/sdk/usbdriver_source.properties b/sdk/usbdriver_source.properties
index bff71f9..c33d032 100755
--- a/sdk/usbdriver_source.properties
+++ b/sdk/usbdriver_source.properties
@@ -1,4 +1,4 @@
-Pkg.Revision=7

+Pkg.Revision=8

 Archive.Os=WINDOWS

 Archive.Arch=ANY

 Extra.Path=usb_driver

diff --git a/testrunner/android_build.py b/testrunner/android_build.py
index a10d43b..cacd67e 100644
--- a/testrunner/android_build.py
+++ b/testrunner/android_build.py
@@ -48,6 +48,25 @@
   return root_path
 
 
+def GetHostOutDir():
+  """Returns the full pathname of out/host/arch of the Android development tree.
+
+  Assumes build environment has been properly configured by envsetup &
+  lunch/choosecombo.
+
+  Returns:
+    the absolute file path of the Android host output directory.
+  Raises:
+    AbortError: if Android host output directory could not be found.
+  """
+  host_out_path = os.getenv("ANDROID_HOST_OUT")
+  if host_out_path is None:
+    logger.Log("Error: ANDROID_HOST_OUT not defined. Please run "
+               "envsetup.sh and lunch/choosecombo")
+    raise errors.AbortError
+  return host_out_path
+
+
 def GetHostOsArch():
   """Identify the host os and arch.
 
@@ -72,10 +91,25 @@
   return (host_os, host_arch, "%s-%s" % (host_os, host_arch))
 
 
+def GetOutDir():
+  """Returns the full pathname of the "out" of the Android development tree.
+
+  Assumes build environment has been properly configured by envsetup &
+  lunch/choosecombo.
+
+  Returns:
+    the absolute file path of the Android build output directory.
+  """
+  root_path = os.getenv("OUT_DIR")
+  if root_path is None:
+    root_path = os.path.join(GetTop(), "out")
+  return root_path
+
+
 def GetHostBin():
   """Compute the full pathname to the host binary directory.
 
-  Typically $ANDROID_BUILD_TOP/out/host/linux-x86/bin.
+  Typically $ANDROID_HOST_OUT/bin.
 
   Assumes build environment has been properly configured by envsetup &
   lunch/choosecombo.
@@ -86,8 +120,7 @@
   Raises:
     AbortError: if Android host binary directory could not be found.
   """
-  (_, _, os_arch) = GetHostOsArch()
-  path = os.path.join(GetTop(), "out", "host", os_arch, "bin")
+  path = os.path.join(GetHostOutDir(), "bin")
   if not os.path.exists(path):
     logger.Log("Error: Host bin path could not be found %s" % path)
     raise errors.AbortError
@@ -139,7 +172,7 @@
 def GetHostLibraryPath():
   """Returns the full pathname to the host java library output directory.
 
-  Typically $ANDROID_BUILD_TOP/out/host/<host_os>/framework.
+  Typically $ANDROID_HOST_OUT/framework.
 
   Assumes build environment has been properly configured by envsetup &
   lunch/choosecombo.
@@ -150,8 +183,7 @@
   Raises:
     AbortError: if Android host java library directory could not be found.
   """
-  (_, _, os_arch) = GetHostOsArch()
-  path = os.path.join(GetTop(), "out", "host", os_arch, "framework")
+  path = os.path.join(GetHostOutDir(), "framework")
   if not os.path.exists(path):
     logger.Log("Error: Host library path could not be found %s" % path)
     raise errors.AbortError
diff --git a/testrunner/coverage/coverage.py b/testrunner/coverage/coverage.py
index 570527d..824f5c5 100755
--- a/testrunner/coverage/coverage.py
+++ b/testrunner/coverage/coverage.py
@@ -43,7 +43,7 @@
   _EMMA_JAR = os.path.join("external", "emma", "lib", "emma.jar")
   _TEST_COVERAGE_EXT = "ec"
   # root path of generated coverage report files, relative to Android build root
-  _COVERAGE_REPORT_PATH = os.path.join("out", "emma")
+  _COVERAGE_REPORT_PATH = "emma"
   _TARGET_DEF_FILE = "coverage_targets.xml"
   _CORE_TARGET_PATH = os.path.join("development", "testrunner",
                                    _TARGET_DEF_FILE)
@@ -53,12 +53,13 @@
                                      _TARGET_DEF_FILE)
 
   # path to root of target build intermediates
-  _TARGET_INTERMEDIATES_BASE_PATH = os.path.join("out", "target", "common",
+  _TARGET_INTERMEDIATES_BASE_PATH = os.path.join("target", "common",
                                                  "obj")
 
   def __init__(self, adb_interface):
     self._root_path = android_build.GetTop()
-    self._output_root_path = os.path.join(self._root_path,
+    self._out_path = android_build.GetOut()
+    self._output_root_path = os.path.join(self._out_path,
                                           self._COVERAGE_REPORT_PATH)
     self._emma_jar_path = os.path.join(self._root_path, self._EMMA_JAR)
     self._adb = adb_interface
@@ -78,7 +79,7 @@
       target: the CoverageTarget to use as basis for coverage calculation
       device_coverage_path: location of coverage file on device
       output_path: path to place output files in. If None will use
-        <android_root_path>/<_COVERAGE_REPORT_PATH>/<target>/<test[-qualifier]>
+        <android_out_path>/<_COVERAGE_REPORT_PATH>/<target>/<test[-qualifier]>
       test_qualifier: designates mode test was run with. e.g size=small.
         If not None, this will be used to customize output_path as shown above.
 
@@ -89,7 +90,7 @@
       report_name = test_suite_name
       if test_qualifier:
         report_name = report_name + "-" + test_qualifier
-      output_path = os.path.join(self._root_path,
+      output_path = os.path.join(self._out_path,
                                  self._COVERAGE_REPORT_PATH,
                                  target.GetName(),
                                  report_name)
@@ -153,7 +154,7 @@
 
   def _GetBuildIntermediatePath(self, target):
     return os.path.join(
-        self._root_path, self._TARGET_INTERMEDIATES_BASE_PATH, target.GetType(),
+        self._out_path, self._TARGET_INTERMEDIATES_BASE_PATH, target.GetType(),
         "%s_intermediates" % target.GetName())
 
   def _GatherSrcs(self, targets):
diff --git a/testrunner/coverage_targets.xml b/testrunner/coverage_targets.xml
index 99ea93b..4ac5979 100644
--- a/testrunner/coverage_targets.xml
+++ b/testrunner/coverage_targets.xml
@@ -92,8 +92,6 @@
         type="APPS" />
 
    <!-- content providers -->
-    <coverage_target name="ApplicationsProvider"
-        build_path="packages/providers/ApplicationsProvider" type="APPS" />
     <coverage_target name="CalendarProvider"
         build_path="packages/providers/CalendarProvider" type="APPS" />
     <coverage_target name="ContactsProvider"
diff --git a/testrunner/runtest.py b/testrunner/runtest.py
index f7a4759..a76d9c0 100755
--- a/testrunner/runtest.py
+++ b/testrunner/runtest.py
@@ -75,16 +75,18 @@
 
   _DALVIK_VERIFIER_OFF_PROP = "dalvik.vm.dexopt-flags = v=n"
 
-  # regular expression to match install: statements in make output
-  _RE_MAKE_INSTALL = re.compile(r'Install:\s(.+)')
+  # regular expression to match path to artifacts to install in make output
+  _RE_MAKE_INSTALL = re.compile(r'INSTALL-PATH:\s(.+)\s(.+)')
 
-  # regular expression to find remote device path from a file path relative
-  # to build root
-  _RE_MAKE_INSTALL_PATH = re.compile(r'out\/target\/product\/\w+\/(.+)$')
 
   def __init__(self):
     # disable logging of timestamp
     self._root_path = android_build.GetTop()
+    out_base_name = os.path.basename(android_build.GetOutDir())
+    # regular expression to find remote device path from a file path relative
+    # to build root
+    pattern = r'' + out_base_name + r'\/target\/product\/\w+\/(.+)$'
+    self._re_make_install_path = re.compile(pattern)
     logger.SetTimestampLogging(False)
     self._adb = None
     self._known_tests = None
@@ -270,12 +272,13 @@
 
       # mmm cannot be used from python, so perform a similar operation using
       # ONE_SHOT_MAKEFILE
-      cmd = 'ONE_SHOT_MAKEFILE="%s" make -j%s -C "%s" all_modules %s' % (
+      cmd = 'ONE_SHOT_MAKEFILE="%s" make -j%s -C "%s" GET-INSTALL-PATH all_modules %s' % (
           target_build_string, self._options.make_jobs, self._root_path,
           extra_args_string)
       logger.Log(cmd)
       if not self._options.preview:
         output = run_command.RunCommand(cmd, return_output=True, timeout_time=600)
+        logger.SilentLog(output)
         self._DoInstall(output)
 
   def _DoInstall(self, make_output):
@@ -289,7 +292,7 @@
     for line in make_output.split("\n"):
       m = self._RE_MAKE_INSTALL.match(line)
       if m:
-        install_path = m.group(1)
+        install_path = m.group(2)
         if install_path.endswith(".apk"):
           abs_install_path = os.path.join(self._root_path, install_path)
           logger.Log("adb install -r %s" % abs_install_path)
@@ -298,9 +301,12 @@
           self._PushInstallFileToDevice(install_path)
 
   def _PushInstallFileToDevice(self, install_path):
-    m = self._RE_MAKE_INSTALL_PATH.match(install_path)
+    m = self._re_make_install_path.match(install_path)
     if m:
       remote_path = m.group(1)
+      remote_dir = os.path.dirname(remote_path)
+      logger.Log("adb shell mkdir -p %s" % remote_dir)
+      self._adb.SendShellCommand("mkdir -p %s" % remote_dir)
       abs_install_path = os.path.join(self._root_path, install_path)
       logger.Log("adb push %s %s" % (abs_install_path, remote_path))
       self._adb.Push(abs_install_path, remote_path)
@@ -313,7 +319,8 @@
 
     # hack to build cts dependencies
     # TODO: remove this when cts dependencies are removed
-    if self._IsCtsTests(tests):
+    is_cts =  self._IsCtsTests(tests)
+    if is_cts:
       # need to use make since these fail building with ONE_SHOT_MAKEFILE
       extra_args_set.add('CtsTestStubs')
       extra_args_set.add('android.core.tests.runner')
@@ -335,8 +342,15 @@
         old_dir = os.getcwd()
         os.chdir(self._root_path)
         output = run_command.RunCommand(cmd, return_output=True)
+        logger.SilentLog(output)
         os.chdir(old_dir)
         self._DoInstall(output)
+        if is_cts:
+          # hack! hardcode install of CtsTestStubs
+          out = android_build.GetTestAppPath()
+          abs_install_path = os.path.join(out, "CtsTestStubs.apk")
+          logger.Log("adb install -r %s" % abs_install_path)
+          logger.Log(self._adb.Install(abs_install_path))
 
   def _AddBuildTarget(self, test_suite, target_tree, extra_args_set):
     if not test_suite.IsFullMake():
diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml
index 516dc7c..421641f 100644
--- a/testrunner/test_defs.xml
+++ b/testrunner/test_defs.xml
@@ -137,9 +137,13 @@
     description="Framework libutils unit tests." />
 
 <test-native name="libinput"
-    build_path="frameworks/base/services/input/tests"
+    build_path="frameworks/native/libs/input/tests"
     description="Framework libinput unit tests." />
 
+<test-native name="libinputservice"
+    build_path="frameworks/base/services/input/tests"
+    description="Framework libinputservice unit tests." />
+
 <test name="volley"
     build_path="frameworks/support/volley/tests"
     package="com.android.volley.tests"
@@ -187,6 +191,12 @@
     runner=".MediaFrameworkUnitTestRunner"
     coverage_target="framework" />
 
+<test name="mediaintegrationtest"
+    build_path="frameworks/base/media/tests/MediaFrameworkTest"
+    package="com.android.mediaframeworktest"
+    runner=".MediaFrameworkIntegrationTestRunner"
+    coverage_target="framework" />
+
 <test-native name="camera-client-native"
     build_path="frameworks/av/camera/tests/"
     description="Camera client native tests." />
@@ -336,7 +346,7 @@
 <test name="cts-net"
     build_path="cts/tests/tests/net"
     package="com.android.cts.net"
-    runner="android.test.InstrumentationTestRunner"
+    runner="android.test.InstrumentationCtsTestRunner"
     coverage_target="framework"
     suite="cts" />
 
@@ -403,12 +413,6 @@
     build_path="development/samples/ApiDemos"
     package="com.example.android.apis.tests" />
 
-<test name="applicationsprov"
-    build_path="packages/providers/ApplicationsProvider"
-    package="com.android.providers.applications.tests"
-    coverage_target="ApplicationsProvider"
-    continuous="true" />
-
 <test name="browser"
     build_path="packages/apps/Browser"
     package="com.android.browser.tests"
@@ -529,6 +533,13 @@
     continuous="true"
     description="SystemUI tests" />
 
+<test name="documentsui"
+    build_path="frameworks/base/packages/DocumentsUI/tests"
+    package="com.android.documentsui.tests"
+    coverage_target="DocumentsUI"
+    continuous="true"
+    description="DocumentsUI tests" />
+
 <!--  native tests  -->
 
 <!-- Bionic C++ -->
diff --git a/testrunner/test_defs/gtest.py b/testrunner/test_defs/gtest.py
index 094ceea..dc72f94 100644
--- a/testrunner/test_defs/gtest.py
+++ b/testrunner/test_defs/gtest.py
@@ -89,7 +89,8 @@
       logger.SilentLog('Creating gtest suite for file %s' % test_file)
       suite = GTestSuite()
       suite.SetBuildPath(self.GetBuildPath())
-      suite.SetTargetExecPath(os.path.join(target_root_path, test_file))
+      # expect tests in /data/nativetest/test_file/test_file
+      suite.SetTargetExecPath(os.path.join(target_root_path, test_file, test_file))
       test_suites.append(suite)
     return test_suites
 
diff --git a/testrunner/test_defs/native_test.py b/testrunner/test_defs/native_test.py
index dc26c73..caef877 100644
--- a/testrunner/test_defs/native_test.py
+++ b/testrunner/test_defs/native_test.py
@@ -154,7 +154,7 @@
 
     Args:
       binary: basename of the file to be run. It is expected to be under
-            out/host/<os>-<arch>/bin.
+            $ANDROID_HOST_OUT/bin.
       valgrind: If True the command will be run under valgrind.
 
     Returns:
diff --git a/tools/emulator/test-apps/ConnectivityTest/Android.mk b/tools/emulator/test-apps/ConnectivityTest/Android.mk
index 097d118..ca20d57 100644
--- a/tools/emulator/test-apps/ConnectivityTest/Android.mk
+++ b/tools/emulator/test-apps/ConnectivityTest/Android.mk
@@ -24,6 +24,8 @@
 
 LOCAL_SDK_VERSION := 4
 
+LOCAL_PROGUARD_ENABLED := disabled
+
 include $(BUILD_PACKAGE)
 
 # Use the following include to make our test apk.
diff --git a/tools/emulator/test-apps/GpsLocationTest/Android.mk b/tools/emulator/test-apps/GpsLocationTest/Android.mk
index 35c9443..5f90f3a 100644
--- a/tools/emulator/test-apps/GpsLocationTest/Android.mk
+++ b/tools/emulator/test-apps/GpsLocationTest/Android.mk
@@ -24,6 +24,8 @@
 
 LOCAL_SDK_VERSION := 4
 
+LOCAL_PROGUARD_ENABLED := disabled
+
 include $(BUILD_PACKAGE)
 
 # Use the following include to make our test apk.
diff --git a/tools/idegen/Android.mk b/tools/idegen/Android.mk
index d424ab6..8771160 100644
--- a/tools/idegen/Android.mk
+++ b/tools/idegen/Android.mk
@@ -2,8 +2,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
-        guavalib \
+LOCAL_STATIC_JAVA_LIBRARIES := guavalib
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/tools/idegen/index-gen.sh b/tools/idegen/index-gen.sh
index eadaa98..5b9e24b 100755
--- a/tools/idegen/index-gen.sh
+++ b/tools/idegen/index-gen.sh
@@ -14,12 +14,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Generates a module index file by searching through android source tree for make files.  The
-# intellij-gen.sh script automatically calls this script the first time or if you delete the
-# generated indexed file.  The only time you need to run this manually is if modules are added or
-# deleted.
+# Generates a module index file by searching through android source
+# tree for make files.  The intellij-gen.sh script automatically calls
+# this script the first time or if you delete the generated indexed
+# file.  The only time you need to run this manually is if modules are
+# added or deleted.
 #
-# To use:
+# To use, run the following command from either your repo root or
+# development/tools/idegen:
 #   index-gen.sh
 #
 # Only tested on linux.  Should work for macs but have not tried.
@@ -27,7 +29,15 @@
 set -e
 
 script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-root_dir=`readlink -f -n $script_dir/../../..`
+#root_dir=`readlink -f -n $script_dir/../../..`
+root_dir=$PWD
+if [ ! -e $root_dir/.repo ]; then
+  root_dir=$PWD/../../..
+  if [ ! -e $root_dir/.repo ]; then
+    echo "Repo root not found. Run this script from your repo root or the idegen directory."
+    exit 1
+  fi
+fi
 tmp_file=tmp.txt
 dest_file=module-index.txt
 
diff --git a/tools/idegen/intellij-gen.sh b/tools/idegen/intellij-gen.sh
index 7f00eba..d67c1f8 100755
--- a/tools/idegen/intellij-gen.sh
+++ b/tools/idegen/intellij-gen.sh
@@ -14,7 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# To use:
+# To use, run the following command from either your repo root or
+# development/tools/idegen:
 #   intellij-gen.sh <module name>
 #
 # where module name is the LOCAL_PACKAGE_NAME in Android.mk for the project.
@@ -22,27 +23,38 @@
 # For example, to generate a project for Contacts, use:
 #   intellij-gen.sh Contacts
 #
-# The project directory (.idea) will be put in the root directory of the module.  Sharable iml
-# files will be put into each respective module directory.
+# The project directory (.idea) will be put in the root directory of
+# the module.  Sharable iml files will be put into each respective
+# module directory.
 #
 # Only tested on linux.  Should work for macs but have not tried.
 #
 set -e
 
-script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-root_dir=`readlink -f -n $script_dir/../../..`
-index_file=$script_dir/module-index.txt
-idegenjar=$root_dir/out/host/common/obj/JAVA_LIBRARIES/idegen_intermediates/javalib.jar
-
 progname=`basename $0`
 if [ $# -ne 1 ]
 then
     echo "Usage: $progname <module_name>"
     exit 1
 fi
-
 module_name=$1
 
+script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+root_dir=$PWD
+if [ ! -e $root_dir/.repo ]; then
+  root_dir=$PWD/../../..
+  if [ ! -e $root_dir/.repo ]; then
+    echo "Repo root not found. Run this script from your repo root or the idegen directory."
+    exit 1
+  fi
+fi
+index_file=$root_dir/module-index.txt
+idegenjar=$script_dir/idegen.jar
+if [ ! -e $idegenjar ]; then
+  # See if the jar is in the build directory.
+  idegenjar=$root_dir/out/host/linux-x86/framework/idegen.jar
+fi
+
 if [ ! -e "$index_file" ]; then
   echo "Module index file missing; generating this is only done the first time."
   echo "If any dependencies change, you should generate a new index file by running index-gen.sh."
diff --git a/tools/idegen/src/com/android/idegen/Constants.java b/tools/idegen/src/com/android/idegen/Constants.java
deleted file mode 100644
index f541dd4..0000000
--- a/tools/idegen/src/com/android/idegen/Constants.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.idegen;
-
-import java.nio.charset.Charset;
-
-/**
- * Constants
- */
-public class Constants {
-
-    public static final Charset CHARSET = Charset.forName("UTF-8");
-
-    public static final String REL_TEMPLATE_DIR = "development/tools/idegen/templates";
-    public static final String REL_MODULES_TEMPLATE = REL_TEMPLATE_DIR + "/idea/modules.xml";
-    public static final String REL_VCS_TEMPLATE = REL_TEMPLATE_DIR + "/idea/vcs.xml";
-    public static final String REL_IML_TEMPLATE = REL_TEMPLATE_DIR + "/module-template.iml";
-
-    public static final String REL_OUT_APP_DIR = "out/target/common/obj/APPS";
-
-    public static final String FRAMEWORK_MODULE = "framework";
-    public static final String[] AUTO_DEPENDENCIES = new String[]{
-            FRAMEWORK_MODULE, "libcore"
-    };
-    public static final String[] DIRS_WITH_AUTO_DEPENDENCIES = new String[] {
-      "packages", "vendor", "frameworks/ex", "frameworks/opt", "frameworks/support"
-    };
-
-    // Framework needs a special constant for it's intermediates because it does not follow
-    // normal conventions.
-    public static final String FRAMEWORK_INTERMEDIATES = "framework-res_intermediates";
-}
diff --git a/tools/idegen/src/com/android/idegen/DirectorySearch.java b/tools/idegen/src/com/android/idegen/DirectorySearch.java
index 1bbf99f..2ff23e3 100644
--- a/tools/idegen/src/com/android/idegen/DirectorySearch.java
+++ b/tools/idegen/src/com/android/idegen/DirectorySearch.java
@@ -21,8 +21,12 @@
 import com.google.common.collect.Sets;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FilenameFilter;
+import java.net.URISyntaxException;
 import java.util.HashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -31,6 +35,8 @@
  */
 public class DirectorySearch {
 
+    private static final Logger logger = Logger.getLogger(DirectorySearch.class.getName());
+
     private static final HashSet<String> SOURCE_DIRS = Sets.newHashSet();
     static {
         SOURCE_DIRS.add("src");
@@ -40,6 +46,9 @@
     private static final Pattern EXCLUDE_PATTERN = Pattern.compile("values-..(-.*)*");
 
     private static File repoRoot = null;
+    public static final String REL_TEMPLATE_DIR = "templates";
+    public static final String REL_TEMPLATE_PATH_FROM_ROOT = "development/tools/idegen/"
+            + REL_TEMPLATE_DIR;
 
     /**
      * Find the repo root.  This is the root branch directory of a full repo checkout.
@@ -138,4 +147,38 @@
 
         return builder.build();
     }
+
+    private static File templateDirCurrent = null;
+    private static File templateDirRoot = null;
+
+    public static File findTemplateDir() throws FileNotFoundException {
+        // Cache optimization.
+        if (templateDirCurrent != null && templateDirCurrent.exists()) return templateDirCurrent;
+        if (templateDirRoot != null && templateDirRoot.exists()) return templateDirRoot;
+
+        File currentDir = null;
+        try {
+            currentDir = new File(IntellijProject.class.getProtectionDomain().getCodeSource()
+                    .getLocation().toURI().getPath()).getParentFile();
+        } catch (URISyntaxException e) {
+            logger.log(Level.SEVERE, "Could not get jar location.", e);
+            return null;
+        }
+
+        // First check relative to current run directory.
+        templateDirCurrent = new File(currentDir, REL_TEMPLATE_DIR);
+        if (templateDirCurrent.exists()) {
+            return templateDirCurrent;
+        } else {
+            // Then check relative to root directory.
+            templateDirRoot = new File(repoRoot, REL_TEMPLATE_PATH_FROM_ROOT);
+            if (templateDirRoot.exists()) {
+                return templateDirRoot;
+            }
+        }
+        throw new FileNotFoundException(
+                "Unable to find template dir. Tried the following locations:\n" +
+                templateDirCurrent.getAbsolutePath() + "\n" +
+                templateDirRoot.getAbsolutePath());
+    }
 }
diff --git a/tools/idegen/src/com/android/idegen/FrameworkModule.java b/tools/idegen/src/com/android/idegen/FrameworkModule.java
index bfcd1fa..8743925 100644
--- a/tools/idegen/src/com/android/idegen/FrameworkModule.java
+++ b/tools/idegen/src/com/android/idegen/FrameworkModule.java
@@ -25,15 +25,19 @@
  */
 public class FrameworkModule extends StandardModule {
 
+    // Framework needs a special constant for it's intermediates because it does not follow
+    // normal conventions.
+    private static final String FRAMEWORK_INTERMEDIATES = "framework-res_intermediates";
+
     public FrameworkModule(String moduleName, String makeFile) {
-        super(Constants.FRAMEWORK_MODULE, makeFile, true);
+        super(IntellijProject.FRAMEWORK_MODULE, makeFile, true);
     }
 
     @Override
     protected String buildIntermediates() {
         StringBuilder sb = new StringBuilder();
         File intermediates = new File(repoRoot,
-                Constants.REL_OUT_APP_DIR + File.separator +  Constants.FRAMEWORK_INTERMEDIATES);
+                REL_OUT_APP_DIR + File.separator +  FRAMEWORK_INTERMEDIATES);
         ImmutableList<File> intermediateSrcDirs = DirectorySearch.findSourceDirs(intermediates);
         sb.append("    <content url=\"file://").append(intermediates).append("\">\n");
         for (File src : intermediateSrcDirs) {
diff --git a/tools/idegen/src/com/android/idegen/IntellijProject.java b/tools/idegen/src/com/android/idegen/IntellijProject.java
index d5564d5..e49a12b 100644
--- a/tools/idegen/src/com/android/idegen/IntellijProject.java
+++ b/tools/idegen/src/com/android/idegen/IntellijProject.java
@@ -22,6 +22,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.charset.Charset;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.logging.Logger;
@@ -31,9 +32,16 @@
  */
 public class IntellijProject {
 
+    public static final String FRAMEWORK_MODULE = "framework";
+    public static final Charset CHARSET = Charset.forName("UTF-8");
+
     private static final Logger logger = Logger.getLogger(IntellijProject.class.getName());
 
+    private static final String MODULES_TEMPLATE_FILE_NAME = "modules.xml";
+    private static final String VCS_TEMPLATE_FILE_NAME = "vcs.xml";
+
     ModuleCache cache = ModuleCache.getInstance();
+
     File indexFile;
     File repoRoot;
     File projectIdeaDir;
@@ -55,6 +63,11 @@
 
         // First pass, find all dependencies and cache them.
         Module module = cache.getAndCache(moduleName);
+        if (module == null) {
+            logger.info("Module '" + moduleName + "' not found." +
+                    " Module names are case senstive.");
+            return;
+        }
         projectIdeaDir = new File(module.getDir(), ".idea");
         projectIdeaDir.mkdir();
         copyTemplates();
@@ -104,19 +117,27 @@
 
     /**
      * Framework module needs special handling due to one off resource path:
-     *   frameworks/base/Android.mk
+     * frameworks/base/Android.mk
      */
     private void buildFrameWorkModule() throws IOException {
-        String makeFile = cache.getMakeFile(Constants.FRAMEWORK_MODULE);
-        logger.info("makefile: " + makeFile);
-        StandardModule frameworkModule = new FrameworkModule(Constants.FRAMEWORK_MODULE, makeFile);
-        frameworkModule.build();
-        cache.put(frameworkModule);
+        String makeFile = cache.getMakeFile(FRAMEWORK_MODULE);
+        if (makeFile == null) {
+            logger.warning("Unable to find framework module: " + FRAMEWORK_MODULE +
+                    ". Skipping.");
+        } else {
+            logger.info("makefile: " + makeFile);
+            StandardModule frameworkModule = new FrameworkModule(FRAMEWORK_MODULE,
+                    makeFile);
+            frameworkModule.build();
+            cache.put(frameworkModule);
+        }
     }
 
     private void createModulesFile(Module module) throws IOException {
-        String modulesContent = Files.toString(new File(repoRoot, Constants.REL_MODULES_TEMPLATE),
-                Constants.CHARSET);
+        String modulesContent = Files.toString(
+                new File(DirectorySearch.findTemplateDir(),
+                        "idea" + File.separator + MODULES_TEMPLATE_FILE_NAME),
+                CHARSET);
         StringBuilder sb = new StringBuilder();
         File moduleIml = module.getImlFile();
         sb.append("      <module fileurl=\"file://").append(moduleIml.getAbsolutePath())
@@ -131,12 +152,14 @@
 
         File out = new File(projectIdeaDir, "modules.xml");
         logger.info("Creating " + out.getAbsolutePath());
-        Files.write(modulesContent, out, Constants.CHARSET);
+        Files.write(modulesContent, out, CHARSET);
     }
 
     private void createVcsFile(Module module) throws IOException {
-        String vcsTemplate = Files.toString(new File(module.getRepoRoot(),
-                Constants.REL_VCS_TEMPLATE), Constants.CHARSET);
+        String vcsTemplate = Files.toString(
+                new File(DirectorySearch.findTemplateDir(),
+                        "idea" + File.separator + VCS_TEMPLATE_FILE_NAME),
+                CHARSET);
 
         StringBuilder sb = new StringBuilder();
         for (String name : module.getAllDependencies()) {
@@ -149,18 +172,17 @@
             }
         }
         vcsTemplate = vcsTemplate.replace("@VCS@", sb.toString());
-        Files.write(vcsTemplate, new File(projectIdeaDir, "vcs.xml"), Constants.CHARSET);
+        Files.write(vcsTemplate, new File(projectIdeaDir, "vcs.xml"), CHARSET);
     }
 
     private void createNameFile(String name) throws IOException {
-        File out =  new File(projectIdeaDir, ".name");
-        Files.write(name, out, Constants.CHARSET);
+        File out = new File(projectIdeaDir, ".name");
+        Files.write(name, out, CHARSET);
     }
 
     private void copyTemplates() throws IOException {
-        File templateDir = new File(repoRoot,
-                Constants.REL_TEMPLATE_DIR + File.separatorChar + "idea");
-        copyTemplates(templateDir, projectIdeaDir);
+        File templateDir = DirectorySearch.findTemplateDir();
+        copyTemplates(new File(templateDir, "idea"), projectIdeaDir);
     }
 
     private void copyTemplates(File fromDir, File toDir) throws IOException {
diff --git a/tools/idegen/src/com/android/idegen/Module.java b/tools/idegen/src/com/android/idegen/Module.java
index 7ba42a3..deb2281 100644
--- a/tools/idegen/src/com/android/idegen/Module.java
+++ b/tools/idegen/src/com/android/idegen/Module.java
@@ -34,6 +34,8 @@
 
     private static final Logger logger = Logger.getLogger(Module.class.getName());
 
+    private static final String IML_TEMPLATE_FILE_NAME = "module-template.iml";
+
     /**
      * All possible attributes for the make file.
      */
@@ -44,23 +46,35 @@
     }
 
     ModuleCache moduleCache = ModuleCache.getInstance();
+
     private File imlFile;
+
     private Set<String> allDependencies = Sets.newHashSet(); // direct + indirect
+
     private Set<File> allDependentImlFiles = Sets.newHashSet();
 
     protected abstract void build() throws IOException;
+
     protected abstract String getName();
+
     protected abstract File getDir();
+
     protected abstract boolean isAndroidModule();
+
     protected abstract List<File> getIntermediatesDirs();
+
     public abstract Set<String> getDirectDependencies();
+
     protected abstract ImmutableList<File> getSourceDirs();
+
     protected abstract ImmutableList<File> getExcludeDirs();
+
     public abstract File getRepoRoot();
 
     public void buildImlFile() throws IOException {
-        String imlTemplate = Files.toString(new File(getRepoRoot(), Constants.REL_IML_TEMPLATE),
-                Constants.CHARSET);
+        String imlTemplate = Files.toString(
+                new File(DirectorySearch.findTemplateDir(), IML_TEMPLATE_FILE_NAME),
+                IntellijProject.CHARSET);
 
         String facetXml = "";
         if (isAndroidModule()) {
@@ -100,7 +114,7 @@
 
         imlFile = new File(moduleDir, getName() + ".iml");
         logger.info("Creating " + imlFile.getAbsolutePath());
-        Files.write(imlTemplate, imlFile, Constants.CHARSET);
+        Files.write(imlTemplate, imlFile, IntellijProject.CHARSET);
     }
 
     protected String buildIntermediates() {
diff --git a/tools/idegen/src/com/android/idegen/StandardModule.java b/tools/idegen/src/com/android/idegen/StandardModule.java
index dffb95e..f7b24b0 100644
--- a/tools/idegen/src/com/android/idegen/StandardModule.java
+++ b/tools/idegen/src/com/android/idegen/StandardModule.java
@@ -17,6 +17,7 @@
 package com.android.idegen;
 
 import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
@@ -45,10 +46,18 @@
  */
 public class StandardModule extends Module {
 
+    static final String REL_OUT_APP_DIR = "out/target/common/obj/APPS";
+
     private static final Logger logger = Logger.getLogger(StandardModule.class.getName());
 
     private static final Pattern SRC_PATTERN = Pattern.compile(
             ".*\\(call all-java-files-under, (.*)\\)");
+    private static final String[] AUTO_DEPENDENCIES = new String[]{
+            IntellijProject.FRAMEWORK_MODULE, "libcore"
+    };
+    private static final String[] DIRS_WITH_AUTO_DEPENDENCIES = new String[]{
+            "packages", "vendor", "frameworks/ex", "frameworks/opt", "frameworks/support"
+    };
 
     String moduleName;
     File makeFile;
@@ -66,7 +75,8 @@
     }
 
     public StandardModule(String moduleName, String makeFile, boolean searchForSrc) {
-        this(moduleName, new File(makeFile), searchForSrc);
+        this(Preconditions.checkNotNull(moduleName), new File(Preconditions.checkNotNull(makeFile)),
+                searchForSrc);
     }
 
     public StandardModule(String moduleName, File makeFile, boolean searchForSrc) {
@@ -75,16 +85,16 @@
         this.moduleRoot = makeFile.getParentFile();
         this.repoRoot = DirectorySearch.findRepoRoot(makeFile);
         this.intermediatesDir = new File(repoRoot.getAbsolutePath() + File.separator +
-                Constants.REL_OUT_APP_DIR + File.separator + getName() + "_intermediates" +
+                REL_OUT_APP_DIR + File.separator + getName() + "_intermediates" +
                 File.separator + "src");
         this.searchForSrc = searchForSrc;
 
         // TODO: auto-detect when framework dependency is needed instead of using coded list.
-        for (String dir : Constants.DIRS_WITH_AUTO_DEPENDENCIES) {
+        for (String dir : DIRS_WITH_AUTO_DEPENDENCIES) {
             // length + 2 to account for slash
             boolean isDir = makeFile.getAbsolutePath().startsWith(repoRoot + "/" + dir);
             if (isDir) {
-                for (String dependency : Constants.AUTO_DEPENDENCIES) {
+                for (String dependency : AUTO_DEPENDENCIES) {
                     this.directDependencies.add(dependency);
                 }
             }
diff --git a/tools/recovery_l10n/res/values-en-rIN/strings.xml b/tools/recovery_l10n/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..b70d678c
--- /dev/null
+++ b/tools/recovery_l10n/res/values-en-rIN/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"Installing system update…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Erasing…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"No command."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Error!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-et-rEE/strings.xml b/tools/recovery_l10n/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..407a53d
--- /dev/null
+++ b/tools/recovery_l10n/res/values-et-rEE/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"Süsteemivärskenduste installimine ..."</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Kustutamine ..."</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"Käsk puudub."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Viga!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-fr-rCA/strings.xml b/tools/recovery_l10n/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..f2a85d8
--- /dev/null
+++ b/tools/recovery_l10n/res/values-fr-rCA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"Installation de la mise à jour du système en cours…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Effacement en cours…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"Aucune commande."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Erreur!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-hi/strings.xml b/tools/recovery_l10n/res/values-hi/strings.xml
index 3dfab3e..a470d12 100644
--- a/tools/recovery_l10n/res/values-hi/strings.xml
+++ b/tools/recovery_l10n/res/values-hi/strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recovery_installing" msgid="7864047928003865598">"सिस्टम अपडेट इंस्टॉल कर रहा है…"</string>
+    <string name="recovery_installing" msgid="7864047928003865598">"सिस्टम के बारे में नई जानकारी मिल रही है…"</string>
     <string name="recovery_erasing" msgid="4612809744968710197">"मिटा रहा है…"</string>
     <string name="recovery_no_command" msgid="1915703879031023455">"कोई आदेश नहीं."</string>
     <string name="recovery_error" msgid="4550265746256727080">"त्रुटि!"</string>
diff --git a/tools/recovery_l10n/res/values-hy-rAM/strings.xml b/tools/recovery_l10n/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..7babe80
--- /dev/null
+++ b/tools/recovery_l10n/res/values-hy-rAM/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"Համակարգի թարմացման տեղադրում…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Ջնջում…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"Հրամանը տրված չէ:"</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Սխալ"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-ka-rGE/strings.xml b/tools/recovery_l10n/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..2d27c17
--- /dev/null
+++ b/tools/recovery_l10n/res/values-ka-rGE/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"სისტემის განახლების დაყენება…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"მიმდინარეობს წაშლა…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"ბრძანება არ არის."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"შეცდომა!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-km-rKH/strings.xml b/tools/recovery_l10n/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..0c1c272
--- /dev/null
+++ b/tools/recovery_l10n/res/values-km-rKH/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"កំពុង​ដំឡើង​បច្ចុប្បន្នភាព​ប្រព័ន្ធ…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"កំពុង​លុប…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"គ្មាន​ពាក្យ​បញ្ជា។"</string>
+    <string name="recovery_error" msgid="4550265746256727080">"កំហុស!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-lo-rLA/strings.xml b/tools/recovery_l10n/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..5880cca
--- /dev/null
+++ b/tools/recovery_l10n/res/values-lo-rLA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"ກຳລັງຕິດຕັ້ງການອັບເດດລະບົບ..."</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"ກຳລັງລຶບ..."</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"ບໍ່ມີຄຳສັ່ງ."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"ຜິດພາດ!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-mn-rMN/strings.xml b/tools/recovery_l10n/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..463cafe
--- /dev/null
+++ b/tools/recovery_l10n/res/values-mn-rMN/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"Системийн шинэчлэлтийг суулгаж байна…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Арилгаж байна…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"Команд байхгүй."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Алдаа!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-ms-rMY/strings.xml b/tools/recovery_l10n/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..f563591
--- /dev/null
+++ b/tools/recovery_l10n/res/values-ms-rMY/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"Memasang kemas kini sistem..."</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"Memadam..."</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"Tiada arahan."</string>
+    <string name="recovery_error" msgid="4550265746256727080">"Ralat!"</string>
+</resources>
diff --git a/tools/recovery_l10n/res/values-zh-rHK/strings.xml b/tools/recovery_l10n/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..f615c7a
--- /dev/null
+++ b/tools/recovery_l10n/res/values-zh-rHK/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recovery_installing" msgid="7864047928003865598">"正在安裝系統更新…"</string>
+    <string name="recovery_erasing" msgid="4612809744968710197">"正在清除…"</string>
+    <string name="recovery_no_command" msgid="1915703879031023455">"沒有指令。"</string>
+    <string name="recovery_error" msgid="4550265746256727080">"錯誤!"</string>
+</resources>
diff --git a/tutorials/ReverseDebug/Android.mk b/tutorials/ReverseDebug/Android.mk
new file mode 100644
index 0000000..586daf8
--- /dev/null
+++ b/tutorials/ReverseDebug/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+ifneq ($(filter arm ,$(TARGET_ARCH)),)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= main.c.arm
+
+LOCAL_CFLAGS := -std=gnu99 -O0
+
+LOCAL_MODULE := reverse_debug
+
+include $(BUILD_EXECUTABLE)
+
+endif # arm in TARGET_ARCH
diff --git a/tutorials/ReverseDebug/README.txt b/tutorials/ReverseDebug/README.txt
new file mode 100644
index 0000000..2578a4d
--- /dev/null
+++ b/tutorials/ReverseDebug/README.txt
@@ -0,0 +1,137 @@
+This is a tutorial/unittest for gdb's reverse debugging feature. It is a new
+feature that allows users to take a snapshot of the machine state, continue
+until a later stage of the program, then return to the previously recorded
+state and execute again. An ideal usage case is to help track down the reason
+why a memory location is clobbered. 
+
+In the sample below, the "clobber" function trashes a neighboring variable "p"
+on the stack next to the "values" variable, and the program will crash at
+line 42 when "p" is being dereferenced.
+
+ 18 #include <stdio.h>
+ 19 #include <stdlib.h>
+ 20 
+ 21 #define ARRAY_LENGTH 10
+ 22 
+ 23 int flag;
+ 24 
+ 25 void clobber(int *array, int size) {
+ 26     /* Make sure it clobbers something. */
+ 27     array[-1] = 0x123;
+ 28     array[size] = 0x123;
+ 29 }
+ 30 
+ 31 int main(void) {
+ 32     int values[ARRAY_LENGTH];
+ 33     int *p = (int *) malloc(sizeof(int));
+ 34     *p = 10;
+ 35 
+ 36     while (!flag) {
+ 37         sleep(1);
+ 38     }
+ 39 
+ 40     /* Set a breakpint here: "b main.c:41" */
+ 41     clobber(values, ARRAY_LENGTH);
+ 42     printf("*p = %d\n", *p);
+ 43     free(p);
+ 44 
+ 45     return 0;
+ 46 }
+
+The test program can be built/installed on the device by doing:
+
+> mmm development/tutorials/ReverseDebug
+> adb sync
+> adb shell reverse_debug
+
+In another window the following command can be used to attach to the running
+program:
+
+> gdbclient reverse_debug :5039 reverse_debug
+[1] 12802
+Attached; pid = 1842
+Listening on port 5039
+GNU gdb (GDB) 7.6
+Copyright (C) 2013 Free Software Foundation, Inc.
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
+and "show warranty" for details.
+This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-android".
+For bug reporting instructions, please see:
+<http://source.android.com/source/report-bugs.html>...
+Reading symbols from /usr/local/google/work/master/out/target/product/manta/symbols/system/bin/reverse_debug...done.
+Remote debugging from host 127.0.0.1
+nanosleep () at bionic/libc/arch-arm/syscalls/nanosleep.S:10
+10      mov     r7, ip
+
+====
+
+Now set a breakpoint on line 41 and set flag to 1 so that the program can
+ continue. 
+
+(gdb) b main.c:41
+Breakpoint 1 at 0xb6f174a8: file development/tutorials/ReverseDebug/main.c, line 41.
+(gdb) p flag=1
+$1 = 1
+(gdb) c
+Continuing.
+
+====
+
+Now try the new "record" command to take a snapshot of the machine state.
+
+Breakpoint 1, main () at development/tutorials/ReverseDebug/main.c:41
+41      clobber(values, ARRAY_LENGTH);
+(gdb) record
+(gdb) c
+Continuing.
+
+====
+
+Now the program crashes as expected as "p" has been clobbered. The
+"reverse-continue" command will bring the program back to line 41 and let you
+replay each instruction from there.
+
+Program received signal SIGSEGV, Segmentation fault.
+0xb6f174bc in main () at development/tutorials/ReverseDebug/main.c:42
+42      printf("*p = %d\n", *p);
+(gdb) reverse-continue
+Continuing.
+
+No more reverse-execution history.
+main () at development/tutorials/ReverseDebug/main.c:41
+41      clobber(values, ARRAY_LENGTH);
+
+
+====
+
+Now let's add a watch point at "&p" to hopefully catch the clobber on the spot:
+ 
+(gdb) watch *(&p)
+Hardware watchpoint 2: *(&p)
+(gdb) c
+Continuing.
+Hardware watchpoint 2: *(&p)
+
+====
+
+And here it is:
+
+Old value = (int *) 0xb728c020
+New value = (int *) 0x123
+0xb6f17440 in clobber (array=0xbebcaab0, size=10)
+    at development/tutorials/ReverseDebug/main.c:28
+28      array[size] = 0x123;
+
+
+===============================
+
+That said, reverse debugging on ARM is still in the infant stage. Currently
+(as of gdb 7.6) it only recognizes ARM instructions and will punt on all
+Thumb(2) instructions. To give it a try you will need to recompile your
+program in ARM mode. To do that you have to add the ".arm" suffix to the
+desired file in Android.mk:
+
+LOCAL_SRC_FILES:= main.c.arm
+
diff --git a/tutorials/ReverseDebug/main.c b/tutorials/ReverseDebug/main.c
new file mode 100644
index 0000000..5ae1890
--- /dev/null
+++ b/tutorials/ReverseDebug/main.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ARRAY_LENGTH 10
+
+int flag;
+
+void clobber(int *array, int size) {
+    /* Make sure it clobbers something. */
+    array[-1] = 0x123;
+    array[size] = 0x123;
+}
+
+int main(void) {
+    int values[ARRAY_LENGTH];
+    int *p = (int *) malloc(sizeof(int));
+    *p = 10;
+
+    while (!flag) {
+        sleep(1);
+    }
+
+    /* Set a breakpint here: "b main.c:41" */
+    clobber(values, ARRAY_LENGTH);
+    printf("*p = %d\n", *p);
+    free(p);
+
+    return 0;
+}