Add prebuilt browseable samples as static files.

Change-Id: Ifb5382223343400882834d2dd9c182c3df602e34
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/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..d1967d3
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="ActivityInstrumentation"
+sample.group=Testing
+@jd:body
+
+<p>
+            
+            This sample provides a basic example of using an InstrumentationTest to probe the
+            internal state of an Activity.
+            
+        </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..901b569
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/_index.jd
@@ -0,0 +1,18 @@
+
+
+
+page.tags="AdvancedImmersiveMode"
+sample.group=UI
+@jd:body
+
+<p>
+            
+            \"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.
+            
+        </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..17f668d
--- /dev/null
+++ b/samples/browseable/Basic/_index.jd
@@ -0,0 +1,15 @@
+
+
+
+page.tags="Basic"
+sample.group=UI
+@jd:body
+
+<p>
+            
+            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.
+            
+        </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..b1c6dde
--- /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 an accessible application, using a mix of different widgets demonstrating different ways of adding accessibility markup to a UI.
+            
+        </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..b69787e
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/_index.jd
@@ -0,0 +1,17 @@
+
+
+
+page.tags="BasicAndroidKeyStore"
+sample.group=Security
+@jd:body
+
+<p>
+            
+                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            
+        </p>
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..a947004
--- /dev/null
+++ b/samples/browseable/BasicContactables/_index.jd
@@ -0,0 +1,14 @@
+
+
+
+page.tags="BasicContactables"
+sample.group=Content
+@jd:body
+
+<p>
+            
+            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!
+            
+        </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..bdcd925
--- /dev/null
+++ b/samples/browseable/BasicGestureDetect/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="BasicGestureDetect"
+sample.group=Input
+@jd:body
+
+<p>
+            
+            Welcome to Basic Gesture Detect!
+            In order to try this sample out, try dragging or tapping this text to see what happens!
+            
+        </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..5394b6b
--- /dev/null
+++ b/samples/browseable/BasicImmersiveMode/_index.jd
@@ -0,0 +1,14 @@
+
+
+
+page.tags="BasicImmersiveMode"
+sample.group=UI
+@jd:body
+
+<p>
+            
+            \"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.
+            
+        </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..af8e5e4
--- /dev/null
+++ b/samples/browseable/BasicMediaDecoder/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="BasicMediaDecoder"
+sample.group=Media
+@jd:body
+
+<p>
+            
+             This activity uses a TextureView to render the frames of a video decoded using the
+             MediaCodec API.
+            
+        </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..b97fcff
--- /dev/null
+++ b/samples/browseable/BasicMediaRouter/_index.jd
@@ -0,0 +1,17 @@
+
+
+
+page.tags="BasicMediaRouter"
+sample.group=Media
+@jd:body
+
+<p>
+            
+            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.
+            
+        </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