Merge "ndk: Remove obsolete API level 11 platform files"
diff --git a/apps/Fallback/res/values-af/strings.xml b/apps/Fallback/res/values-af/strings.xml
new file mode 100644
index 0000000..8cf16a7
--- /dev/null
+++ b/apps/Fallback/res/values-af/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Terugval"</string>
+    <string name="title" msgid="8156274565006125136">"Nie-ondersteunde handeling"</string>
+    <string name="error" msgid="6539615832923362301">"Hierdie handeling word tans nie ondersteun nie."</string>
+</resources>
diff --git a/apps/Fallback/res/values-am/strings.xml b/apps/Fallback/res/values-am/strings.xml
new file mode 100644
index 0000000..0c89122
--- /dev/null
+++ b/apps/Fallback/res/values-am/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Fallback"</string>
+    <string name="title" msgid="8156274565006125136">"የማይደገፍ ድርጊት"</string>
+    <string name="error" msgid="6539615832923362301">"ያድርጊት በአሁኑ ጊዜ የማይደገፍ ነው።"</string>
+</resources>
diff --git a/apps/Fallback/res/values-iw/strings.xml b/apps/Fallback/res/values-iw/strings.xml
index 671919b..cbf35ef 100644
--- a/apps/Fallback/res/values-iw/strings.xml
+++ b/apps/Fallback/res/values-iw/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="appTitle" msgid="161410001913116606">"החזרה"</string>
+    <string name="appTitle" msgid="161410001913116606">"חלופי"</string>
     <string name="title" msgid="8156274565006125136">"פעולה לא נתמכת"</string>
     <string name="error" msgid="6539615832923362301">"הפעולה אינה נתמכת בשלב זה."</string>
 </resources>
diff --git a/apps/Fallback/res/values-ms/strings.xml b/apps/Fallback/res/values-ms/strings.xml
new file mode 100644
index 0000000..930fe79
--- /dev/null
+++ b/apps/Fallback/res/values-ms/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Jatuh balik"</string>
+    <string name="title" msgid="8156274565006125136">"Tindakan tidak disokong"</string>
+    <string name="error" msgid="6539615832923362301">"Tindakan tidak disokong pada masa ini."</string>
+</resources>
diff --git a/apps/Fallback/res/values-sw/strings.xml b/apps/Fallback/res/values-sw/strings.xml
new file mode 100644
index 0000000..4b07acb
--- /dev/null
+++ b/apps/Fallback/res/values-sw/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Kimbilio"</string>
+    <string name="title" msgid="8156274565006125136">"Kitendo kisichohimiliwa"</string>
+    <string name="error" msgid="6539615832923362301">"Kitendo hakihimili kwa sasa."</string>
+</resources>
diff --git a/apps/Fallback/res/values-zu/strings.xml b/apps/Fallback/res/values-zu/strings.xml
new file mode 100644
index 0000000..2c85d28
--- /dev/null
+++ b/apps/Fallback/res/values-zu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="appTitle" msgid="161410001913116606">"Buyela emuva"</string>
+    <string name="title" msgid="8156274565006125136">"Isenzo esingasekelwe"</string>
+    <string name="error" msgid="6539615832923362301">"Leso senzo okwamanje asisekelwe."</string>
+</resources>
diff --git a/build/sdk-android-armeabi-v7a.atree b/build/sdk-android-armeabi-v7a.atree
index 8a79994..8867bf7 100644
--- a/build/sdk-android-armeabi-v7a.atree
+++ b/build/sdk-android-armeabi-v7a.atree
@@ -15,4 +15,7 @@
 #
 
 # Copy the ARMv7 specific kernel image to .../kernel-qemu
-prebuilt/android-${TARGET_ARCH}/kernel/kernel-qemu-armv7 platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/kernel-qemu
+prebuilt/android-${TARGET_ARCH}/kernel/kernel-qemu-armv7 system-images/${PLATFORM_NAME}/${TARGET_CPU_ABI}/kernel-qemu
+
+# version files for the SDK updater, from development.git
+development/sdk/images_armeabi-v7a_source.properties   system-images/${PLATFORM_NAME}/${TARGET_CPU_ABI}/source.properties
diff --git a/build/sdk-android-armeabi.atree b/build/sdk-android-armeabi.atree
index d90b069..a31eca6 100644
--- a/build/sdk-android-armeabi.atree
+++ b/build/sdk-android-armeabi.atree
@@ -14,4 +14,7 @@
 # limitations under the License.
 #
 
-prebuilt/android-${TARGET_ARCH}/kernel/kernel-qemu platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/kernel-qemu
+prebuilt/android-${TARGET_ARCH}/kernel/kernel-qemu system-images/${PLATFORM_NAME}/${TARGET_CPU_ABI}/kernel-qemu
+
+# version files for the SDK updater, from development.git
+development/sdk/images_armeabi_source.properties   system-images/${PLATFORM_NAME}/${TARGET_CPU_ABI}/source.properties
diff --git a/build/sdk-android-x86.atree b/build/sdk-android-x86.atree
index d90b069..748478a 100644
--- a/build/sdk-android-x86.atree
+++ b/build/sdk-android-x86.atree
@@ -14,4 +14,7 @@
 # limitations under the License.
 #
 
-prebuilt/android-${TARGET_ARCH}/kernel/kernel-qemu platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/kernel-qemu
+prebuilt/android-${TARGET_ARCH}/kernel/kernel-qemu system-images/${PLATFORM_NAME}/${TARGET_CPU_ABI}/kernel-qemu
+
+# version files for the SDK updater, from development.git
+development/sdk/images_x86_source.properties   system-images/${PLATFORM_NAME}/${TARGET_CPU_ABI}/source.properties
diff --git a/build/sdk-windows-x86.atree b/build/sdk-windows-x86.atree
new file mode 100644
index 0000000..68105a2
--- /dev/null
+++ b/build/sdk-windows-x86.atree
@@ -0,0 +1,60 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# These are the files that comprise the *Windows* SDK.
+#
+# The Windows SDK is based on the Linux one so in this file we
+# need to remove Linux binaries and replace them by their
+# Windows counterparts.
+#
+# This file only includes platform-dependent files.
+# Tools-dependent files (and not tied to a specific platform)
+# are controled by sdk/build/tools.windows.atree.
+#
+
+rm platform-tools/adb
+bin/adb.exe                             strip platform-tools/adb.exe
+bin/AdbWinUsbApi.dll                          platform-tools/AdbWinUsbApi.dll
+bin/AdbWinApi.dll                             platform-tools/AdbWinApi.dll
+
+rm platform-tools/aapt
+bin/aapt.exe                            strip platform-tools/aapt.exe
+
+rm platform-tools/aidl
+bin/aidl.exe                            strip platform-tools/aidl.exe
+
+rm platform-tools/dx
+dalvik/dx/etc/dx.bat                          platform-tools/dx.bat
+
+rm platform-tools/dexdump
+bin/dexdump.exe                         strip platform-tools/dexdump.exe
+
+rm platform-tools/llvm-rs-cc
+bin/llvm-rs-cc.exe                      strip platform-tools/llvm-rs-cc.exe
+
+prebuilt/windows/swt/swt.jar                  tools/lib/x86/swt.jar
+prebuilt/windows-x86_64/swt/swt.jar           tools/lib/x86_64/swt.jar
+
+external/sonivox/jet_tools/JetCreator                 tools/Jet/JetCreator
+external/sonivox/jet_tools/JetCreator_content         tools/Jet/demo_content
+external/sonivox/jet_tools/logic_templates            tools/Jet/logic_templates
+prebuilt/windows/jetcreator/EASDLL.dll                tools/Jet/JetCreator/EASDLL.dll
+external/sonivox/docs/JET_Authoring_Guidelines.html   docs/JetCreator/JET_Authoring_Guidelines.html
+external/sonivox/docs/JET_Authoring_Guidelines_files  docs/JetCreator/JET_Authoring_Guidelines_files
+external/sonivox/docs/JET_Creator_User_Manual.html    docs/JetCreator/JET_Creator_User_Manual.html
+external/sonivox/docs/JET_Creator_User_Manual_files   docs/JetCreator/JET_Creator_User_Manual_files
+
diff --git a/build/sdk.atree b/build/sdk.atree
index 3d7d1af..35ca61a 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -38,11 +38,10 @@
 ##############################################################################
 
 # host tools from out/host/$(HOST_OS)-$(HOST_ARCH)/
-bin/adb                                       platform-tools/adb
-bin/aapt                                      platform-tools/aapt
-bin/aidl                                      platform-tools/aidl
-bin/llvm-rs-cc                                platform-tools/llvm-rs-cc
-development/sdk/llvm-rs-cc.txt                platform-tools/llvm-rs-cc.txt
+bin/adb                                 strip platform-tools/adb
+bin/aapt                                strip platform-tools/aapt
+bin/aidl                                strip platform-tools/aidl
+bin/llvm-rs-cc                          strip platform-tools/llvm-rs-cc
 
 # dx
 bin/dx                                        platform-tools/dx
@@ -55,7 +54,7 @@
 # Platform Component
 ##############################################################################
 
-# version files for the SDK updater, from sdk.git
+# version files for the SDK updater, from development.git
 development/sdk/platform_source.properties    platforms/${PLATFORM_NAME}/source.properties
 
 # copy build prop from out/.../sdk/
@@ -72,14 +71,6 @@
 external/clang/lib/Headers       platforms/${PLATFORM_NAME}/renderscript/clang-include
 external/clang/LICENSE.TXT       platforms/${PLATFORM_NAME}/renderscript/clang-include/LICENSE.TXT
 
-# System images + Kernel
-system.img                              platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/system.img
-ramdisk.img                             platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/ramdisk.img
-userdata.img                            platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/userdata.img
-system/build.prop platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/build.prop
-
-# Note: the kernel image is handled by sdk-android-<abi>.atree now.
-
 # emulator skins from sdk.git
 development/tools/emulator/skins/QVGA      platforms/${PLATFORM_NAME}/skins/QVGA
 development/tools/emulator/skins/WQVGA432  platforms/${PLATFORM_NAME}/skins/WQVGA432
@@ -88,7 +79,8 @@
 development/tools/emulator/skins/WVGA800   platforms/${PLATFORM_NAME}/skins/WVGA800
 development/tools/emulator/skins/WVGA854   platforms/${PLATFORM_NAME}/skins/WVGA854
 development/tools/emulator/skins/WSVGA     platforms/${PLATFORM_NAME}/skins/WSVGA
-development/tools/emulator/skins/WXGA      platforms/${PLATFORM_NAME}/skins/WXGA
+development/tools/emulator/skins/WXGA720   platforms/${PLATFORM_NAME}/skins/WXGA720
+development/tools/emulator/skins/WXGA800   platforms/${PLATFORM_NAME}/skins/WXGA800
 
 # Platform SDK properties
 development/sdk/sdk.properties               platforms/${PLATFORM_NAME}/sdk.properties
@@ -123,6 +115,18 @@
 sdk/files/sdk_files_NOTICE.txt platforms/${PLATFORM_NAME}/skins/NOTICE.txt
 
 ##############################################################################
+# System image Component
+##############################################################################
+
+# System images + Kernel
+system.img                                 system-images/${PLATFORM_NAME}/${TARGET_CPU_ABI}/system.img
+ramdisk.img                                system-images/${PLATFORM_NAME}/${TARGET_CPU_ABI}/ramdisk.img
+userdata.img                               system-images/${PLATFORM_NAME}/${TARGET_CPU_ABI}/userdata.img
+system/build.prop                          system-images/${PLATFORM_NAME}/${TARGET_CPU_ABI}/build.prop
+
+# Note: the kernel image is handled by sdk-android-<abi>.atree now.
+
+##############################################################################
 # Docs Component
 ##############################################################################
 
@@ -149,6 +153,8 @@
 #
 development/samples/AccessibilityService       samples/${PLATFORM_NAME}/AccessibilityService
 development/samples/AccelerometerPlay          samples/${PLATFORM_NAME}/AccelerometerPlay
+development/samples/ActionBarCompat            samples/${PLATFORM_NAME}/ActionBarCompat
+development/samples/AndroidBeam                samples/${PLATFORM_NAME}/AndroidBeam
 development/samples/ApiDemos                   samples/${PLATFORM_NAME}/ApiDemos
 development/samples/BackupRestore              samples/${PLATFORM_NAME}/BackupRestore
 development/samples/BasicGLSurfaceView         samples/${PLATFORM_NAME}/BasicGLSurfaceView
@@ -162,7 +168,9 @@
 development/samples/LunarLander                samples/${PLATFORM_NAME}/LunarLander
 development/samples/MultiResolution            samples/${PLATFORM_NAME}/MultiResolution
 development/samples/NotePad                    samples/${PLATFORM_NAME}/NotePad
+development/samples/NFCDemo                    samples/${PLATFORM_NAME}/NFCDemo
 development/samples/RandomMusicPlayer          samples/${PLATFORM_NAME}/RandomMusicPlayer
+development/samples/SampleSpellCheckerService  samples/${PLATFORM_NAME}/SampleSpellCheckerService
 development/samples/SampleSyncAdapter          samples/${PLATFORM_NAME}/SampleSyncAdapter
 development/samples/SearchableDictionary       samples/${PLATFORM_NAME}/SearchableDictionary
 development/samples/SipDemo                    samples/${PLATFORM_NAME}/SipDemo
@@ -180,6 +188,7 @@
 development/samples/VoicemailProviderDemo      samples/${PLATFORM_NAME}/VoicemailProviderDemo
 development/samples/WeatherListWidget          samples/${PLATFORM_NAME}/WeatherListWidget
 development/apps/WidgetPreview                 samples/${PLATFORM_NAME}/WidgetPreview
+development/samples/WiFiDirectDemo             samples/${PLATFORM_NAME}/WiFiDirectDemo
 development/samples/Wiktionary                 samples/${PLATFORM_NAME}/Wiktionary
 development/samples/WiktionarySimple           samples/${PLATFORM_NAME}/WiktionarySimple
 development/samples/XmlAdapters                samples/${PLATFORM_NAME}/XmlAdapters
@@ -200,18 +209,18 @@
 sdk/files/README_add-ons.txt add-ons/README.txt
 
 ##############################################################################
-# Extra Component: Compatibility
+# Extra Component: Support
 ##############################################################################
 
-development/sdk/compatibility_source.properties                                                   extras/android/compatibility/source.properties
-development/sdk/compatibility_README.txt                                                          extras/android/compatibility/README.txt
-sdk/files/sdk_files_NOTICE.txt                                                                    extras/android/compatibility/NOTICE.txt
-${OUT_DIR}/target/common/obj/PACKAGING/android-support-v4_intermediates/android-support-v4.jar    extras/android/compatibility/v4/android-support-v4.jar
-frameworks/support/v4                                                                             extras/android/compatibility/v4/src
-development/samples/Support4Demos                                                                 extras/android/compatibility/v4/samples/Support4Demos
-${OUT_DIR}/target/common/obj/PACKAGING/android-support-v13_intermediates/android-support-v13.jar  extras/android/compatibility/v13/android-support-v13.jar
-frameworks/support/v13                                                                            extras/android/compatibility/v13/src
-development/samples/Support13Demos                                                                extras/android/compatibility/v13/samples/Support13Demos
+development/sdk/support_source.properties                                                         extras/android/support/source.properties
+development/sdk/support_README.txt                                                                extras/android/support/README.txt
+sdk/files/sdk_files_NOTICE.txt                                                                    extras/android/support/NOTICE.txt
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-v4_intermediates/android-support-v4.jar    extras/android/support/v4/android-support-v4.jar
+frameworks/support/v4                                                                             extras/android/support/v4/src
+development/samples/Support4Demos                                                                 extras/android/support/v4/samples/Support4Demos
+${OUT_DIR}/target/common/obj/PACKAGING/android-support-v13_intermediates/android-support-v13.jar  extras/android/support/v13/android-support-v13.jar
+frameworks/support/v13                                                                            extras/android/support/v13/src
+development/samples/Support13Demos                                                                extras/android/support/v13/samples/Support13Demos
 
 ##############################################################################
 # Tests Component
diff --git a/build/tools/mk_sdk_repo_xml.sh b/build/tools/mk_sdk_repo_xml.sh
index 56f426b..a97ecaf 100755
--- a/build/tools/mk_sdk_repo_xml.sh
+++ b/build/tools/mk_sdk_repo_xml.sh
@@ -6,7 +6,7 @@
 
 PROG_DIR=$(dirname $0)
 
-TYPES="tool platform-tool platform sample doc add-on"
+TYPES="tool platform-tool platform sample doc add-on system-image source support"
 OSES="linux macosx windows any linux-x86 darwin"
 
 TMP_DIR=$(mktemp -d -t sdkrepo.tmp.XXXXXXXX)
@@ -86,12 +86,17 @@
   Platform.Version              version
   AndroidVersion.ApiLevel       api-level
   AndroidVersion.CodeName       codename
+  Platform.IncludedAbi          included-abi
   Platform.MinToolsRev          min-tools-rev
   Platform.MinPlatformToolsRev  min-platform-tools-rev
-  Extra.Path                    path
   Extra.Vendor                  vendor
+  Extra.Path                    path
+  Extra.OldPaths                old-paths
   Extra.MinApiLevel             min-api-level
   Sample.MinApiLevel            min-api-level
+  SystemImage.Abi               abi
+  Layoutlib.Api                 layoutlib/api
+  Layoutlib.Revision            layoutlib/revision
   # for addon packages
   vendor                        vendor
   name                          name
@@ -124,23 +129,37 @@
   local OUT="$1"
   shift
   local KEY VALUE
+  local NODE LAST_NODE
 
   while [[ "$1" ]]; do
     KEY="$1"
     VALUE="${2//@/ }"
+    NODE="${KEY%%/*}"
+    KEY="${KEY##*/}"
+    [[ "$NODE" == "$KEY" ]] && NODE=""
+    if [[ "$NODE" != "$LAST_NODE" ]]; then
+        [[ "$LAST_NODE" ]] && echo "          </sdk:$LAST_NODE>" >> "$OUT"
+        LAST_NODE="$NODE"
+        [[ "$NODE"      ]] && echo "          <sdk:$NODE>" >> "$OUT"
+    fi
     echo "        <sdk:$KEY>$VALUE</sdk:$KEY>" >> "$OUT"
     shift
     shift
   done
+  if [[ "$LAST_NODE" ]]; then echo "          </sdk:$LAST_NODE>" >> "$OUT"; fi
 }
 
 while [[ -n "$1" ]]; do
   # Process archives.
-  # First we expect a type. For conveniency the type can be plural.
+  # First we expect a type. For convenience the type can be plural.
   TYPE=$(check_enum "${1%%s}" $TYPES)
   [[ -z $TYPE ]] && error "Unknown archive type '$1'."
   shift
 
+  ELEMENT="$TYPE"
+  # The element name is different for extras:
+  [[ "$TYPE" == "support" ]] && ELEMENT="extra"
+
   MAP=""
   FIRST="1"
   LIBS_XML=""
@@ -168,13 +187,16 @@
     # - description             all
     # - revision                all
     # - version                 platform
-    # - api-level               platform sample doc add-on
-    # - codename                platform sample doc add-on
+    # - included-abi            platform
+    # - api-level               platform sample doc add-on system-image
+    # - codename                platform sample doc add-on system-image
     # - min-tools-rev           platform sample
     # - min-platform-tools-rev  tool
     # - min-api-level           extra
     # - vendor                  extra               add-on
     # - path                    extra
+    # - old-paths               extra
+    # - abi                     system-image
     #
     # We don't actually validate here.
     # Just take whatever is defined and put it in the XML.
@@ -212,7 +234,7 @@
       MAP=$(parse_attributes "$PROPS" ${ATTRS[@]})
 
       # Time to generate the XML for the package
-      echo "    <sdk:${TYPE}>" >> "$OUT"
+      echo "    <sdk:${ELEMENT}>" >> "$OUT"
       output_attributes "$OUT" $MAP
       [[ -n "$LIBS_XML" ]] && echo "$LIBS_XML" >> "$OUT"
       echo "        <sdk:archives>" >> "$OUT"
@@ -241,7 +263,7 @@
 
     if [[ ! "$OS" ]]; then
       echo "        </sdk:archives>" >> "$OUT"
-      echo "    </sdk:${TYPE}>" >> "$OUT"
+      echo "    </sdk:${ELEMENT}>" >> "$OUT"
     fi
   done
 
diff --git a/build/tools/mk_sources_zip.py b/build/tools/mk_sources_zip.py
new file mode 100755
index 0000000..3d4c582
--- /dev/null
+++ b/build/tools/mk_sources_zip.py
@@ -0,0 +1,202 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import re
+import os
+import sys
+import getopt
+import zipfile
+
+VERBOSE = False
+TOP_FOLDER = "src"
+_RE_PKG = re.compile("^\s*package\s+([^\s;]+)\s*;.*")
+
+# Holds cmd-line arguments and context information
+class Params(object):
+    def __init__(self):
+        self.DRY = False
+        self.PROPS = None
+        self.SRC = None
+        self.DST = None
+        self.CNT_USED = 0
+        self.CNT_NOPKG = 0
+        # DIR is the list of directories to scan in TOPDIR.
+        self.DIR = "frameworks libcore"
+        # IGNORE is a list of namespaces to ignore. Must be java
+        # package definitions (e.g. "com.blah.foo.")
+        self.IGNORE = [ "sun.", "libcore.", "dalvik.",
+                        "com.test.", "com.google.",
+                        "coretestutils.", "test.", "test2.", "tests." ]
+        self.zipfile = None
+
+
+def verbose(msg, *args):
+    """Prints a verbose message to stderr if --verbose is set."""
+    global VERBOSE
+    if VERBOSE:
+        if args:
+            msg = msg % args
+        print >>sys.stderr, msg
+
+
+# Prints a usage summary
+def usage(error=None):
+    print """
+ Description:
+   This script collects all framework Java sources from the current android
+   source code and places them in a source.zip file that can be distributed
+   by the SDK Manager.
+
+ Usage:
+   %s [-n|-v] <source.properties> <sources.zip> <topdir>
+
+ The source.properties file must exist and will be injected in the Zip file.
+ The source directory must already exist.
+ Use -v for verbose output (lists each file being picked up or ignored).
+ Use -n for a dry-run (doesn't write the zip file).
+
+""" % sys.argv[0]
+
+    if error:
+        print >>sys.stderr, "Error:", error
+
+
+# Parse command line args, returns a Params instance or sys.exit(2) on error
+# after printing the error and the usage.
+def parseArgs(argv):
+    global VERBOSE
+    p = Params()
+    error = None
+
+    try:
+        opts, args = getopt.getopt(argv[1:],
+                                   "vns:",
+                                   [ "--verbose", "--dry", "--sourcedir=" ])
+    except getopt.GetoptError, e:
+        error = str(e)
+
+    if error is None:
+        for o, a in opts:
+            if o in [ "-n", "--dry" ]:
+                p.DRY = True
+            if o in [ "-v", "--verbose" ]:
+                VERBOSE = True
+            elif o in [ "-s", "--sourcedir" ]:
+                p.DIR = a
+
+        if len(args) != 3:
+            error = "Missing arguments: <source> <dest>"
+        else:
+            p.PROPS = args[0]
+            p.DST = args[1]
+            p.SRC = args[2]
+
+            if not os.path.isfile(p.PROPS):
+                error = "%s is not a file" % p.PROPS
+            if not os.path.isdir(p.SRC):
+                error = "%s is not a directory" % p.SRC
+
+    if error:
+        usage(error)
+        sys.exit(2)
+
+    return p
+
+
+# Recursively parses the given directory and processes java files found
+def parseSrcDir(p, srcdir):
+    if not os.path.exists(srcdir):
+        verbose("Error: Skipping unknown directory %s", srcdir)
+        return
+
+    for filename in os.listdir(srcdir):
+        filepath = os.path.join(srcdir, filename)
+        if filename.endswith(".java") and os.path.isfile(filepath):
+            pkg = checkJavaFile(filepath)
+            if not pkg:
+                verbose("No package found in %s", filepath)
+            if pkg:
+                # Should we ignore this package?
+                for ignore in p.IGNORE:
+                    if pkg.startswith(ignore):
+                        verbose("Ignore package %s [%s]", pkg, filepath)
+                        pkg = None
+                        break
+
+            if pkg:
+                pkg = pkg.replace(".", os.path.sep)  # e.g. android.view => android/view
+                copy(p, filepath, pkg)
+                p.CNT_USED += 1
+            else:
+                p.CNT_NOPKG += 1
+        elif os.path.isdir(filepath):
+            parseSrcDir(p, filepath)
+
+
+# Check a java file to find its package declaration, if any
+def checkJavaFile(path):
+    try:
+        f = None
+        try:
+            f = file(path)
+            for l in f.readlines():
+                m = _RE_PKG.match(l)
+                if m:
+                    return m.group(1)
+        finally:
+            if f: f.close()
+    except Exception:
+        pass
+
+    return None
+
+
+# Copy the given file (given its absolute filepath) to
+# the relative desk_pkg directory in the zip file.
+def copy(p, filepath, dest_pkg):
+    arc_path = os.path.join(TOP_FOLDER, dest_pkg, os.path.basename(filepath))
+    if p.DRY:
+        print >>sys.stderr, "zip %s [%s]" % (arc_path, filepath)
+    elif p.zipfile is not None:
+        p.zipfile.write(filepath, arc_path)
+
+
+def main():
+    p = parseArgs(sys.argv)
+    z = None
+    try:
+        if not p.DRY:
+            p.zipfile = z = zipfile.ZipFile(p.DST, "w", zipfile.ZIP_DEFLATED)
+            z.write(p.PROPS, TOP_FOLDER + "/source.properties")
+        for d in p.DIR.split():
+            if d:
+                parseSrcDir(p, os.path.join(p.SRC, d))
+    finally:
+        if z is not None:
+            z.close()
+    print "%s: %d java files copied" % (p.DST, p.CNT_USED)
+    if p.CNT_NOPKG:
+        print "%s: %d java files ignored" % (p.DST, p.CNT_NOPKG)
+    if p.DRY:
+        print >>sys.stderr, "This was in *DRY* mode. No copies done."
+
+
+if __name__ == "__main__":
+    main()
+
+# For emacs:
+# -*- tab-width: 4; -*-
diff --git a/build/tools/patch_windows_sdk.sh b/build/tools/patch_windows_sdk.sh
index 5f60970..6d30577 100755
--- a/build/tools/patch_windows_sdk.sh
+++ b/build/tools/patch_windows_sdk.sh
@@ -1,4 +1,19 @@
 #!/bin/bash
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
 
 # This script takes a Linux SDK, cleans it and injects the necessary Windows
 # binaries needed by the SDK. The script has 2 parts:
@@ -53,55 +68,13 @@
     $USB_DRIVER_HOOK $V $TEMP_SDK_DIR $TOPDIR
 fi
 
-# Remove obsolete stuff from tools & platform
-TOOLS=$TEMP_SDK_DIR/tools
-PLATFORM_TOOLS=$TEMP_SDK_DIR/platform-tools
-LIB=$TEMP_SDK_DIR/tools/lib
-rm $V $TOOLS/{dmtracedump,etc1tool,hprof-conv,sqlite3,zipalign}
-rm $V $LIB/*/swt.jar
-rm $V $PLATFORM_TOOLS/{adb,aapt,aidl,dx,dexdump,llvm-rs-cc}
 
-# Copy all the new stuff in tools
-# Note: some tools are first copied here and then moved in platform-tools
-cp $V $WIN_OUT_DIR/host/windows-x86/bin/*.{exe,dll} $TOOLS/
-# Remove some tools we don't want to take in the SDK
-rm $V -f $TOOLS/{fastboot.exe,rs-spec-gen.exe,tblgen.exe}
-mkdir -pv $LIB/x86
-cp $V ${TOPDIR}prebuilt/windows/swt/swt.jar         $LIB/x86/
-mkdir -pv $LIB/x86_64
-cp $V ${TOPDIR}prebuilt/windows-x86_64/swt/swt.jar  $LIB/x86_64/
-
-# Put the JetCreator tools, content and docs (not available in the linux SDK)
-JET=$TOOLS/Jet
-JETCREATOR=$JET/JetCreator
-JETDEMOCONTENT=$JET/demo_content
-JETLOGICTEMPLATES=$JET/logic_templates
-JETDOC=$TEMP_SDK_DIR/docs/JetCreator
-
-# need to rm these folders since a Mac SDK will have them and it might create a conflict
-rm -rf $V $JET
-rm -rf $V $JETDOC
-
-# now create fresh folders for JetCreator
-mkdir $V $JET
-mkdir $V $JETDOC
-
-cp -r $V ${TOPDIR}external/sonivox/jet_tools/JetCreator         $JETCREATOR/
-cp -r $V ${TOPDIR}external/sonivox/jet_tools/JetCreator_content $JETDEMOCONTENT/
-cp -r $V ${TOPDIR}external/sonivox/jet_tools/logic_templates    $JETLOGICTEMPLATES/
-chmod $V -R u+w $JETCREATOR  # fixes an issue where Cygwin might copy the above as u+rx only
-cp $V ${TOPDIR}prebuilt/windows/jetcreator/EASDLL.dll           $JETCREATOR/
-
-cp    $V ${TOPDIR}external/sonivox/docs/JET_Authoring_Guidelines.html  $JETDOC/
-cp -r $V ${TOPDIR}external/sonivox/docs/JET_Authoring_Guidelines_files $JETDOC/
-cp    $V ${TOPDIR}external/sonivox/docs/JET_Creator_User_Manual.html   $JETDOC/
-cp -r $V ${TOPDIR}external/sonivox/docs/JET_Creator_User_Manual_files  $JETDOC/
-
-# Copy or move platform specific tools to the default platform.
-cp $V ${TOPDIR}dalvik/dx/etc/dx.bat $PLATFORM_TOOLS/
-mv $V $TOOLS/{adb.exe,aapt.exe,aidl.exe,dexdump.exe} $PLATFORM_TOOLS/
-mv $V $TOOLS/Adb*.dll $PLATFORM_TOOLS/
-mv $V $TOOLS/llvm-rs-cc.exe                               $PLATFORM_TOOLS/llvm-rs-cc.exe
+# Invoke atree to copy the files
+# TODO: pass down OUT_HOST_EXECUTABLE to get the right bin/atree directory
+${TOPDIR}out/host/linux-x86/bin/atree -f ${TOPDIR}development/build/sdk-windows-x86.atree \
+      -I $WIN_OUT_DIR/host/windows-x86 \
+      -I ${TOPDIR:-.} \
+      -o $TEMP_SDK_DIR
 
 # Fix EOL chars to make window users happy - fix all files at the top level
 # as well as all batch files including those in platform-tools/
diff --git a/build/tools/sdk_repo.mk b/build/tools/sdk_repo.mk
index c709502..de48e57 100644
--- a/build/tools/sdk_repo.mk
+++ b/build/tools/sdk_repo.mk
@@ -56,6 +56,48 @@
 	$(call sdk-repo-pkg-zip,$(1),$(2),$(3)):$(notdir $(call sdk-repo-pkg-zip,$(1),$(2),$(3)))
 endef
 
+# Defines the rule to build an SDK repository package when the
+# package directory contains 3 levels from the sdk dir, for example
+# to package SDK/extra/android/support or SDK/system-images/android-N/armeabi.
+# Because we do not know the intermediary directory name, this only works
+# if each directory contains a single sub-directory (e.g. sdk/$4/*/* must be
+# unique.)
+#
+# $1=OS (e.g. linux-x86, windows, etc)
+# $2=sdk zip (e.g. out/host/linux.../android-eng-sdk.zip)
+# $3=package to create (e.g. system-images, support, etc.)
+# $4=the root of directory to package in the sdk (e.g. extra/android).
+#    this must be a 2-segment path, the last one can be *.
+#
+# The rule depends on the SDK zip file, which is defined by $2.
+#
+define mk-sdk-repo-pkg-3
+$(call sdk-repo-pkg-zip,$(1),$(2),$(3)): $(2)
+	@echo "Building SDK repository package $(3) from $(notdir $(2))"
+	$(hide) cd $(basename $(2))/$(4) && \
+			zip -9rq ../../../$(notdir $(call sdk-repo-pkg-zip,$(1),$(2),$(3))) *
+$(call dist-for-goals, sdk_repo, $(call sdk-repo-pkg-zip,$(1),$(2),$(3)))
+SDK_REPO_XML_ARGS += $(3) $(1) \
+	$(call sdk-repo-pkg-zip,$(1),$(2),$(3)):$(notdir $(call sdk-repo-pkg-zip,$(1),$(2),$(3)))
+endef
+
+# Defines the rule to build an SDK sources package.
+#
+# $1=OS (e.g. linux-x86, windows, etc)
+# $2=sdk zip (e.g. out/host/linux.../android-eng-sdk.zip)
+# $3=package to create, must be "sources"
+#
+define mk-sdk-repo-sources
+$(call sdk-repo-pkg-zip,$(1),$(2),$(3)): $(2) $(TOPDIR)development/sdk/source_source.properties
+	@echo "Building SDK sources package"
+	$(hide) $(TOPDIR)development/build/tools/mk_sources_zip.py \
+			$(TOPDIR)development/sdk/source_source.properties \
+			$(call sdk-repo-pkg-zip,$(1),$(2),$(3)) \
+			$(TOPDIR).
+$(call dist-for-goals, sdk_repo, $(call sdk-repo-pkg-zip,$(1),$(2),$(3)))
+SDK_REPO_XML_ARGS += $(3) $(1) \
+	$(call sdk-repo-pkg-zip,$(1),$(2),$(3)):$(notdir $(call sdk-repo-pkg-zip,$(1),$(2),$(3)))
+endef
 
 # -----------------------------------------------------------------
 # Rules for win_sdk
@@ -67,7 +109,7 @@
 $(eval $(call mk-sdk-repo-pkg-1,windows,$(WIN_SDK_ZIP),platform-tools))
 
 SDK_REPO_DEPS += \
-		$(call sdk-repo-pkg-zip,windows,$(WIN_SDK_ZIP),tools) \
+	$(call sdk-repo-pkg-zip,windows,$(WIN_SDK_ZIP),tools) \
         $(call sdk-repo-pkg-zip,windows,$(WIN_SDK_ZIP),platform-tools)
 
 endif
@@ -82,6 +124,9 @@
 $(eval $(call mk-sdk-repo-pkg-1,$(HOST_OS),$(MAIN_SDK_ZIP),docs))
 $(eval $(call mk-sdk-repo-pkg-2,$(HOST_OS),$(MAIN_SDK_ZIP),platforms))
 $(eval $(call mk-sdk-repo-pkg-2,$(HOST_OS),$(MAIN_SDK_ZIP),samples))
+$(eval $(call mk-sdk-repo-pkg-3,$(HOST_OS),$(MAIN_SDK_ZIP),system-images,system-images/*))
+$(eval $(call mk-sdk-repo-pkg-3,$(HOST_OS),$(MAIN_SDK_ZIP),support,extras/android))
+$(eval $(call mk-sdk-repo-sources,$(HOST_OS),$(MAIN_SDK_ZIP),sources))
 
 SDK_REPO_DEPS += \
 		$(call sdk-repo-pkg-zip,$(HOST_OS),$(MAIN_SDK_ZIP),tools) \
@@ -89,6 +134,9 @@
 		$(call sdk-repo-pkg-zip,$(HOST_OS),$(MAIN_SDK_ZIP),docs) \
 		$(call sdk-repo-pkg-zip,$(HOST_OS),$(MAIN_SDK_ZIP),platforms) \
 		$(call sdk-repo-pkg-zip,$(HOST_OS),$(MAIN_SDK_ZIP),samples) \
+		$(call sdk-repo-pkg-zip,$(HOST_OS),$(MAIN_SDK_ZIP),system-images) \
+		$(call sdk-repo-pkg-zip,$(HOST_OS),$(MAIN_SDK_ZIP),support) \
+		$(call sdk-repo-pkg-zip,$(HOST_OS),$(MAIN_SDK_ZIP),sources)
 
 endif
 
diff --git a/build/tools/windows_sdk.mk b/build/tools/windows_sdk.mk
index 8421a91..2a6fc74 100644
--- a/build/tools/windows_sdk.mk
+++ b/build/tools/windows_sdk.mk
@@ -22,10 +22,13 @@
 $(error Need a unix2dos command. Please 'apt-get install tofrodos')
 endif
 
+# Define WIN_SDK_TARGETS, the list of targets located in topdir/sdk
+# and are tools-dependent, not platform-dependent.
 include $(TOPDIR)sdk/build/windows_sdk_tools.mk
 
-# This is the list of target that we want to generate as
-# Windows executables.
+# This is the list of targets that we want to generate as
+# Windows executables. All the targets specified here are located in
+# the topdir/development directory and are somehow platform-dependent.
 WIN_TARGETS := \
 	aapt adb aidl \
 	etc1tool \
@@ -84,7 +87,6 @@
 	$(hide) USB_DRIVER_HOOK=$(USB_DRIVER_HOOK) \
 		$(TOPDIR)development/build/tools/patch_windows_sdk.sh $(subst @,-q,$(hide)) \
 		$(WIN_SDK_DIR)/$(WIN_SDK_NAME) $(OUT_DIR) $(TOPDIR)
-	$(hide) strip --strip-all $(WIN_SDK_DIR)/$(WIN_SDK_NAME)/platform-tools/llvm-rs-cc.exe
 	$(hide) $(TOPDIR)sdk/build/patch_windows_sdk.sh $(subst @,-q,$(hide)) \
 		$(WIN_SDK_DIR)/$(WIN_SDK_NAME) $(OUT_DIR) $(TOPDIR)
 	$(hide) ( \
diff --git a/data/etc/apns-conf.xml b/data/etc/apns-conf.xml
index 156fec2..2fe90d9 100644
--- a/data/etc/apns-conf.xml
+++ b/data/etc/apns-conf.xml
@@ -19,7 +19,7 @@
 
 <!-- use empty string to specify no proxy or port -->
 <!-- This version must agree with that in apps/common/res/apns.xml -->
-<apns version="6">
+<apns version="7">
     <apn carrier="T-Mobile US"
          mcc="310"
          mnc="260"
diff --git a/data/etc/apns-conf_sdk.xml b/data/etc/apns-conf_sdk.xml
index 5129dc7..0e9cf7d 100644
--- a/data/etc/apns-conf_sdk.xml
+++ b/data/etc/apns-conf_sdk.xml
@@ -23,7 +23,7 @@
 
 <!-- use empty string to specify no proxy or port -->
 <!-- This version must agree with that in apps/common/res/apns.xml -->
-<apns version="6">
+<apns version="7">
     <apn carrier="Android"
         mcc="310"
         mnc="995"
diff --git a/samples/ActionBarCompat/Android.mk b/samples/ActionBarCompat/Android.mk
new file mode 100644
index 0000000..d9da54a
--- /dev/null
+++ b/samples/ActionBarCompat/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := samples
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := ActionBarCompat
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/samples/ActionBarCompat/AndroidManifest.xml b/samples/ActionBarCompat/AndroidManifest.xml
new file mode 100644
index 0000000..1a48274
--- /dev/null
+++ b/samples/ActionBarCompat/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.actionbarcompat"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="14" />
+
+    <application 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/ActionBarCompat/_index.html b/samples/ActionBarCompat/_index.html
new file mode 100644
index 0000000..8808de1
--- /dev/null
+++ b/samples/ActionBarCompat/_index.html
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<p>This sample shows how to use the action bar design pattern on pre-API 11 devices and the built-in
+<a href="../../../reference/android/app/ActionBar.html">ActionBar</a> on devices supporting API
+11 or greater. The example 'compatible' action bar, instantiated on pre-Android 3.0 devices,
+uses the same <a href="../../../guide/topics/resources/menu-resource.html">menu resource</a>-based
+action item definition mechanism as the new framework API, even supporting the
+<code>android:showAsAction</code> attribute to a limited extent.</p>
+
+<img alt="" src="../images/ActionBarCompat1.png" height="320" />
+<img alt="" src="../images/ActionBarCompat2.png" height="320" />
diff --git a/samples/ActionBarCompat/res/drawable-hdpi/actionbar_shadow.9.png b/samples/ActionBarCompat/res/drawable-hdpi/actionbar_shadow.9.png
new file mode 100644
index 0000000..3c80a3f
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-hdpi/actionbar_shadow.9.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-hdpi/ic_action_refresh.png b/samples/ActionBarCompat/res/drawable-hdpi/ic_action_refresh.png
new file mode 100644
index 0000000..efe99e0
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-hdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-hdpi/ic_action_search.png b/samples/ActionBarCompat/res/drawable-hdpi/ic_action_search.png
new file mode 100644
index 0000000..f6719d2
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-hdpi/ic_action_search.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-hdpi/ic_action_share.png b/samples/ActionBarCompat/res/drawable-hdpi/ic_action_share.png
new file mode 100644
index 0000000..7d0b872
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-hdpi/ic_action_share.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-hdpi/ic_home.png b/samples/ActionBarCompat/res/drawable-hdpi/ic_home.png
new file mode 100644
index 0000000..7e52ff5
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-hdpi/ic_home.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-hdpi/ic_launcher.png b/samples/ActionBarCompat/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..e4b0492
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-hdpi/ic_menu_share.png b/samples/ActionBarCompat/res/drawable-hdpi/ic_menu_share.png
new file mode 100755
index 0000000..a78bf7a
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-hdpi/ic_menu_share.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-mdpi/actionbar_shadow.9.png b/samples/ActionBarCompat/res/drawable-mdpi/actionbar_shadow.9.png
new file mode 100644
index 0000000..cae1778
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-mdpi/actionbar_shadow.9.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-mdpi/ic_action_refresh.png b/samples/ActionBarCompat/res/drawable-mdpi/ic_action_refresh.png
new file mode 100644
index 0000000..a85eee3
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-mdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-mdpi/ic_action_search.png b/samples/ActionBarCompat/res/drawable-mdpi/ic_action_search.png
new file mode 100755
index 0000000..45d2398
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-mdpi/ic_action_search.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-mdpi/ic_action_share.png b/samples/ActionBarCompat/res/drawable-mdpi/ic_action_share.png
new file mode 100644
index 0000000..26a39bd
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-mdpi/ic_action_share.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-mdpi/ic_home.png b/samples/ActionBarCompat/res/drawable-mdpi/ic_home.png
new file mode 100644
index 0000000..949b4aa
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-mdpi/ic_home.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-mdpi/ic_launcher.png b/samples/ActionBarCompat/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..78d0e29
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-mdpi/ic_menu_share.png b/samples/ActionBarCompat/res/drawable-mdpi/ic_menu_share.png
new file mode 100755
index 0000000..3329b6b
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-mdpi/ic_menu_share.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-xhdpi/actionbar_shadow.9.png b/samples/ActionBarCompat/res/drawable-xhdpi/actionbar_shadow.9.png
new file mode 100644
index 0000000..30778e3
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-xhdpi/actionbar_shadow.9.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-xhdpi/ic_action_refresh.png b/samples/ActionBarCompat/res/drawable-xhdpi/ic_action_refresh.png
new file mode 100644
index 0000000..6ce9376
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-xhdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-xhdpi/ic_action_search.png b/samples/ActionBarCompat/res/drawable-xhdpi/ic_action_search.png
new file mode 100644
index 0000000..f89c4e9
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-xhdpi/ic_action_search.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-xhdpi/ic_action_share.png b/samples/ActionBarCompat/res/drawable-xhdpi/ic_action_share.png
new file mode 100644
index 0000000..47b27d1
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-xhdpi/ic_action_share.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-xhdpi/ic_home.png b/samples/ActionBarCompat/res/drawable-xhdpi/ic_home.png
new file mode 100644
index 0000000..03eb53d
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-xhdpi/ic_home.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable-xhdpi/ic_launcher.png b/samples/ActionBarCompat/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..485f7be
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/ActionBarCompat/res/drawable/actionbar_compat_item.xml b/samples/ActionBarCompat/res/drawable/actionbar_compat_item.xml
new file mode 100644
index 0000000..4b3960c
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable/actionbar_compat_item.xml
@@ -0,0 +1,23 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/actionbar_compat_item_pressed"
+        android:state_pressed="true" />
+    <item android:drawable="@drawable/actionbar_compat_item_focused"
+        android:state_focused="true" />
+    <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/samples/ActionBarCompat/res/drawable/actionbar_compat_item_focused.xml b/samples/ActionBarCompat/res/drawable/actionbar_compat_item_focused.xml
new file mode 100644
index 0000000..04811d3
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable/actionbar_compat_item_focused.xml
@@ -0,0 +1,19 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#ef7000" />
+</shape>
diff --git a/samples/ActionBarCompat/res/drawable/actionbar_compat_item_pressed.xml b/samples/ActionBarCompat/res/drawable/actionbar_compat_item_pressed.xml
new file mode 100644
index 0000000..72ff4b4
--- /dev/null
+++ b/samples/ActionBarCompat/res/drawable/actionbar_compat_item_pressed.xml
@@ -0,0 +1,19 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#eda700" />
+</shape>
diff --git a/samples/ActionBarCompat/res/layout-v11/actionbar_indeterminate_progress.xml b/samples/ActionBarCompat/res/layout-v11/actionbar_indeterminate_progress.xml
new file mode 100644
index 0000000..c05750e
--- /dev/null
+++ b/samples/ActionBarCompat/res/layout-v11/actionbar_indeterminate_progress.xml
@@ -0,0 +1,27 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center">
+    <ProgressBar android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:layout_marginLeft="12dp"
+        android:layout_marginRight="12dp"
+        android:layout_gravity="center"
+        style="?android:attr/indeterminateProgressStyle" />
+</FrameLayout>
diff --git a/samples/HoneycombGallery/res/layout/action_bar_custom.xml b/samples/ActionBarCompat/res/layout/actionbar_compat.xml
similarity index 60%
copy from samples/HoneycombGallery/res/layout/action_bar_custom.xml
copy to samples/ActionBarCompat/res/layout/actionbar_compat.xml
index 5f111d9..ae6c44b 100644
--- a/samples/HoneycombGallery/res/layout/action_bar_custom.xml
+++ b/samples/ActionBarCompat/res/layout/actionbar_compat.xml
@@ -1,24 +1,21 @@
 <!--
-  Copyright (C) 2011 The Android Open Source Project
+  Copyright 2011 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
 
-       http://www.apache.org/licenses/LICENSE-2.0
+      http://www.apache.org/licenses/LICENSE-2.0
 
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
- -->
+  -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">Hello Action Bar</TextView>
-</LinearLayout>
+    android:id="@id/actionbar_compat"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="horizontal" />
diff --git a/samples/ActionBarCompat/res/layout/main.xml b/samples/ActionBarCompat/res/layout/main.xml
new file mode 100644
index 0000000..a58a346
--- /dev/null
+++ b/samples/ActionBarCompat/res/layout/main.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    <Button android:id="@+id/toggle_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/toggle_title" />
+</FrameLayout>
diff --git a/samples/ActionBarCompat/res/menu/main.xml b/samples/ActionBarCompat/res/menu/main.xml
new file mode 100644
index 0000000..a306a3c
--- /dev/null
+++ b/samples/ActionBarCompat/res/menu/main.xml
@@ -0,0 +1,34 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_refresh"
+        android:title="@string/menu_refresh"
+        android:icon="@drawable/ic_action_refresh"
+        android:orderInCategory="1"
+        android:showAsAction="always" />
+    <item android:id="@+id/menu_search"
+        android:title="@string/menu_search"
+        android:icon="@drawable/ic_action_search"
+        android:orderInCategory="0"
+        android:showAsAction="always" />
+
+    <item android:id="@+id/menu_share"
+        android:title="@string/menu_share"
+        android:icon="@drawable/ic_menu_share"
+        android:orderInCategory="1"
+        android:showAsAction="never" />
+</menu>
diff --git a/samples/ActionBarCompat/res/values-v11/styles.xml b/samples/ActionBarCompat/res/values-v11/styles.xml
new file mode 100644
index 0000000..dc1aa7c
--- /dev/null
+++ b/samples/ActionBarCompat/res/values-v11/styles.xml
@@ -0,0 +1,34 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="AppTheme" parent="android:style/Theme.Holo.Light">
+        <item name="android:actionBarStyle">@style/ActionBar</item>
+        <item name="android:windowContentOverlay">@drawable/actionbar_shadow</item>
+    </style>
+
+    <style name="ActionBar" parent="android:style/Widget.Holo.Light.ActionBar">
+        <item name="android:background">#eee</item>
+        <item name="android:titleTextStyle">@style/ActionBarTitle</item>
+        <item name="android:icon">@drawable/ic_home</item>
+    </style>
+
+    <style name="ActionBarTitle">
+        <item name="android:textColor">@color/actionbar_title_color</item>
+    </style>
+
+</resources>
diff --git a/samples/ActionBarCompat/res/values-v13/styles.xml b/samples/ActionBarCompat/res/values-v13/styles.xml
new file mode 100644
index 0000000..8a042b4
--- /dev/null
+++ b/samples/ActionBarCompat/res/values-v13/styles.xml
@@ -0,0 +1,23 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="ActionBarTitle" parent="android:style/TextAppearance.Holo.Widget.ActionBar.Title">
+        <item name="android:textColor">@color/actionbar_title_color</item>
+    </style>
+
+</resources>
diff --git a/samples/ActionBarCompat/res/values/attrs.xml b/samples/ActionBarCompat/res/values/attrs.xml
new file mode 100644
index 0000000..c59822c
--- /dev/null
+++ b/samples/ActionBarCompat/res/values/attrs.xml
@@ -0,0 +1,31 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <declare-styleable name="AppTheme">
+        <attr name="actionbarCompatTitleStyle" format="reference" />
+        <attr name="actionbarCompatItemStyle" format="reference" />
+        <attr name="actionbarCompatItemHomeStyle" format="reference" />
+        <attr name="actionbarCompatProgressIndicatorStyle" format="reference" />
+    </declare-styleable>
+
+    <declare-styleable name="BezelImageView">
+        <attr name="maskDrawable" format="reference" />
+        <attr name="borderDrawable" format="reference" />
+    </declare-styleable>
+
+</resources>
diff --git a/samples/ActionBarCompat/res/values/colors.xml b/samples/ActionBarCompat/res/values/colors.xml
new file mode 100644
index 0000000..4edc6d6
--- /dev/null
+++ b/samples/ActionBarCompat/res/values/colors.xml
@@ -0,0 +1,19 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <color name="actionbar_title_color">#224894</color>
+</resources>
diff --git a/samples/ActionBarCompat/res/values/dimens.xml b/samples/ActionBarCompat/res/values/dimens.xml
new file mode 100644
index 0000000..67c8436
--- /dev/null
+++ b/samples/ActionBarCompat/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <dimen name="actionbar_compat_height">48dp</dimen>
+    <dimen name="actionbar_compat_button_width">48dp</dimen>
+    <dimen name="actionbar_compat_button_home_width">56dp</dimen>
+</resources>
diff --git a/samples/ActionBarCompat/res/values/ids.xml b/samples/ActionBarCompat/res/values/ids.xml
new file mode 100644
index 0000000..e0a4745
--- /dev/null
+++ b/samples/ActionBarCompat/res/values/ids.xml
@@ -0,0 +1,23 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <item type="id" name="actionbar_compat" />
+    <item type="id" name="actionbar_compat_title" />
+    <item type="id" name="actionbar_compat_item_refresh_progress" />
+    <item type="id" name="actionbar_compat_item_refresh" />
+    <item type="id" name="menu_refresh" />
+</resources>
diff --git a/samples/ActionBarCompat/res/values/strings.xml b/samples/ActionBarCompat/res/values/strings.xml
new file mode 100644
index 0000000..234aa78
--- /dev/null
+++ b/samples/ActionBarCompat/res/values/strings.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="app_name">Action Bar Demo</string>
+    <string name="alternate_title">An alternate title that is long</string>
+    <string name="toggle_title">Toggle title</string>
+
+    <string name="menu_refresh">Refresh</string>
+    <string name="menu_search">Search</string>
+    <string name="menu_share">Share</string>
+</resources>
diff --git a/samples/ActionBarCompat/res/values/styles.xml b/samples/ActionBarCompat/res/values/styles.xml
new file mode 100644
index 0000000..5d0c029
--- /dev/null
+++ b/samples/ActionBarCompat/res/values/styles.xml
@@ -0,0 +1,66 @@
+<!--
+  Copyright 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+
+    <style name="AppTheme" parent="android:style/Theme.Light">
+        <item name="android:windowTitleSize">@dimen/actionbar_compat_height</item>
+        <item name="android:windowTitleBackgroundStyle">@style/ActionBarCompat</item>
+        <item name="android:windowContentOverlay">@drawable/actionbar_shadow</item>
+
+        <!-- for programmatic instantiation -->
+        <item name="actionbarCompatTitleStyle">@style/ActionBarCompatTitle</item>
+        <item name="actionbarCompatItemStyle">@style/ActionBarCompatItem</item>
+        <item name="actionbarCompatItemHomeStyle">@style/ActionBarCompatHomeItem</item>
+        <item name="actionbarCompatProgressIndicatorStyle">@style/ActionBarCompatProgressIndicator</item>
+    </style>
+
+    <style name="ActionBarCompat">
+        <item name="android:background">#eee</item>
+    </style>
+
+    <style name="ActionBarCompatItemBase">
+        <!-- layout_width/height must be set in code -->
+        <item name="android:scaleType">center</item>
+        <item name="android:background">@drawable/actionbar_compat_item</item>
+    </style>
+
+    <style name="ActionBarCompatProgressIndicator" parent="android:style/Widget.ProgressBar.Large">
+        <item name="android:indeterminate">true</item>
+    </style>
+
+    <style name="ActionBarCompatTitleBase">
+        <item name="android:id">@id/actionbar_compat_title</item>
+        <!-- layout_width/height/weight must be set in code -->
+        <item name="android:gravity">center_vertical</item>
+        <item name="android:textSize">18sp</item>
+        <item name="android:paddingLeft">6dp</item>
+        <item name="android:paddingRight">6dp</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:ellipsize">marquee</item>
+    </style>
+
+    <style name="ActionBarCompatTitle" parent="style/ActionBarCompatTitleBase">
+        <item name="android:textColor">@color/actionbar_title_color</item>
+    </style>
+
+    <style name="ActionBarCompatItem" parent="style/ActionBarCompatItemBase">
+    </style>
+
+    <style name="ActionBarCompatHomeItem" parent="style/ActionBarCompatItemBase">
+    </style>
+
+</resources>
diff --git a/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarActivity.java b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarActivity.java
new file mode 100644
index 0000000..251e411
--- /dev/null
+++ b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarActivity.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuInflater;
+
+/**
+ * A base activity that defers common functionality across app activities to an {@link
+ * ActionBarHelper}.
+ *
+ * NOTE: dynamically marking menu items as invisible/visible is not currently supported.
+ *
+ * NOTE: this may used with the Android Compatibility Package by extending
+ * android.support.v4.app.FragmentActivity instead of {@link Activity}.
+ */
+public abstract class ActionBarActivity extends Activity {
+    final ActionBarHelper mActionBarHelper = ActionBarHelper.createInstance(this);
+
+    /**
+     * Returns the {@link ActionBarHelper} for this activity.
+     */
+    protected ActionBarHelper getActionBarHelper() {
+        return mActionBarHelper;
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    public MenuInflater getMenuInflater() {
+        return mActionBarHelper.getMenuInflater(super.getMenuInflater());
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mActionBarHelper.onCreate(savedInstanceState);
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    protected void onPostCreate(Bundle savedInstanceState) {
+        super.onPostCreate(savedInstanceState);
+        mActionBarHelper.onPostCreate(savedInstanceState);
+    }
+
+    /**
+     * Base action bar-aware implementation for
+     * {@link Activity#onCreateOptionsMenu(android.view.Menu)}.
+     *
+     * Note: marking menu items as invisible/visible is not currently supported.
+     */
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        boolean retValue = false;
+        retValue |= mActionBarHelper.onCreateOptionsMenu(menu);
+        retValue |= super.onCreateOptionsMenu(menu);
+        return retValue;
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    protected void onTitleChanged(CharSequence title, int color) {
+        mActionBarHelper.onTitleChanged(title, color);
+        super.onTitleChanged(title, color);
+    }
+}
diff --git a/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelper.java b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelper.java
new file mode 100644
index 0000000..075f993
--- /dev/null
+++ b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelper.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat;
+
+import android.app.Activity;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuInflater;
+
+/**
+ * An abstract class that handles some common action bar-related functionality in the app. This
+ * class provides functionality useful for both phones and tablets, and does not require any Android
+ * 3.0-specific features, although it uses them if available.
+ *
+ * Two implementations of this class are {@link ActionBarHelperBase} for a pre-Honeycomb version of
+ * the action bar, and {@link ActionBarHelperHoneycomb}, which uses the built-in ActionBar features
+ * in Android 3.0 and later.
+ */
+public abstract class ActionBarHelper {
+    protected Activity mActivity;
+
+    /**
+     * Factory method for creating {@link ActionBarHelper} objects for a
+     * given activity. Depending on which device the app is running, either a basic helper or
+     * Honeycomb-specific helper will be returned.
+     */
+    public static ActionBarHelper createInstance(Activity activity) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            return new ActionBarHelperICS(activity);
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            return new ActionBarHelperHoneycomb(activity);
+        } else {
+            return new ActionBarHelperBase(activity);
+        }
+    }
+
+    protected ActionBarHelper(Activity activity) {
+        mActivity = activity;
+    }
+
+    /**
+     * Action bar helper code to be run in {@link Activity#onCreate(android.os.Bundle)}.
+     */
+    public void onCreate(Bundle savedInstanceState) {
+    }
+
+    /**
+     * Action bar helper code to be run in {@link Activity#onPostCreate(android.os.Bundle)}.
+     */
+    public void onPostCreate(Bundle savedInstanceState) {
+    }
+
+    /**
+     * Action bar helper code to be run in {@link Activity#onCreateOptionsMenu(android.view.Menu)}.
+     *
+     * NOTE: Setting the visibility of menu items in <em>menu</em> is not currently supported.
+     */
+    public boolean onCreateOptionsMenu(Menu menu) {
+        return true;
+    }
+
+    /**
+     * Action bar helper code to be run in {@link Activity#onTitleChanged(CharSequence, int)}.
+     */
+    protected void onTitleChanged(CharSequence title, int color) {
+    }
+
+    /**
+     * Sets the indeterminate loading state of the item with ID {@link R.id.menu_refresh}.
+     * (where the item ID was menu_refresh).
+     */
+    public abstract void setRefreshActionItemState(boolean refreshing);
+
+    /**
+     * Returns a {@link MenuInflater} for use when inflating menus. The implementation of this
+     * method in {@link ActionBarHelperBase} returns a wrapped menu inflater that can read
+     * action bar metadata from a menu resource pre-Honeycomb.
+     */
+    public MenuInflater getMenuInflater(MenuInflater superMenuInflater) {
+        return superMenuInflater;
+    }
+}
diff --git a/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelperBase.java b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelperBase.java
new file mode 100644
index 0000000..f70b54a
--- /dev/null
+++ b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelperBase.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.view.InflateException;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A class that implements the action bar pattern for pre-Honeycomb devices.
+ */
+public class ActionBarHelperBase extends ActionBarHelper {
+    private static final String MENU_RES_NAMESPACE = "http://schemas.android.com/apk/res/android";
+    private static final String MENU_ATTR_ID = "id";
+    private static final String MENU_ATTR_SHOW_AS_ACTION = "showAsAction";
+
+    protected Set<Integer> mActionItemIds = new HashSet<Integer>();
+
+    protected ActionBarHelperBase(Activity activity) {
+        super(activity);
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        mActivity.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    public void onPostCreate(Bundle savedInstanceState) {
+        mActivity.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
+                R.layout.actionbar_compat);
+        setupActionBar();
+
+        SimpleMenu menu = new SimpleMenu(mActivity);
+        mActivity.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu);
+        mActivity.onPrepareOptionsMenu(menu);
+        for (int i = 0; i < menu.size(); i++) {
+            MenuItem item = menu.getItem(i);
+            if (mActionItemIds.contains(item.getItemId())) {
+                addActionItemCompatFromMenuItem(item);
+            }
+        }
+    }
+
+    /**
+     * Sets up the compatibility action bar with the given title.
+     */
+    private void setupActionBar() {
+        final ViewGroup actionBarCompat = getActionBarCompat();
+        if (actionBarCompat == null) {
+            return;
+        }
+
+        LinearLayout.LayoutParams springLayoutParams = new LinearLayout.LayoutParams(
+                0, ViewGroup.LayoutParams.FILL_PARENT);
+        springLayoutParams.weight = 1;
+
+        // Add Home button
+        SimpleMenu tempMenu = new SimpleMenu(mActivity);
+        SimpleMenuItem homeItem = new SimpleMenuItem(
+                tempMenu, android.R.id.home, 0, mActivity.getString(R.string.app_name));
+        homeItem.setIcon(R.drawable.ic_home);
+        addActionItemCompatFromMenuItem(homeItem);
+
+        // Add title text
+        TextView titleText = new TextView(mActivity, null, R.attr.actionbarCompatTitleStyle);
+        titleText.setLayoutParams(springLayoutParams);
+        titleText.setText(mActivity.getTitle());
+        actionBarCompat.addView(titleText);
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    public void setRefreshActionItemState(boolean refreshing) {
+        View refreshButton = mActivity.findViewById(R.id.actionbar_compat_item_refresh);
+        View refreshIndicator = mActivity.findViewById(
+                R.id.actionbar_compat_item_refresh_progress);
+
+        if (refreshButton != null) {
+            refreshButton.setVisibility(refreshing ? View.GONE : View.VISIBLE);
+        }
+        if (refreshIndicator != null) {
+            refreshIndicator.setVisibility(refreshing ? View.VISIBLE : View.GONE);
+        }
+    }
+
+    /**
+     * Action bar helper code to be run in {@link Activity#onCreateOptionsMenu(android.view.Menu)}.
+     *
+     * NOTE: This code will mark on-screen menu items as invisible.
+     */
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Hides on-screen action items from the options menu.
+        for (Integer id : mActionItemIds) {
+            menu.findItem(id).setVisible(false);
+        }
+        return true;
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    protected void onTitleChanged(CharSequence title, int color) {
+        TextView titleView = (TextView) mActivity.findViewById(R.id.actionbar_compat_title);
+        if (titleView != null) {
+            titleView.setText(title);
+        }
+    }
+
+    /**
+     * Returns a {@link android.view.MenuInflater} that can read action bar metadata on
+     * pre-Honeycomb devices.
+     */
+    public MenuInflater getMenuInflater(MenuInflater superMenuInflater) {
+        return new WrappedMenuInflater(mActivity, superMenuInflater);
+    }
+
+    /**
+     * Returns the {@link android.view.ViewGroup} for the action bar on phones (compatibility action
+     * bar). Can return null, and will return null on Honeycomb.
+     */
+    private ViewGroup getActionBarCompat() {
+        return (ViewGroup) mActivity.findViewById(R.id.actionbar_compat);
+    }
+
+    /**
+     * Adds an action button to the compatibility action bar, using menu information from a {@link
+     * android.view.MenuItem}. If the menu item ID is <code>menu_refresh</code>, the menu item's
+     * state can be changed to show a loading spinner using
+     * {@link com.example.android.actionbarcompat.ActionBarHelperBase#setRefreshActionItemState(boolean)}.
+     */
+    private View addActionItemCompatFromMenuItem(final MenuItem item) {
+        final int itemId = item.getItemId();
+
+        final ViewGroup actionBar = getActionBarCompat();
+        if (actionBar == null) {
+            return null;
+        }
+
+        // Create the button
+        ImageButton actionButton = new ImageButton(mActivity, null,
+                itemId == android.R.id.home
+                        ? R.attr.actionbarCompatItemHomeStyle
+                        : R.attr.actionbarCompatItemStyle);
+        actionButton.setLayoutParams(new ViewGroup.LayoutParams(
+                (int) mActivity.getResources().getDimension(
+                        itemId == android.R.id.home
+                                ? R.dimen.actionbar_compat_button_home_width
+                                : R.dimen.actionbar_compat_button_width),
+                ViewGroup.LayoutParams.FILL_PARENT));
+        if (itemId == R.id.menu_refresh) {
+            actionButton.setId(R.id.actionbar_compat_item_refresh);
+        }
+        actionButton.setImageDrawable(item.getIcon());
+        actionButton.setScaleType(ImageView.ScaleType.CENTER);
+        actionButton.setContentDescription(item.getTitle());
+        actionButton.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View view) {
+                mActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item);
+            }
+        });
+
+        actionBar.addView(actionButton);
+
+        if (item.getItemId() == R.id.menu_refresh) {
+            // Refresh buttons should be stateful, and allow for indeterminate progress indicators,
+            // so add those.
+            ProgressBar indicator = new ProgressBar(mActivity, null,
+                    R.attr.actionbarCompatProgressIndicatorStyle);
+
+            final int buttonWidth = mActivity.getResources().getDimensionPixelSize(
+                    R.dimen.actionbar_compat_button_width);
+            final int buttonHeight = mActivity.getResources().getDimensionPixelSize(
+                    R.dimen.actionbar_compat_height);
+            final int progressIndicatorWidth = buttonWidth / 2;
+
+            LinearLayout.LayoutParams indicatorLayoutParams = new LinearLayout.LayoutParams(
+                    progressIndicatorWidth, progressIndicatorWidth);
+            indicatorLayoutParams.setMargins(
+                    (buttonWidth - progressIndicatorWidth) / 2,
+                    (buttonHeight - progressIndicatorWidth) / 2,
+                    (buttonWidth - progressIndicatorWidth) / 2,
+                    0);
+            indicator.setLayoutParams(indicatorLayoutParams);
+            indicator.setVisibility(View.GONE);
+            indicator.setId(R.id.actionbar_compat_item_refresh_progress);
+            actionBar.addView(indicator);
+        }
+
+        return actionButton;
+    }
+
+    /**
+     * A {@link android.view.MenuInflater} that reads action bar metadata.
+     */
+    private class WrappedMenuInflater extends MenuInflater {
+        MenuInflater mInflater;
+
+        public WrappedMenuInflater(Context context, MenuInflater inflater) {
+            super(context);
+            mInflater = inflater;
+        }
+
+        @Override
+        public void inflate(int menuRes, Menu menu) {
+            loadActionBarMetadata(menuRes);
+            mInflater.inflate(menuRes, menu);
+        }
+
+        /**
+         * Loads action bar metadata from a menu resource, storing a list of menu item IDs that
+         * should be shown on-screen (i.e. those with showAsAction set to always or ifRoom).
+         * @param menuResId
+         */
+        private void loadActionBarMetadata(int menuResId) {
+            XmlResourceParser parser = null;
+            try {
+                parser = mActivity.getResources().getXml(menuResId);
+
+                int eventType = parser.getEventType();
+                int itemId;
+                int showAsAction;
+
+                boolean eof = false;
+                while (!eof) {
+                    switch (eventType) {
+                        case XmlPullParser.START_TAG:
+                            if (!parser.getName().equals("item")) {
+                                break;
+                            }
+
+                            itemId = parser.getAttributeResourceValue(MENU_RES_NAMESPACE,
+                                    MENU_ATTR_ID, 0);
+                            if (itemId == 0) {
+                                break;
+                            }
+
+                            showAsAction = parser.getAttributeIntValue(MENU_RES_NAMESPACE,
+                                    MENU_ATTR_SHOW_AS_ACTION, -1);
+                            if (showAsAction == MenuItem.SHOW_AS_ACTION_ALWAYS ||
+                                    showAsAction == MenuItem.SHOW_AS_ACTION_IF_ROOM) {
+                                mActionItemIds.add(itemId);
+                            }
+                            break;
+
+                        case XmlPullParser.END_DOCUMENT:
+                            eof = true;
+                            break;
+                    }
+
+                    eventType = parser.next();
+                }
+            } catch (XmlPullParserException e) {
+                throw new InflateException("Error inflating menu XML", e);
+            } catch (IOException e) {
+                throw new InflateException("Error inflating menu XML", e);
+            } finally {
+                if (parser != null) {
+                    parser.close();
+                }
+            }
+        }
+
+    }
+}
diff --git a/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelperHoneycomb.java b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelperHoneycomb.java
new file mode 100644
index 0000000..16fba69
--- /dev/null
+++ b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelperHoneycomb.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+/**
+ * An extension of {@link ActionBarHelper} that provides Android 3.0-specific functionality for
+ * Honeycomb tablets. It thus requires API level 11.
+ */
+public class ActionBarHelperHoneycomb extends ActionBarHelper {
+    private Menu mOptionsMenu;
+    private View mRefreshIndeterminateProgressView = null;
+
+    protected ActionBarHelperHoneycomb(Activity activity) {
+        super(activity);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        mOptionsMenu = menu;
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
+    public void setRefreshActionItemState(boolean refreshing) {
+        // On Honeycomb, we can set the state of the refresh button by giving it a custom
+        // action view.
+        if (mOptionsMenu == null) {
+            return;
+        }
+
+        final MenuItem refreshItem = mOptionsMenu.findItem(R.id.menu_refresh);
+        if (refreshItem != null) {
+            if (refreshing) {
+                if (mRefreshIndeterminateProgressView == null) {
+                    LayoutInflater inflater = (LayoutInflater)
+                            getActionBarThemedContext().getSystemService(
+                                    Context.LAYOUT_INFLATER_SERVICE);
+                    mRefreshIndeterminateProgressView = inflater.inflate(
+                            R.layout.actionbar_indeterminate_progress, null);
+                }
+
+                refreshItem.setActionView(mRefreshIndeterminateProgressView);
+            } else {
+                refreshItem.setActionView(null);
+            }
+        }
+    }
+
+    /**
+     * Returns a {@link Context} suitable for inflating layouts for the action bar. The
+     * implementation for this method in {@link ActionBarHelperICS} asks the action bar for a
+     * themed context.
+     */
+    protected Context getActionBarThemedContext() {
+        return mActivity;
+    }
+}
diff --git a/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelperICS.java b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelperICS.java
new file mode 100644
index 0000000..d2239db
--- /dev/null
+++ b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/ActionBarHelperICS.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.Menu;
+import android.view.MenuItem;
+
+/**
+ * An extension of {@link com.example.android.actionbarcompat.ActionBarHelper} that provides Android
+ * 4.0-specific functionality for IceCreamSandwich devices. It thus requires API level 14.
+ */
+public class ActionBarHelperICS extends ActionBarHelperHoneycomb {
+    protected ActionBarHelperICS(Activity activity) {
+        super(activity);
+    }
+
+    @Override
+    protected Context getActionBarThemedContext() {
+        return mActivity.getActionBar().getThemedContext();
+    }
+}
diff --git a/samples/ActionBarCompat/src/com/example/android/actionbarcompat/MainActivity.java b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/MainActivity.java
new file mode 100644
index 0000000..facf1ae
--- /dev/null
+++ b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/MainActivity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat;
+
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Toast;
+
+public class MainActivity extends ActionBarActivity {
+    private boolean mAlternateTitle = false;
+
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        findViewById(R.id.toggle_title).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                if (mAlternateTitle) {
+                    setTitle(R.string.app_name);
+                } else {
+                    setTitle(R.string.alternate_title);
+                }
+                mAlternateTitle = !mAlternateTitle;
+            }
+        });
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater menuInflater = getMenuInflater();
+        menuInflater.inflate(R.menu.main, menu);
+
+        // Calling super after populating the menu is necessary here to ensure that the
+        // action bar helpers have a chance to handle this event.
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                Toast.makeText(this, "Tapped home", Toast.LENGTH_SHORT).show();
+                break;
+
+            case R.id.menu_refresh:
+                Toast.makeText(this, "Fake refreshing...", Toast.LENGTH_SHORT).show();
+                getActionBarHelper().setRefreshActionItemState(true);
+                getWindow().getDecorView().postDelayed(
+                        new Runnable() {
+                            @Override
+                            public void run() {
+                                getActionBarHelper().setRefreshActionItemState(false);
+                            }
+                        }, 1000);
+                break;
+
+            case R.id.menu_search:
+                Toast.makeText(this, "Tapped search", Toast.LENGTH_SHORT).show();
+                break;
+
+            case R.id.menu_share:
+                Toast.makeText(this, "Tapped share", Toast.LENGTH_SHORT).show();
+                break;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+}
diff --git a/samples/ActionBarCompat/src/com/example/android/actionbarcompat/SimpleMenu.java b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/SimpleMenu.java
new file mode 100644
index 0000000..8b694d0
--- /dev/null
+++ b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/SimpleMenu.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+
+import java.util.ArrayList;
+
+/**
+ * A <em>really</em> dumb implementation of the {@link android.view.Menu} interface, that's only
+ * useful for our actionbar-compat purposes. See
+ * <code>com.android.internal.view.menu.MenuBuilder</code> in AOSP for a more complete
+ * implementation.
+ */
+public class SimpleMenu implements Menu {
+
+    private Context mContext;
+    private Resources mResources;
+
+    private ArrayList<SimpleMenuItem> mItems;
+
+    public SimpleMenu(Context context) {
+        mContext = context;
+        mResources = context.getResources();
+        mItems = new ArrayList<SimpleMenuItem>();
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public Resources getResources() {
+        return mResources;
+    }
+
+    public MenuItem add(CharSequence title) {
+        return addInternal(0, 0, title);
+    }
+
+    public MenuItem add(int titleRes) {
+        return addInternal(0, 0, mResources.getString(titleRes));
+    }
+
+    public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
+        return addInternal(itemId, order, title);
+    }
+
+    public MenuItem add(int groupId, int itemId, int order, int titleRes) {
+        return addInternal(itemId, order, mResources.getString(titleRes));
+    }
+
+    /**
+     * Adds an item to the menu.  The other add methods funnel to this.
+     */
+    private MenuItem addInternal(int itemId, int order, CharSequence title) {
+        final SimpleMenuItem item = new SimpleMenuItem(this, itemId, order, title);
+        mItems.add(findInsertIndex(mItems, order), item);
+        return item;
+    }
+
+    private static int findInsertIndex(ArrayList<? extends MenuItem> items, int order) {
+        for (int i = items.size() - 1; i >= 0; i--) {
+            MenuItem item = items.get(i);
+            if (item.getOrder() <= order) {
+                return i + 1;
+            }
+        }
+
+        return 0;
+    }
+
+    public int findItemIndex(int id) {
+        final int size = size();
+
+        for (int i = 0; i < size; i++) {
+            SimpleMenuItem item = mItems.get(i);
+            if (item.getItemId() == id) {
+                return i;
+            }
+        }
+
+        return -1;
+    }
+
+    public void removeItem(int itemId) {
+        removeItemAtInt(findItemIndex(itemId));
+    }
+
+    private void removeItemAtInt(int index) {
+        if ((index < 0) || (index >= mItems.size())) {
+            return;
+        }
+        mItems.remove(index);
+    }
+
+    public void clear() {
+        mItems.clear();
+    }
+
+    public MenuItem findItem(int id) {
+        final int size = size();
+        for (int i = 0; i < size; i++) {
+            SimpleMenuItem item = mItems.get(i);
+            if (item.getItemId() == id) {
+                return item;
+            }
+        }
+
+        return null;
+    }
+
+    public int size() {
+        return mItems.size();
+    }
+
+    public MenuItem getItem(int index) {
+        return mItems.get(index);
+    }
+
+    // Unsupported operations.
+
+    public SubMenu addSubMenu(CharSequence charSequence) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public SubMenu addSubMenu(int titleRes) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public int addIntentOptions(int i, int i1, int i2, ComponentName componentName,
+            Intent[] intents, Intent intent, int i3, MenuItem[] menuItems) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public void removeGroup(int i) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public void setGroupCheckable(int i, boolean b, boolean b1) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public void setGroupVisible(int i, boolean b) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public void setGroupEnabled(int i, boolean b) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public boolean hasVisibleItems() {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public void close() {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public boolean performShortcut(int i, KeyEvent keyEvent, int i1) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public boolean isShortcutKey(int i, KeyEvent keyEvent) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public boolean performIdentifierAction(int i, int i1) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+
+    public void setQwertyMode(boolean b) {
+        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
+    }
+}
diff --git a/samples/ActionBarCompat/src/com/example/android/actionbarcompat/SimpleMenuItem.java b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/SimpleMenuItem.java
new file mode 100644
index 0000000..425ba72
--- /dev/null
+++ b/samples/ActionBarCompat/src/com/example/android/actionbarcompat/SimpleMenuItem.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.actionbarcompat;
+
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.view.ActionProvider;
+import android.view.ContextMenu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+
+/**
+ * A <em>really</em> dumb implementation of the {@link android.view.MenuItem} interface, that's only
+ * useful for our actionbar-compat purposes. See
+ * <code>com.android.internal.view.menu.MenuItemImpl</code> in AOSP for a more complete
+ * implementation.
+ */
+public class SimpleMenuItem implements MenuItem {
+
+    private SimpleMenu mMenu;
+
+    private final int mId;
+    private final int mOrder;
+    private CharSequence mTitle;
+    private CharSequence mTitleCondensed;
+    private Drawable mIconDrawable;
+    private int mIconResId = 0;
+    private boolean mEnabled = true;
+
+    public SimpleMenuItem(SimpleMenu menu, int id, int order, CharSequence title) {
+        mMenu = menu;
+        mId = id;
+        mOrder = order;
+        mTitle = title;
+    }
+
+    public int getItemId() {
+        return mId;
+    }
+
+    public int getOrder() {
+        return mOrder;
+    }
+
+    public MenuItem setTitle(CharSequence title) {
+        mTitle = title;
+        return this;
+    }
+
+    public MenuItem setTitle(int titleRes) {
+        return setTitle(mMenu.getContext().getString(titleRes));
+    }
+
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    public MenuItem setTitleCondensed(CharSequence title) {
+        mTitleCondensed = title;
+        return this;
+    }
+
+    public CharSequence getTitleCondensed() {
+        return mTitleCondensed != null ? mTitleCondensed : mTitle;
+    }
+
+    public MenuItem setIcon(Drawable icon) {
+        mIconResId = 0;
+        mIconDrawable = icon;
+        return this;
+    }
+
+    public MenuItem setIcon(int iconResId) {
+        mIconDrawable = null;
+        mIconResId = iconResId;
+        return this;
+    }
+
+    public Drawable getIcon() {
+        if (mIconDrawable != null) {
+            return mIconDrawable;
+        }
+
+        if (mIconResId != 0) {
+            return mMenu.getResources().getDrawable(mIconResId);
+        }
+
+        return null;
+    }
+
+    public MenuItem setEnabled(boolean enabled) {
+        mEnabled = enabled;
+        return this;
+    }
+
+    public boolean isEnabled() {
+        return mEnabled;
+    }
+
+    // No-op operations. We use no-ops to allow inflation from menu XML.
+
+    public int getGroupId() {
+        // Noop
+        return 0;
+    }
+
+    public View getActionView() {
+        // Noop
+        return null;
+    }
+
+    public MenuItem setActionProvider(ActionProvider actionProvider) {
+        // Noop
+        return this;
+    }
+
+    public ActionProvider getActionProvider() {
+        // Noop
+        return null;
+    }
+
+    public boolean expandActionView() {
+        // Noop
+        return false;
+    }
+
+    public boolean collapseActionView() {
+        // Noop
+        return false;
+    }
+
+    public boolean isActionViewExpanded() {
+        // Noop
+        return false;
+    }
+
+    @Override
+    public MenuItem setOnActionExpandListener(OnActionExpandListener onActionExpandListener) {
+        // Noop
+        return this;
+    }
+
+    public MenuItem setIntent(Intent intent) {
+        // Noop
+        return this;
+    }
+
+    public Intent getIntent() {
+        // Noop
+        return null;
+    }
+
+    public MenuItem setShortcut(char c, char c1) {
+        // Noop
+        return this;
+    }
+
+    public MenuItem setNumericShortcut(char c) {
+        // Noop
+        return this;
+    }
+
+    public char getNumericShortcut() {
+        // Noop
+        return 0;
+    }
+
+    public MenuItem setAlphabeticShortcut(char c) {
+        // Noop
+        return this;
+    }
+
+    public char getAlphabeticShortcut() {
+        // Noop
+        return 0;
+    }
+
+    public MenuItem setCheckable(boolean b) {
+        // Noop
+        return this;
+    }
+
+    public boolean isCheckable() {
+        // Noop
+        return false;
+    }
+
+    public MenuItem setChecked(boolean b) {
+        // Noop
+        return this;
+    }
+
+    public boolean isChecked() {
+        // Noop
+        return false;
+    }
+
+    public MenuItem setVisible(boolean b) {
+        // Noop
+        return this;
+    }
+
+    public boolean isVisible() {
+        // Noop
+        return true;
+    }
+
+    public boolean hasSubMenu() {
+        // Noop
+        return false;
+    }
+
+    public SubMenu getSubMenu() {
+        // Noop
+        return null;
+    }
+
+    public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {
+        // Noop
+        return this;
+    }
+
+    public ContextMenu.ContextMenuInfo getMenuInfo() {
+        // Noop
+        return null;
+    }
+
+    public void setShowAsAction(int i) {
+        // Noop
+    }
+
+    public MenuItem setShowAsActionFlags(int i) {
+        // Noop
+        return null;
+    }
+
+    public MenuItem setActionView(View view) {
+        // Noop
+        return this;
+    }
+
+    public MenuItem setActionView(int i) {
+        // Noop
+        return this;
+    }
+}
diff --git a/samples/AndroidBeam/AndroidManifest.xml b/samples/AndroidBeam/AndroidManifest.xml
new file mode 100644
index 0000000..e01eb2d
--- /dev/null
+++ b/samples/AndroidBeam/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.example.android.beam"
+        android:versionCode="1"
+        android:versionName="1.0">
+    <uses-permission android:name="android.permission.NFC" />
+    <uses-sdk android:minSdkVersion="14" />
+    <uses-feature android:name="android.hardware.nfc" />
+    <application android:icon="@drawable/icon" android:label="@string/app_name">
+        <activity android:name="com.example.android.beam.Beam"
+                android:label="@string/app_name"
+                android:launchMode="singleTop">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="application/com.example.android.beam" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/samples/AndroidBeam/_index.html b/samples/AndroidBeam/_index.html
new file mode 100755
index 0000000..ad4e71a
--- /dev/null
+++ b/samples/AndroidBeam/_index.html
@@ -0,0 +1,3 @@
+<p>The Beam application demonstrates how to use the Android Beam feature introduced in API level 14. This
+application beams a simple message from one device to another when they are in close enough proximity. This
+application must be installed on two devices that have NFC capabilities, running Android 4.0 or later.</p>
diff --git a/samples/AndroidBeam/res/drawable-hdpi/icon.png b/samples/AndroidBeam/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/samples/AndroidBeam/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-ldpi/icon.png b/samples/AndroidBeam/res/drawable-ldpi/icon.png
similarity index 100%
rename from samples/WeatherListWidget/res/drawable-ldpi/icon.png
rename to samples/AndroidBeam/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/samples/AndroidBeam/res/drawable-mdpi/icon.png b/samples/AndroidBeam/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/samples/AndroidBeam/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/samples/AndroidBeam/res/layout/main.xml b/samples/AndroidBeam/res/layout/main.xml
new file mode 100644
index 0000000..dce6169
--- /dev/null
+++ b/samples/AndroidBeam/res/layout/main.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/textView"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    />
diff --git a/samples/AndroidBeam/res/values/strings.xml b/samples/AndroidBeam/res/values/strings.xml
new file mode 100644
index 0000000..ff4492f
--- /dev/null
+++ b/samples/AndroidBeam/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">Beam</string>
+</resources>
diff --git a/samples/AndroidBeam/src/com/example/android/beam/Beam.java b/samples/AndroidBeam/src/com/example/android/beam/Beam.java
new file mode 100644
index 0000000..17ec325
--- /dev/null
+++ b/samples/AndroidBeam/src/com/example/android/beam/Beam.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.beam;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+import android.nfc.NfcAdapter.CreateNdefMessageCallback;
+import android.nfc.NfcEvent;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.widget.TextView;
+import android.widget.Toast;
+import java.nio.charset.Charset;
+
+
+public class Beam extends Activity implements CreateNdefMessageCallback {
+    NfcAdapter mNfcAdapter;
+    TextView textView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+        TextView textView = (TextView) findViewById(R.id.textView);
+        // Check for available NFC Adapter
+        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
+        if (mNfcAdapter == null) {
+            Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
+            finish();
+            return;
+        }
+        // Register callback
+        mNfcAdapter.setNdefPushMessageCallback(this, this);
+    }
+
+    @Override
+    public NdefMessage createNdefMessage(NfcEvent event) {
+        String text = ("Beam me up, Android!\n\n" +
+                "Beam Time: " + System.currentTimeMillis());
+        NdefMessage msg = new NdefMessage(
+                new NdefRecord[] { createMimeRecord(
+                        "application/com.example.android.beam", text.getBytes())
+         /**
+          * The Android Application Record (AAR) is commented out. When a device
+          * receives a push with an AAR in it, the application specified in the AAR
+          * is guaranteed to run. The AAR overrides the tag dispatch system.
+          * You can add it back in to guarantee that this
+          * activity starts when receiving a beamed message. For now, this code
+          * uses the tag dispatch system.
+          */
+          //,NdefRecord.createApplicationRecord("com.example.android.beam")
+        });
+        return msg;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        // Check to see that the Activity started due to an Android Beam
+        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
+            processIntent(getIntent());
+        }
+    }
+
+    @Override
+    public void onNewIntent(Intent intent) {
+        // onResume gets called after this to handle the intent
+        setIntent(intent);
+    }
+
+    /**
+     * Parses the NDEF Message from the intent and prints to the TextView
+     */
+    void processIntent(Intent intent) {
+        textView = (TextView) findViewById(R.id.textView);
+        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
+                NfcAdapter.EXTRA_NDEF_MESSAGES);
+        // only one message sent during the beam
+        NdefMessage msg = (NdefMessage) rawMsgs[0];
+        // record 0 contains the MIME type, record 1 is the AAR, if present
+        textView.setText(new String(msg.getRecords()[0].getPayload()));
+    }
+
+    /**
+     * Creates a custom MIME type encapsulated in an NDEF record
+     *
+     * @param mimeType
+     */
+    public NdefRecord createMimeRecord(String mimeType, byte[] payload) {
+        byte[] mimeBytes = mimeType.getBytes(Charset.forName("US-ASCII"));
+        NdefRecord mimeRecord = new NdefRecord(
+                NdefRecord.TNF_MIME_MEDIA, mimeBytes, new byte[0], payload);
+        return mimeRecord;
+    }
+}
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index 39293e1..4a4a7c3 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -1433,6 +1433,20 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".view.GridLayout0" android:label="Views/Layouts/GridLayout/0. Simple Form (Java)">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.GridLayout1" android:label="Views/Layouts/GridLayout/1. Simple Form (XML)">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".view.Baseline1" android:label="Views/Layouts/Baseline/1. Top">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/samples/ApiDemos/res/layout/grid_layout_1.xml b/samples/ApiDemos/res/layout/grid_layout_1.xml
new file mode 100644
index 0000000..0e53613
--- /dev/null
+++ b/samples/ApiDemos/res/layout/grid_layout_1.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<GridLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+
+        android:useDefaultMargins="true"
+        android:alignmentMode="alignBounds"
+        android:rowOrderPreserved="false"
+
+        android:columnCount="4"
+        >
+
+    <TextView
+            android:text="Email setup"
+            android:textSize="32dip"
+
+            android:layout_columnSpan="4"
+            android:layout_gravity="center_horizontal"
+            />
+
+    <TextView
+            android:text="You can configure email in just a few steps:"
+            android:textSize="16dip"
+
+            android:layout_columnSpan="4"
+            android:layout_gravity="left"
+            />
+
+    <TextView
+            android:text="Email address:"
+
+            android:layout_gravity="right"
+            />
+
+    <EditText
+            android:ems="10"
+            />
+
+    <TextView
+            android:text="Password:"
+
+            android:layout_column="0"
+            android:layout_gravity="right"
+            />
+
+    <EditText
+            android:ems="8"
+            />
+
+    <Space
+            android:layout_row="2"
+            android:layout_rowSpan="3"
+            android:layout_column="2"
+            android:layout_gravity="fill"
+            />
+
+    <Button
+            android:text="Manual setup"
+
+            android:layout_row="5"
+            android:layout_column="3"
+            />
+
+    <Button
+            android:text="Next"
+
+            android:layout_column="3"
+            android:layout_gravity="fill_horizontal"
+            />
+</GridLayout>
diff --git a/samples/ApiDemos/res/layout/layout_animations.xml b/samples/ApiDemos/res/layout/layout_animations.xml
index 68f0e0e..ce179c4 100644
--- a/samples/ApiDemos/res/layout/layout_animations.xml
+++ b/samples/ApiDemos/res/layout/layout_animations.xml
@@ -40,34 +40,40 @@
     <LinearLayout
         android:orientation="horizontal"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         >
         <CheckBox
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:checked="true"
-            android:text="Appearing Animation"
+            android:text="In"
             android:id="@+id/appearingCB"
             />
         <CheckBox
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:checked="true"
-            android:text="Disappearing Animation"
+            android:text="Out"
             android:id="@+id/disappearingCB"
             />
+    </LinearLayout>
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        >
         <CheckBox
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:checked="true"
-            android:text="Changing/Appearing Animation"
+            android:text="Changing-In"
             android:id="@+id/changingAppearingCB"
             />
         <CheckBox
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:checked="true"
-            android:text="Changing/Disappearing Animation"
+            android:text="Changing-Out"
             android:id="@+id/changingDisappearingCB"
             />
     </LinearLayout>
diff --git a/samples/ApiDemos/res/layout/layout_animations_by_default.xml b/samples/ApiDemos/res/layout/layout_animations_by_default.xml
index a5062bb..6236088 100644
--- a/samples/ApiDemos/res/layout/layout_animations_by_default.xml
+++ b/samples/ApiDemos/res/layout/layout_animations_by_default.xml
@@ -24,18 +24,11 @@
         android:text="Add Button"
         android:id="@+id/addNewButton"
         />
-    <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:id="@+id/horizontalContainer"
-        android:animateLayoutChanges="true"
-        />
-    <LinearLayout
-        android:orientation="vertical"
+    <GridLayout
+        android:columnCount="4"
         android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:id="@+id/verticalContainer"
+        android:layout_height="wrap_content"
+        android:id="@+id/gridContainer"
         android:animateLayoutChanges="true"
         />
 </LinearLayout>
diff --git a/samples/ApiDemos/res/layout/layout_animations_hideshow.xml b/samples/ApiDemos/res/layout/layout_animations_hideshow.xml
index 4215ac1..49c2047 100644
--- a/samples/ApiDemos/res/layout/layout_animations_hideshow.xml
+++ b/samples/ApiDemos/res/layout/layout_animations_hideshow.xml
@@ -30,6 +30,12 @@
             android:text="Show Buttons"
             android:id="@+id/addNewButton"
             />
+    </LinearLayout>
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        >
         <CheckBox
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/samples/SampleSyncAdapter/res/values/styles.xml b/samples/ApiDemos/res/values-v14/bools.xml
similarity index 64%
rename from samples/SampleSyncAdapter/res/values/styles.xml
rename to samples/ApiDemos/res/values-v14/bools.xml
index 074613e..92aa94a 100644
--- a/samples/SampleSyncAdapter/res/values/styles.xml
+++ b/samples/ApiDemos/res/values-v14/bools.xml
@@ -15,13 +15,6 @@
 -->
 
 <resources>
-    <!--
-        These styles will only be used in Honeycomb and later because
-        Android doesn't support third-party contact editing in pre-
-        Honeycomb versions.
-    -->
-    <color name="EditPanelBackgroundColor">#ffffff</color>
-    <color name="EditPanelBorderColor">#cccccc</color>
-    <style name="ContactEditTheme" parent="android:Theme.Holo.Light">
-    </style>
+    <!-- True if running under IceCreamSandwich or later. -->
+    <bool name="atLeastIceCreamSandwich">true</bool>
 </resources>
diff --git a/samples/ApiDemos/res/values/bools.xml b/samples/ApiDemos/res/values/bools.xml
index 5d2eaa0..bc48079 100644
--- a/samples/ApiDemos/res/values/bools.xml
+++ b/samples/ApiDemos/res/values/bools.xml
@@ -27,6 +27,6 @@
     <!-- This resource is true if running under at least IceCreamSandwich
          API level.  The default value is false; an alternative value
          for IceCreamSandwich is true. -->
-    <bool name="atLeastIceCreamSandwich">true</bool>
+    <bool name="atLeastIceCreamSandwich">false</bool>
 
 </resources>
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimations.java b/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimations.java
index 65ad782..a2ff23c 100644
--- a/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimations.java
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimations.java
@@ -20,7 +20,6 @@
 // class is in a sub-package.
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
-import android.widget.LinearLayout;
 import com.example.android.apis.R;
 
 import android.animation.AnimatorListenerAdapter;
@@ -59,8 +58,8 @@
 
         container = new FixedGridLayout(this);
         container.setClipChildren(false);
-        ((FixedGridLayout)container).setCellHeight(50);
-        ((FixedGridLayout)container).setCellWidth(200);
+        ((FixedGridLayout)container).setCellHeight(90);
+        ((FixedGridLayout)container).setCellWidth(100);
         final LayoutTransition transitioner = new LayoutTransition();
         container.setLayoutTransition(transitioner);
         defaultAppearingAnim = transitioner.getAnimator(LayoutTransition.APPEARING);
@@ -83,7 +82,7 @@
         addButton.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
                 Button newButton = new Button(LayoutAnimations.this);
-                newButton.setText("Click to Delete " + (numButtons++));
+                newButton.setText(String.valueOf(numButtons++));
                 newButton.setOnClickListener(new View.OnClickListener() {
                     public void onClick(View v) {
                         container.removeView(v);
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsByDefault.java b/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsByDefault.java
index 67b9b51..8898b55 100644
--- a/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsByDefault.java
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsByDefault.java
@@ -21,11 +21,11 @@
 import com.example.android.apis.R;
 
 import android.view.View;
-import android.view.ViewGroup;
 
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.Button;
+import android.widget.GridLayout;
 
 /**
  * This application demonstrates how to use the animateLayoutChanges tag in XML to automate
@@ -35,36 +35,25 @@
 
     private int numButtons = 1;
 
-    /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState) {
 
         super.onCreate(savedInstanceState);
         setContentView(R.layout.layout_animations_by_default);
 
-        final ViewGroup horizontalContainer = (ViewGroup) findViewById(R.id.horizontalContainer);
-        final ViewGroup verticalContainer = (ViewGroup) findViewById(R.id.verticalContainer);
+        final GridLayout gridContainer = (GridLayout) findViewById(R.id.gridContainer);
 
         Button addButton = (Button) findViewById(R.id.addNewButton);
         addButton.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
                 Button newButton = new Button(LayoutAnimationsByDefault.this);
-                newButton.setText("Click To Remove " + (numButtons++));
+                newButton.setText(String.valueOf(numButtons++));
                 newButton.setOnClickListener(new View.OnClickListener() {
                     public void onClick(View v) {
-                        horizontalContainer.removeView(v);
+                        gridContainer.removeView(v);
                     }
                 });
-                horizontalContainer.addView(newButton, Math.min(1, horizontalContainer.getChildCount()));
-
-                newButton = new Button(LayoutAnimationsByDefault.this);
-                newButton.setText("Click To Remove " + (numButtons++));
-                newButton.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        verticalContainer.removeView(v);
-                    }
-                });
-                verticalContainer.addView(newButton, Math.min(1, verticalContainer.getChildCount()));
+                gridContainer.addView(newButton, Math.min(1, gridContainer.getChildCount()));
             }
         });
     }
diff --git a/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsHideShow.java b/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsHideShow.java
index 1a5d9c0..ac0609e 100644
--- a/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsHideShow.java
+++ b/samples/ApiDemos/src/com/example/android/apis/animation/LayoutAnimationsHideShow.java
@@ -60,9 +60,9 @@
 
         // Add a slew of buttons to the container. We won't add any more buttons at runtime, but
         // will just show/hide the buttons we've already created
-        for (int i = 0; i < 6; ++i) {
+        for (int i = 0; i < 4; ++i) {
             Button newButton = new Button(this);
-            newButton.setText("Click to Hide " + i);
+            newButton.setText(String.valueOf(i));
             container.addView(newButton);
             newButton.setOnClickListener(new View.OnClickListener() {
                 public void onClick(View v) {
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/GridLayout0.java b/samples/ApiDemos/src/com/example/android/apis/view/GridLayout0.java
new file mode 100644
index 0000000..70de1ac
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/GridLayout0.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.apis.view;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+
+import android.widget.*;
+
+import static android.text.InputType.*;
+import static android.widget.GridLayout.*;
+
+/**
+ * A simple form, showing use of the GridLayout API.
+ */
+public class GridLayout0 extends Activity {
+
+    public static View create(Context context) {
+        GridLayout p = new GridLayout(context);
+        p.setUseDefaultMargins(true);
+        p.setAlignmentMode(ALIGN_BOUNDS);
+        p.setRowOrderPreserved(false);
+
+        Spec row1 = spec(0);
+        Spec row2 = spec(1);
+        Spec row3 = spec(2, BASELINE);
+        Spec row4 = spec(3, BASELINE);
+        Spec row5 = spec(2, 3, FILL); // allow the last two rows to overlap the middle two
+        Spec row6 = spec(5);
+        Spec row7 = spec(6);
+
+        Spec col1a = spec(0, 4, CENTER);
+        Spec col1b = spec(0, 4, LEFT);
+        Spec col1c = spec(0, RIGHT);
+        Spec col2 = spec(1, LEFT);
+        Spec col3 = spec(2, FILL);
+        Spec col4a = spec(3);
+        Spec col4b = spec(3, FILL);
+
+        {
+            TextView c = new TextView(context);
+            c.setTextSize(32);
+            c.setText("Email setup");
+            p.addView(c, new LayoutParams(row1, col1a));
+        }
+        {
+            TextView c = new TextView(context);
+            c.setTextSize(16);
+            c.setText("You can configure email in just a few steps:");
+            p.addView(c, new LayoutParams(row2, col1b));
+        }
+        {
+            TextView c = new TextView(context);
+            c.setText("Email address:");
+            p.addView(c, new LayoutParams(row3, col1c));
+        }
+        {
+            EditText c = new EditText(context);
+            c.setEms(10);
+            c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+            p.addView(c, new LayoutParams(row3, col2));
+        }
+        {
+            TextView c = new TextView(context);
+            c.setText("Password:");
+            p.addView(c, new LayoutParams(row4, col1c));
+        }
+        {
+            TextView c = new EditText(context);
+            c.setEms(8);
+            c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
+            p.addView(c, new LayoutParams(row4, col2));
+        }
+        {
+            Space c = new Space(context);
+            p.addView(c, new LayoutParams(row5, col3));
+        }
+        {
+            Button c = new Button(context);
+            c.setText("Manual setup");
+            p.addView(c, new LayoutParams(row6, col4a));
+        }
+        {
+            Button c = new Button(context);
+            c.setText("Next");
+            p.addView(c, new LayoutParams(row7, col4b));
+        }
+
+        return p;
+    }
+
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(create(this));
+    }
+
+}
\ No newline at end of file
diff --git a/samples/HoneycombGallery/src/com/example/android/hcgallery/CameraSample.java b/samples/ApiDemos/src/com/example/android/apis/view/GridLayout1.java
similarity index 75%
copy from samples/HoneycombGallery/src/com/example/android/hcgallery/CameraSample.java
copy to samples/ApiDemos/src/com/example/android/apis/view/GridLayout1.java
index 2243858..f4318e4 100644
--- a/samples/HoneycombGallery/src/com/example/android/hcgallery/CameraSample.java
+++ b/samples/ApiDemos/src/com/example/android/apis/view/GridLayout1.java
@@ -14,19 +14,19 @@
  * limitations under the License.
  */
 
-package com.example.android.hcgallery;
+package com.example.android.apis.view;
+
+import com.example.android.apis.R;
 
 import android.app.Activity;
 import android.os.Bundle;
 
-public class CameraSample extends Activity {
-
-    @Override
+/**
+ * A simple form, showing use of the GridLayout API from XML.
+ */
+public class GridLayout1 extends Activity {
     protected void onCreate(Bundle savedInstanceState) {
-        int themeId = this.getIntent().getExtras().getInt("theme");
-        this.setTheme(themeId);
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.camera_sample);
+        setContentView(R.layout.grid_layout_1);
     }
-
 }
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/LabelView.java b/samples/ApiDemos/src/com/example/android/apis/view/LabelView.java
index b98a5b5..b0a1f96 100644
--- a/samples/ApiDemos/src/com/example/android/apis/view/LabelView.java
+++ b/samples/ApiDemos/src/com/example/android/apis/view/LabelView.java
@@ -84,7 +84,8 @@
     private final void initLabelView() {
         mTextPaint = new Paint();
         mTextPaint.setAntiAlias(true);
-        mTextPaint.setTextSize(16);
+        // Must manually scale the desired text size to match screen density
+        mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
         mTextPaint.setColor(0xFF000000);
         setPadding(3, 3, 3, 3);
     }
@@ -104,6 +105,7 @@
      * @param size Font size
      */
     public void setTextSize(int size) {
+        // This text size has been pre-scaled by the getDimensionPixelOffset method
         mTextPaint.setTextSize(size);
         requestLayout();
         invalidate();
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/OverscanActivity.java b/samples/ApiDemos/src/com/example/android/apis/view/OverscanActivity.java
index 3ee63e5..464b601 100644
--- a/samples/ApiDemos/src/com/example/android/apis/view/OverscanActivity.java
+++ b/samples/ApiDemos/src/com/example/android/apis/view/OverscanActivity.java
@@ -99,9 +99,8 @@
     }
     private class OverscanState implements State {
         public void apply() {
-            display("FULLSCREEN + LOW_PROFILE + HIDE_NAVIGATION");
-            mImage.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
-                                       | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+            display("FULLSCREEN + HIDE_NAVIGATION");
+            mImage.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
         }
         public State next() {
             return new NormalState();
diff --git a/samples/BrowserPlugin/jni/RenderingThread.cpp b/samples/BrowserPlugin/jni/RenderingThread.cpp
index 91ffb4a..1307e90 100644
--- a/samples/BrowserPlugin/jni/RenderingThread.cpp
+++ b/samples/BrowserPlugin/jni/RenderingThread.cpp
@@ -43,9 +43,14 @@
 }
 
 android::status_t RenderingThread::readyToRun() {
+    gLogI.log(kError_ANPLogType, "thread %p acquiring native window...", this);
     while (m_ANW == NULL) {
         m_ANW = gNativeWindowI.acquireNativeWindow(m_npp);
+        if (!m_ANW)
+            gLogI.log(kError_ANPLogType, "thread %p acquire native window FAILED!", this);
+
     }
+    gLogI.log(kError_ANPLogType, "thread %p acquired native window successfully!", this);
 
 #if (!USE_SOFTWARE_RENDERING)
     m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@@ -165,6 +170,8 @@
                                          const SkBitmap& bitmap)
 {
 #if USE_SOFTWARE_RENDERING
+    if (bitmap.height() == 0 || bitmap.width() == 0)
+        return;
 
     //STEP 1: lock the ANW, getting a buffer
     ANativeWindow_Buffer buffer;
diff --git a/samples/BrowserPlugin/jni/animation/AnimationThread.cpp b/samples/BrowserPlugin/jni/animation/AnimationThread.cpp
index 1388fe3..2729a53 100644
--- a/samples/BrowserPlugin/jni/animation/AnimationThread.cpp
+++ b/samples/BrowserPlugin/jni/animation/AnimationThread.cpp
@@ -45,7 +45,7 @@
     m_paint = new SkPaint;
     m_paint->setAntiAlias(true);
 
-    m_bitmap = constructBitmap(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    m_bitmap = constructBitmap(0, 0);
     m_canvas = new SkCanvas(*m_bitmap);
 
     m_startExecutionTime = 0;
@@ -95,11 +95,6 @@
     int width, height;
     getDimensions(width, height);
 
-    if (width <= 0)
-        width = DEFAULT_WIDTH;
-    if (height <= 0)
-        height = DEFAULT_HEIGHT;
-
     if (m_bitmap->width() != width || m_bitmap->height() != height) {
         delete m_canvas;
         delete m_bitmap;
diff --git a/samples/BrowserPlugin/jni/animation/AnimationThread.h b/samples/BrowserPlugin/jni/animation/AnimationThread.h
index e95ecce..8222a7e 100644
--- a/samples/BrowserPlugin/jni/animation/AnimationThread.h
+++ b/samples/BrowserPlugin/jni/animation/AnimationThread.h
@@ -59,9 +59,6 @@
     SkPaint* m_paint;
     SkBitmap* m_bitmap;
     SkCanvas* m_canvas;
-
-    static const unsigned int DEFAULT_WIDTH = 400;
-    static const unsigned int DEFAULT_HEIGHT = 400;
 };
 
 
diff --git a/samples/HoneycombGallery/AndroidManifest.xml b/samples/HoneycombGallery/AndroidManifest.xml
index 6e6163b..2a99856 100644
--- a/samples/HoneycombGallery/AndroidManifest.xml
+++ b/samples/HoneycombGallery/AndroidManifest.xml
@@ -15,10 +15,16 @@
   limitations under the License.
  -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.hcgallery" android:versionCode="1"
-    android:versionName="1.0">
+    package="com.example.android.hcgallery" android:versionCode="2"
+    android:versionName="1.5">
 
-    <uses-sdk android:minSdkVersion="11" />
+    <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="14" />
+
+    <!-- Declares that the app supports devices w/o touch, such as a mouse-driven device
+         or a device that provides only a d-pad for navigation -->
+    <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
+    <!-- The app uses the camera, but checks for it at runtime and will work without it -->
+    <uses-feature android:name="android.hardware.camera" android:required="false" />
 
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -27,8 +33,7 @@
         android:icon="@drawable/icon"
         android:logo="@drawable/logo"
         android:theme="@style/AppTheme.Light"
-        android:hardwareAccelerated="true"
-        android:debuggable="true">
+        android:hardwareAccelerated="true">
 
         <activity android:name=".MainActivity"
             android:label="@string/app_name"
@@ -43,8 +48,11 @@
             </intent-filter>
         </activity>
 
-        <!-- CameraSample -->
-        <activity android:name=".CameraSample"
+        <!-- Holds the ContentFragment for small/normal screens -->
+        <activity android:name=".ContentActivity" />
+
+        <!-- Camera Sample -->
+        <activity android:name=".CameraActivity"
             android:label="@string/camera_sample"
             android:screenOrientation="landscape" />
       </application>
diff --git a/samples/HoneycombGallery/res/layout-port/main.xml b/samples/HoneycombGallery/res/layout-large-port/main.xml
similarity index 82%
rename from samples/HoneycombGallery/res/layout-port/main.xml
rename to samples/HoneycombGallery/res/layout-large-port/main.xml
index a5e9970..206c6ce 100644
--- a/samples/HoneycombGallery/res/layout-port/main.xml
+++ b/samples/HoneycombGallery/res/layout-large-port/main.xml
@@ -21,14 +21,12 @@
     android:id="@+id/frags">
 
     <fragment class="com.example.android.hcgallery.TitlesFragment"
-            android:id="@+id/frag_title"
-            android:visibility="gone"
-            android:layout_marginTop="?android:attr/actionBarSize"
+            android:id="@+id/titles_frag"
             android:layout_width="match_parent"
-            android:layout_height="@dimen/titles_size"/>
+            android:layout_height="@dimen/titles_size" />
 
     <fragment class="com.example.android.hcgallery.ContentFragment"
-            android:id="@+id/frag_content"
+            android:id="@+id/content_frag"
             android:layout_width="match_parent"
             android:layout_height="match_parent" />
 
diff --git a/samples/HoneycombGallery/res/layout-port/main.xml b/samples/HoneycombGallery/res/layout-large/main.xml
similarity index 76%
copy from samples/HoneycombGallery/res/layout-port/main.xml
copy to samples/HoneycombGallery/res/layout-large/main.xml
index a5e9970..8322e32 100644
--- a/samples/HoneycombGallery/res/layout-port/main.xml
+++ b/samples/HoneycombGallery/res/layout-large/main.xml
@@ -15,21 +15,19 @@
   limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
+    android:orientation="horizontal"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:id="@+id/frags">
 
     <fragment class="com.example.android.hcgallery.TitlesFragment"
-            android:id="@+id/frag_title"
-            android:visibility="gone"
-            android:layout_marginTop="?android:attr/actionBarSize"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/titles_size"/>
+            android:id="@+id/titles_frag"
+            android:layout_width="@dimen/titles_size"
+            android:layout_height="match_parent"/>
 
     <fragment class="com.example.android.hcgallery.ContentFragment"
-            android:id="@+id/frag_content"
+            android:id="@+id/content_frag"
             android:layout_width="match_parent"
             android:layout_height="match_parent" />
 
-</LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/HoneycombGallery/res/layout/camera_sample.xml b/samples/HoneycombGallery/res/layout/camera_sample.xml
index dcb8867..9986f05 100644
--- a/samples/HoneycombGallery/res/layout/camera_sample.xml
+++ b/samples/HoneycombGallery/res/layout/camera_sample.xml
@@ -15,10 +15,7 @@
   limitations under the License.
  -->
 
-
-
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <fragment android:name="com.example.android.hcgallery.CameraFragment"
diff --git a/samples/HoneycombGallery/res/layout/action_bar_custom.xml b/samples/HoneycombGallery/res/layout/content_activity.xml
similarity index 67%
rename from samples/HoneycombGallery/res/layout/action_bar_custom.xml
rename to samples/HoneycombGallery/res/layout/content_activity.xml
index 5f111d9..0409a0c 100644
--- a/samples/HoneycombGallery/res/layout/action_bar_custom.xml
+++ b/samples/HoneycombGallery/res/layout/content_activity.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   Copyright (C) 2011 The Android Open Source Project
 
@@ -14,11 +15,11 @@
   limitations under the License.
  -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">Hello Action Bar</TextView>
-</LinearLayout>
+    <fragment class="com.example.android.hcgallery.ContentFragment"
+            android:id="@+id/content_frag"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+</FrameLayout>
diff --git a/samples/HoneycombGallery/res/layout/main.xml b/samples/HoneycombGallery/res/layout/main.xml
index 4987920..a724429 100644
--- a/samples/HoneycombGallery/res/layout/main.xml
+++ b/samples/HoneycombGallery/res/layout/main.xml
@@ -14,22 +14,13 @@
   See the License for the specific language governing permissions and
   limitations under the License.
  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:id="@+id/frags">
-
-    <fragment class="com.example.android.hcgallery.TitlesFragment"
-            android:id="@+id/frag_title"
-            android:visibility="gone"
-            android:layout_marginTop="?android:attr/actionBarSize"
-            android:layout_width="@dimen/titles_size"
-            android:layout_height="match_parent" />
-
-    <fragment class="com.example.android.hcgallery.ContentFragment"
-            android:id="@+id/frag_content"
+    android:layout_height="match_parent">
+    <fragment 
+            class="com.example.android.hcgallery.TitlesFragment"
+            android:id="@+id/titles_frag"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-    
-</LinearLayout>
+            android:layout_height="match_parent"/>
+</FrameLayout>
diff --git a/samples/HoneycombGallery/res/layout/notification.xml b/samples/HoneycombGallery/res/layout/notification.xml
index 3da757d..caae928 100644
--- a/samples/HoneycombGallery/res/layout/notification.xml
+++ b/samples/HoneycombGallery/res/layout/notification.xml
@@ -21,8 +21,8 @@
     android:orientation="horizontal">
 
     <LinearLayout
-        android:paddingLeft="16dip"
-        android:layout_width="0dip"
+        android:paddingLeft="16dp"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:layout_gravity="center_vertical"
@@ -54,7 +54,7 @@
         android:src="@drawable/btn_notification_ic_example"
         android:background="@null"
         android:layout_weight="0"
-        android:layout_width="48dip"
+        android:layout_width="48dp"
         android:layout_height="match_parent" />
 
 </LinearLayout>
diff --git a/samples/HoneycombGallery/res/menu/camera_menu.xml b/samples/HoneycombGallery/res/menu/camera_menu.xml
index 55184dd..c961d3d 100644
--- a/samples/HoneycombGallery/res/menu/camera_menu.xml
+++ b/samples/HoneycombGallery/res/menu/camera_menu.xml
@@ -16,5 +16,7 @@
  -->
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/switch_cam" android:title="Switch Camera" />
+    <item android:id="@+id/menu_switch_cam" 
+          android:title="@string/switch_camera"
+          android:showAsAction="ifRoom" />
 </menu>
diff --git a/samples/HoneycombGallery/res/menu/main_menu.xml b/samples/HoneycombGallery/res/menu/main_menu.xml
index 0e27cb5..3210aa7 100644
--- a/samples/HoneycombGallery/res/menu/main_menu.xml
+++ b/samples/HoneycombGallery/res/menu/main_menu.xml
@@ -16,25 +16,20 @@
  -->
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/camera"
-        android:title="Camera"
-        android:icon="?attr/menuIconCamera"
-        android:showAsAction="ifRoom" />
-    <item android:id="@+id/toggleTitles"
-        android:icon="?attr/menuIconToggle"
-        android:title="Toggle Titles"
-        android:showAsAction="ifRoom|withText" />
-    <!-- Example of items in the overflow menu -->
-    <item android:id="@+id/toggleTheme"
-        android:title="Day/Night"
-        android:showAsAction="never" />
-    <item android:id="@+id/showDialog"
-        android:title="Show a dialog"
-        android:showAsAction="never" />
-    <item android:id="@+id/showStandardNotification"
-        android:title="Show a basic notification"
-        android:showAsAction="never" />
-    <item android:id="@+id/showCustomNotification"
-        android:title="Show a custom notification"
-        android:showAsAction="never" />
+    <item android:id="@+id/menu_camera"
+          android:title="@string/camera"
+          android:icon="?attr/menuIconCamera"
+          android:showAsAction="ifRoom" />
+    <item android:id="@+id/menu_toggleTitles"
+          android:title="@string/toggle_titles"
+          android:icon="?attr/menuIconToggle"
+          android:showAsAction="ifRoom|withText" />
+    <item android:id="@+id/menu_toggleTheme"
+          android:title="@string/day_night" />
+    <item android:id="@+id/menu_showDialog"
+          android:title="@string/show_dialog" />
+    <item android:id="@+id/menu_showStandardNotification"
+          android:title="@string/basic_notification" />
+    <item android:id="@+id/menu_showCustomNotification"
+          android:title="@string/custom_notification" />
 </menu>
diff --git a/samples/HoneycombGallery/res/menu/photo_context_menu.xml b/samples/HoneycombGallery/res/menu/photo_context_menu.xml
index efe26c9..0039bc3 100644
--- a/samples/HoneycombGallery/res/menu/photo_context_menu.xml
+++ b/samples/HoneycombGallery/res/menu/photo_context_menu.xml
@@ -16,8 +16,8 @@
  -->
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/share"
-        android:title="Share"
-        android:icon="?attr/menuIconShare"
-        android:showAsAction="always|withText" />
+    <item android:id="@+id/menu_share"
+          android:title="@string/share"
+          android:icon="?attr/menuIconShare"
+          android:showAsAction="always|withText" />
 </menu>
diff --git a/samples/HoneycombGallery/res/values-port/dimens.xml b/samples/HoneycombGallery/res/values-large-port/dimens.xml
similarity index 100%
rename from samples/HoneycombGallery/res/values-port/dimens.xml
rename to samples/HoneycombGallery/res/values-large-port/dimens.xml
diff --git a/samples/HoneycombGallery/res/values/strings.xml b/samples/HoneycombGallery/res/values/strings.xml
index 5c3b355..65f7945 100644
--- a/samples/HoneycombGallery/res/values/strings.xml
+++ b/samples/HoneycombGallery/res/values/strings.xml
@@ -25,4 +25,14 @@
     <string name="notification_text">Example notification text</string>
 
     <string name="photo_selection_cab_title">Photo selection</string>
-</resources>
+
+    <!-- Menu strings -->
+    <string name="share">Share</string>
+    <string name="camera">Camera</string>
+    <string name="toggle_titles">Toggle Titles</string>
+    <string name="day_night">Day/Night</string>
+    <string name="show_dialog">Show a dialog</string>
+    <string name="basic_notification">Show a basic notification</string>
+    <string name="custom_notification">Show a custom notification</string>
+    <string name="switch_camera">Switch camera</string>
+</resources>
\ No newline at end of file
diff --git a/samples/HoneycombGallery/src/com/example/android/hcgallery/CameraSample.java b/samples/HoneycombGallery/src/com/example/android/hcgallery/CameraActivity.java
similarity index 90%
rename from samples/HoneycombGallery/src/com/example/android/hcgallery/CameraSample.java
rename to samples/HoneycombGallery/src/com/example/android/hcgallery/CameraActivity.java
index 2243858..d87676c 100644
--- a/samples/HoneycombGallery/src/com/example/android/hcgallery/CameraSample.java
+++ b/samples/HoneycombGallery/src/com/example/android/hcgallery/CameraActivity.java
@@ -19,7 +19,8 @@
 import android.app.Activity;
 import android.os.Bundle;
 
-public class CameraSample extends Activity {
+/** Basic shell activity that hosts CameraFragment. */
+public class CameraActivity extends Activity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/samples/HoneycombGallery/src/com/example/android/hcgallery/CameraFragment.java b/samples/HoneycombGallery/src/com/example/android/hcgallery/CameraFragment.java
index 19c4b47..3290f11 100644
--- a/samples/HoneycombGallery/src/com/example/android/hcgallery/CameraFragment.java
+++ b/samples/HoneycombGallery/src/com/example/android/hcgallery/CameraFragment.java
@@ -16,12 +16,9 @@
 
 package com.example.android.hcgallery;
 
-import java.io.IOException;
-import java.util.List;
-
-import android.app.Fragment;
-import android.app.Activity;
 import android.app.ActionBar;
+import android.app.Activity;
+import android.app.Fragment;
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.Camera;
@@ -38,12 +35,16 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import java.io.IOException;
+import java.util.List;
+
 public class CameraFragment extends Fragment {
 
     private Preview mPreview;
     Camera mCamera;
     int mNumberOfCameras;
-    int mCameraCurrentlyLocked;
+    int mCurrentCamera;  // Camera ID currently chosen
+    int mCameraCurrentlyLocked;  // Camera ID that's actually acquired
 
     // The first rear facing camera
     int mDefaultCameraId;
@@ -52,20 +53,18 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-
-        // Create a RelativeLayout container that will hold a SurfaceView,
-        // and set it as the content of our activity.
+        // Create a container that will hold a SurfaceView for camera previews
         mPreview = new Preview(this.getActivity());
 
         // Find the total number of cameras available
         mNumberOfCameras = Camera.getNumberOfCameras();
 
-        // Find the ID of the default camera
+        // Find the ID of the rear-facing ("default") camera
         CameraInfo cameraInfo = new CameraInfo();
         for (int i = 0; i < mNumberOfCameras; i++) {
             Camera.getCameraInfo(i, cameraInfo);
             if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
-                mDefaultCameraId = i;
+                mCurrentCamera = mDefaultCameraId = i;
             }
         }
         setHasOptionsMenu(mNumberOfCameras > 1);
@@ -95,9 +94,10 @@
     public void onResume() {
         super.onResume();
 
-        // Open the default i.e. the first rear facing camera.
-        mCamera = Camera.open(mDefaultCameraId);
-        mCameraCurrentlyLocked = mDefaultCameraId;
+        // Use mCurrentCamera to select the camera desired to safely restore
+        // the fragment after the camera has been changed
+        mCamera = Camera.open(mCurrentCamera);
+        mCameraCurrentlyLocked = mCurrentCamera;
         mPreview.setCamera(mCamera);
     }
 
@@ -128,7 +128,7 @@
     public boolean onOptionsItemSelected(MenuItem item) {
         // Handle item selection
         switch (item.getItemId()) {
-        case R.id.switch_cam:
+        case R.id.menu_switch_cam:
             // Release this camera -> mCameraCurrentlyLocked
             if (mCamera != null) {
                 mCamera.stopPreview();
@@ -139,10 +139,9 @@
 
             // Acquire the next camera and request Preview to reconfigure
             // parameters.
-            mCamera = Camera
-                    .open((mCameraCurrentlyLocked + 1) % mNumberOfCameras);
-            mCameraCurrentlyLocked = (mCameraCurrentlyLocked + 1)
-                    % mNumberOfCameras;
+            mCurrentCamera = (mCameraCurrentlyLocked + 1) % mNumberOfCameras;
+            mCamera = Camera.open(mCurrentCamera);
+            mCameraCurrentlyLocked = mCurrentCamera;
             mPreview.switchCamera(mCamera);
 
             // Start the preview
@@ -152,6 +151,7 @@
             Intent intent = new Intent(this.getActivity(), MainActivity.class);
             intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
             startActivity(intent);
+            return true;
 
         default:
             return super.onOptionsItemSelected(item);
@@ -175,6 +175,7 @@
     Size mPreviewSize;
     List<Size> mSupportedPreviewSizes;
     Camera mCamera;
+    boolean mSurfaceCreated = false;
 
     Preview(Context context) {
         super(context);
@@ -194,7 +195,7 @@
         if (mCamera != null) {
             mSupportedPreviewSizes = mCamera.getParameters()
                     .getSupportedPreviewSizes();
-            requestLayout();
+            if (mSurfaceCreated) requestLayout();
         }
     }
 
@@ -205,11 +206,6 @@
         } catch (IOException exception) {
             Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
         }
-        Camera.Parameters parameters = camera.getParameters();
-        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
-        requestLayout();
-
-        camera.setParameters(parameters);
     }
 
     @Override
@@ -227,11 +223,18 @@
             mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width,
                     height);
         }
+
+        if (mCamera != null) {
+          Camera.Parameters parameters = mCamera.getParameters();
+          parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
+
+          mCamera.setParameters(parameters);
+        }
     }
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        if (changed && getChildCount() > 0) {
+        if (getChildCount() > 0) {
             final View child = getChildAt(0);
 
             final int width = r - l;
@@ -269,6 +272,8 @@
         } catch (IOException exception) {
             Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
         }
+        if (mPreviewSize == null) requestLayout();
+        mSurfaceCreated = true;
     }
 
     public void surfaceDestroyed(SurfaceHolder holder) {
diff --git a/samples/HoneycombGallery/src/com/example/android/hcgallery/ContentActivity.java b/samples/HoneycombGallery/src/com/example/android/hcgallery/ContentActivity.java
new file mode 100644
index 0000000..f8e93d4
--- /dev/null
+++ b/samples/HoneycombGallery/src/com/example/android/hcgallery/ContentActivity.java
@@ -0,0 +1,48 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package com.example.android.hcgallery;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/** This is a shell activity that hosts ContentFragment when the device screen
+ * is smaller than "large".
+ */
+public class ContentActivity extends Activity {
+  private int mThemeId = 0;
+
+  @Override
+  public void onCreate(Bundle savedInstanceState) {
+      super.onCreate(savedInstanceState);
+
+      Bundle extras = getIntent().getExtras();
+      if (extras != null) {
+          // The activity theme is the only state data that the activity needs
+          // to restore. All info about the content displayed is managed by the fragment
+          mThemeId = extras.getInt("theme");
+      } else if (savedInstanceState != null) {
+          // If there's no restore state, get the theme from the intent
+          mThemeId = savedInstanceState.getInt("theme");
+      }
+
+      if (mThemeId != 0) {
+          setTheme(mThemeId);
+      }
+
+      setContentView(R.layout.content_activity);
+
+      if (extras != null) {
+        // Take the info from the intent and deliver it to the fragment so it can update
+        int category = extras.getInt("category");
+        int position = extras.getInt("position");
+        ContentFragment frag = (ContentFragment) getFragmentManager().findFragmentById(R.id.content_frag);
+        frag.updateContentAndRecycleBitmap(category, position);
+      }
+  }
+
+  @Override
+  protected void onSaveInstanceState(Bundle outState) {
+      super.onSaveInstanceState(outState);
+      outState.putInt("theme", mThemeId);
+  }
+}
diff --git a/samples/HoneycombGallery/src/com/example/android/hcgallery/ContentFragment.java b/samples/HoneycombGallery/src/com/example/android/hcgallery/ContentFragment.java
index 8c3323b..b6754f9 100644
--- a/samples/HoneycombGallery/src/com/example/android/hcgallery/ContentFragment.java
+++ b/samples/HoneycombGallery/src/com/example/android/hcgallery/ContentFragment.java
@@ -17,7 +17,6 @@
 package com.example.android.hcgallery;
 
 import android.app.ActionBar;
-import android.app.Activity;
 import android.app.Fragment;
 import android.content.ClipData;
 import android.content.ClipData.Item;
@@ -37,6 +36,8 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
 import android.widget.ImageView;
 import android.widget.Toast;
 
@@ -46,8 +47,16 @@
 import java.io.IOException;
 import java.util.StringTokenizer;
 
+/** Fragment that shows the content selected from the TitlesFragment.
+ * When running on a screen size smaller than "large", this fragment is hosted in
+ * ContentActivity. Otherwise, it appears side by side with the TitlesFragment
+ * in MainActivity. */
 public class ContentFragment extends Fragment {
     private View mContentView;
+    private int mCategory = 0;
+    private int mCurPosition = 0;
+    private boolean mSystemUiVisible = true;
+    private boolean mSoloFragment = false;
 
     // The bitmap currently used by ImageView
     private Bitmap mBitmap = null;
@@ -55,11 +64,9 @@
     // Current action mode (contextual action bar, a.k.a. CAB)
     private ActionMode mCurrentActionMode;
 
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-    }
-
+    /** This is where we initialize the fragment's UI and attach some
+     * event listeners to UI components.
+     */
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
@@ -67,65 +74,48 @@
         final ImageView imageView = (ImageView) mContentView.findViewById(R.id.image);
         mContentView.setDrawingCacheEnabled(false);
 
+        // Handle drag events when a list item is dragged into the view
         mContentView.setOnDragListener(new View.OnDragListener() {
-            public boolean onDrag(View v, DragEvent event) {
+            public boolean onDrag(View view, DragEvent event) {
                 switch (event.getAction()) {
                     case DragEvent.ACTION_DRAG_ENTERED:
-                        mContentView.setBackgroundColor(
+                        view.setBackgroundColor(
                                 getResources().getColor(R.color.drag_active_color));
                         break;
 
                     case DragEvent.ACTION_DRAG_EXITED:
-                        mContentView.setBackgroundColor(Color.TRANSPARENT);
+                        view.setBackgroundColor(Color.TRANSPARENT);
                         break;
 
                     case DragEvent.ACTION_DRAG_STARTED:
                         return processDragStarted(event);
 
                     case DragEvent.ACTION_DROP:
-                        mContentView.setBackgroundColor(Color.TRANSPARENT);
+                        view.setBackgroundColor(Color.TRANSPARENT);
                         return processDrop(event, imageView);
                 }
                 return false;
             }
         });
 
-        // Keep the action bar visibility in sync with the system status bar. That is, when entering
-        // 'lights out mode,' hide the action bar, and when exiting this mode, show the action bar.
-
-        final Activity activity = getActivity();
-        mContentView.setOnSystemUiVisibilityChangeListener(
-                new View.OnSystemUiVisibilityChangeListener() {
-                    public void onSystemUiVisibilityChange(int visibility) {
-                        ActionBar actionBar = activity.getActionBar();
-                        if (actionBar != null) {
-                            mContentView.setSystemUiVisibility(visibility);
-                            if (visibility == View.STATUS_BAR_VISIBLE) {
-                                actionBar.show();
-                            } else {
-                                actionBar.hide();
-                            }
-                        }
-                    }
-                });
-
-        // Show/hide the system status bar when single-clicking a photo. This is also called
-        // 'lights out mode.' Activating and deactivating this mode also invokes the listener
-        // defined above, which will show or hide the action bar accordingly.
-
+        // Show/hide the system status bar when single-clicking a photo.
         mContentView.setOnClickListener(new OnClickListener() {
-            public void onClick(View v) {
-                if (mContentView.getSystemUiVisibility() == View.STATUS_BAR_VISIBLE) {
-                    mContentView.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
+            public void onClick(View view) {
+                if (mCurrentActionMode != null) {
+                  // If we're in an action mode, don't toggle the action bar
+                  return;
+                }
+
+                if (mSystemUiVisible) {
+                  setSystemUiVisible(false);
                 } else {
-                    mContentView.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
+                  setSystemUiVisible(true);
                 }
             }
         });
 
         // When long-pressing a photo, activate the action mode for selection, showing the
         // contextual action bar (CAB).
-
         mContentView.setOnLongClickListener(new View.OnLongClickListener() {
             public boolean onLongClick(View view) {
                 if (mCurrentActionMode != null) {
@@ -134,7 +124,7 @@
 
                 mCurrentActionMode = getActivity().startActionMode(
                         mContentSelectionActionModeCallback);
-                mContentView.setSelected(true);
+                view.setSelected(true);
                 return true;
             }
         });
@@ -142,6 +132,99 @@
         return mContentView;
     }
 
+    /** This is where we perform additional setup for the fragment that's either
+     * not related to the fragment's layout or must be done after the layout is drawn.
+     */
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        // Set member variable for whether this fragment is the only one in the activity
+        Fragment listFragment = getFragmentManager().findFragmentById(R.id.titles_frag);
+        mSoloFragment = listFragment == null ? true : false;
+
+        if (mSoloFragment) {
+            // The fragment is alone, so enable up navigation
+            getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
+            // Must call in order to get callback to onOptionsItemSelected()
+            setHasOptionsMenu(true);
+        }
+
+        // Current position and UI visibility should survive screen rotations.
+        if (savedInstanceState != null) {
+            setSystemUiVisible(savedInstanceState.getBoolean("systemUiVisible"));
+            if (mSoloFragment) {
+                // Restoring these members is not necessary when this fragment
+                // is combined with the TitlesFragment, because when the TitlesFragment
+                // is restored, it selects the appropriate item and sends the event
+                // to the updateContentAndRecycleBitmap() method itself
+                mCategory = savedInstanceState.getInt("category");
+                mCurPosition = savedInstanceState.getInt("listPosition");
+                updateContentAndRecycleBitmap(mCategory, mCurPosition);
+            }
+        }
+
+        if (mSoloFragment) {
+          String title = Directory.getCategory(mCategory).getEntry(mCurPosition).getName();
+          ActionBar bar = getActivity().getActionBar();
+          bar.setTitle(title);
+        }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // This callback is used only when mSoloFragment == true (see onActivityCreated above)
+        switch (item.getItemId()) {
+        case android.R.id.home:
+            // App icon in Action Bar clicked; go up
+            Intent intent = new Intent(getActivity(), MainActivity.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // Reuse the existing instance
+            startActivity(intent);
+            return true;
+        default:
+            return super.onOptionsItemSelected(item);
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState (Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt("listPosition", mCurPosition);
+        outState.putInt("category", mCategory);
+        outState.putBoolean("systemUiVisible", mSystemUiVisible);
+    }
+
+    /** Toggle whether the system UI (status bar / system bar) is visible.
+     *  This also toggles the action bar visibility.
+     * @param show True to show the system UI, false to hide it.
+     */
+    void setSystemUiVisible(boolean show) {
+        mSystemUiVisible = show;
+
+        Window window = getActivity().getWindow();
+        WindowManager.LayoutParams winParams = window.getAttributes();
+        View view = getView();
+        ActionBar actionBar = getActivity().getActionBar();
+
+        if (show) {
+            // Show status bar (remove fullscreen flag)
+            window.setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+            // Show system bar
+            view.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
+            // Show action bar
+            actionBar.show();
+        } else {
+            // Add fullscreen flag (hide status bar)
+            window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+                WindowManager.LayoutParams.FLAG_FULLSCREEN);
+            // Hide system bar
+            view.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
+            // Hide action bar
+            actionBar.hide();
+        }
+        window.setAttributes(winParams);
+    }
+
     boolean processDragStarted(DragEvent event) {
         // Determine whether to continue processing drag and drop based on the
         // plain text mime type.
@@ -176,7 +259,7 @@
                     updateContentAndRecycleBitmap(category, entryId);
                     // Update list fragment with selected entry.
                     TitlesFragment titlesFrag = (TitlesFragment)
-                            getFragmentManager().findFragmentById(R.id.frag_title);
+                            getFragmentManager().findFragmentById(R.id.titles_frag);
                     titlesFrag.selectPosition(entryId);
                     return true;
                 }
@@ -185,7 +268,15 @@
         return false;
     }
 
+    /**
+     * Sets the current image visible.
+     * @param category Index position of the image category
+     * @param position Index position of the image
+     */
     void updateContentAndRecycleBitmap(int category, int position) {
+        mCategory = category;
+        mCurPosition = position;
+
         if (mCurrentActionMode != null) {
             mCurrentActionMode.finish();
         }
@@ -203,6 +294,9 @@
         ((ImageView) getView().findViewById(R.id.image)).setImageBitmap(mBitmap);
     }
 
+    /** Share the currently selected photo using an AsyncTask to compress the image
+     * and then invoke the appropriate share intent.
+     */
     void shareCurrentPhoto() {
         File externalCacheDir = getActivity().getExternalCacheDir();
         if (externalCacheDir == null) {
@@ -229,6 +323,7 @@
              * Compress and write the bitmap to disk on a separate thread.
              * @return TRUE if the write was successful, FALSE otherwise.
              */
+            @Override
             protected Boolean doInBackground(Void... voids) {
                 try {
                     FileOutputStream fo = new FileOutputStream(tempFile, false);
@@ -250,6 +345,7 @@
              * After doInBackground completes (either successfully or in failure), we invoke an
              * intent to share the photo. This code is run on the main (UI) thread.
              */
+            @Override
             protected void onPostExecute(Boolean result) {
                 if (result != Boolean.TRUE) {
                     return;
@@ -283,7 +379,7 @@
 
         public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
             switch (menuItem.getItemId()) {
-                case R.id.share:
+                case R.id.menu_share:
                     shareCurrentPhoto();
                     actionMode.finish();
                     return true;
diff --git a/samples/HoneycombGallery/src/com/example/android/hcgallery/MainActivity.java b/samples/HoneycombGallery/src/com/example/android/hcgallery/MainActivity.java
index 3cfaf6d..06905b8 100644
--- a/samples/HoneycombGallery/src/com/example/android/hcgallery/MainActivity.java
+++ b/samples/HoneycombGallery/src/com/example/android/hcgallery/MainActivity.java
@@ -33,6 +33,7 @@
 import android.app.PendingIntent;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -43,92 +44,86 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.Window;
 import android.widget.RemoteViews;
 
-public class MainActivity extends Activity implements ActionBar.TabListener {
+/** This is the main "launcher" activity.
+ * When running on a "large" or larger screen, this activity displays both the
+ * TitlesFragments and the Content Fragment. When on a smaller screen size, this
+ * activity displays only the TitlesFragment. In which case, selecting a list
+ * item opens the ContentActivity, holds only the ContentFragment. */
+public class MainActivity extends Activity implements TitlesFragment.OnItemSelectedListener {
 
-    private static final int NOTIFICATION_DEFAULT = 1;
-    private static final String ACTION_DIALOG = "com.example.android.hcgallery.action.DIALOG";
-
-    private View mActionBarView;
     private Animator mCurrentTitlesAnimator;
     private String[] mToggleLabels = {"Show Titles", "Hide Titles"};
-    private int mLabelIndex = 1;
+    private static final int NOTIFICATION_DEFAULT = 1;
+    private static final String ACTION_DIALOG = "com.example.android.hcgallery.action.DIALOG";
     private int mThemeId = -1;
+    private boolean mDualFragments = false;
+    private boolean mTitlesHidden = false;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        if(savedInstanceState != null && savedInstanceState.getInt("theme", -1) != -1) {
-            mThemeId = savedInstanceState.getInt("theme");
-            this.setTheme(mThemeId);
+        if(savedInstanceState != null) {
+            if (savedInstanceState.getInt("theme", -1) != -1) {
+              mThemeId = savedInstanceState.getInt("theme");
+              this.setTheme(mThemeId);
+            }
+            mTitlesHidden = savedInstanceState.getBoolean("titlesHidden");
         }
 
         setContentView(R.layout.main);
 
-        Directory.initializeDirectory();
-
         ActionBar bar = getActionBar();
+        bar.setDisplayShowTitleEnabled(false);
 
-        int i;
-        for (i = 0; i < Directory.getCategoryCount(); i++) {
-            bar.addTab(bar.newTab().setText(Directory.getCategory(i).getName())
-                    .setTabListener(this));
+        ContentFragment frag = (ContentFragment) getFragmentManager()
+                .findFragmentById(R.id.content_frag);
+        if (frag != null) mDualFragments = true;
+        
+        if (mTitlesHidden) {
+            getFragmentManager().beginTransaction()
+                    .hide(getFragmentManager().findFragmentById(R.id.titles_frag)).commit();
         }
-
-        mActionBarView = getLayoutInflater().inflate(
-                R.layout.action_bar_custom, null);
-
-        bar.setCustomView(mActionBarView);
-        bar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_USE_LOGO);
-        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-        bar.setDisplayShowHomeEnabled(true);
-
-        // If category is not saved to the savedInstanceState,
-        // 0 is returned by default.
-        if(savedInstanceState != null) {
-            int category = savedInstanceState.getInt("category");
-            bar.selectTab(bar.getTabAt(category));
-        }
-    }
-
-    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
-        TitlesFragment titleFrag = (TitlesFragment) getFragmentManager()
-                .findFragmentById(R.id.frag_title);
-        titleFrag.populateTitles(tab.getPosition());
-
-        titleFrag.selectPosition(0);
-    }
-
-    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
-    }
-
-    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
     }
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         MenuInflater inflater = getMenuInflater();
         inflater.inflate(R.menu.main_menu, menu);
+        // If the device doesn't support camera, remove the camera menu item
+        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
+            menu.removeItem(R.id.menu_camera);
+        }
         return true;
     }
 
     @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        // If not showing both fragments, remove the "toggle titles" menu item
+        if (!mDualFragments) {
+            menu.removeItem(R.id.menu_toggleTitles);
+        } else {
+            menu.findItem(R.id.menu_toggleTitles).setTitle(mToggleLabels[mTitlesHidden ? 0 : 1]);
+        }
+        return super.onPrepareOptionsMenu(menu);
+    }
+
+    @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
-        case R.id.camera:
-            Intent intent = new Intent(this, CameraSample.class);
+        case R.id.menu_camera:
+            Intent intent = new Intent(this, CameraActivity.class);
             intent.putExtra("theme", mThemeId);
             startActivity(intent);
             return true;
 
-        case R.id.toggleTitles:
+        case R.id.menu_toggleTitles:
             toggleVisibleTitles();
             return true;
 
-        case R.id.toggleTheme:
+        case R.id.menu_toggleTheme:
             if (mThemeId == R.style.AppTheme_Dark) {
                 mThemeId = R.style.AppTheme_Light;
             } else {
@@ -137,15 +132,15 @@
             this.recreate();
             return true;
 
-        case R.id.showDialog:
+        case R.id.menu_showDialog:
             showDialog("This is indeed an awesome dialog.");
             return true;
 
-        case R.id.showStandardNotification:
+        case R.id.menu_showStandardNotification:
             showNotification(false);
             return true;
 
-        case R.id.showCustomNotification:
+        case R.id.menu_showCustomNotification:
             showNotification(true);
             return true;
 
@@ -154,13 +149,13 @@
         }
     }
 
+    /** Respond to the "toogle titles" item in the action bar */
     public void toggleVisibleTitles() {
         // Use these for custom animations.
         final FragmentManager fm = getFragmentManager();
         final TitlesFragment f = (TitlesFragment) fm
-                .findFragmentById(R.id.frag_title);
+                .findFragmentById(R.id.titles_frag);
         final View titlesView = f.getView();
-        mLabelIndex = 1 - mLabelIndex;
 
         // Determine if we're in portrait, and whether we're showing or hiding the titles
         // with this toggle.
@@ -207,6 +202,8 @@
                 @Override
                 public void onAnimationEnd(Animator animator) {
                     mCurrentTitlesAnimator = null;
+                    mTitlesHidden = false;
+                    invalidateOptionsMenu();
                 }
             });
 
@@ -226,6 +223,8 @@
                         return;
                     mCurrentTitlesAnimator = null;
                     fm.beginTransaction().hide(f).commit();
+                    mTitlesHidden = true;
+                    invalidateOptionsMenu();
                 }
             });
         }
@@ -234,8 +233,6 @@
         objectAnimator.start();
         mCurrentTitlesAnimator = objectAnimator;
 
-        invalidateOptionsMenu();
-
         // Manually trigger onNewIntent to check for ACTION_DIALOG.
         onNewIntent(getIntent());
     }
@@ -314,21 +311,35 @@
     }
 
     @Override
-    public boolean onPrepareOptionsMenu(Menu menu) {
-        menu.getItem(1).setTitle(mToggleLabels[mLabelIndex]);
-        return true;
-    }
-
-    @Override
     public void onSaveInstanceState (Bundle outState) {
         super.onSaveInstanceState(outState);
-        ActionBar bar = getActionBar();
-        int category = bar.getSelectedTab().getPosition();
-        outState.putInt("category", category);
         outState.putInt("theme", mThemeId);
+        outState.putBoolean("titlesHidden", mTitlesHidden);
+    }
+
+    /** Implementation for TitlesFragment.OnItemSelectedListener.
+     * When the TitlesFragment receives an onclick event for a list item,
+     * it's passed back to this activity through this method so that we can
+     * deliver it to the ContentFragment in the manner appropriate */
+    public void onItemSelected(int category, int position) {
+      if (!mDualFragments) {
+          // If showing only the TitlesFragment, start the ContentActivity and
+          // pass it the info about the selected item
+          Intent intent = new Intent(this, ContentActivity.class);
+          intent.putExtra("category", category);
+          intent.putExtra("position", position);
+          intent.putExtra("theme", mThemeId);
+          startActivity(intent);
+      } else {
+          // If showing both fragments, directly update the ContentFragment
+          ContentFragment frag = (ContentFragment) getFragmentManager()
+                  .findFragmentById(R.id.content_frag);
+          frag.updateContentAndRecycleBitmap(category, position);
+      }
     }
 
 
+    /** Dialog implementation that shows a simple dialog as a fragment */
     public static class MyDialogFragment extends DialogFragment {
 
         public static MyDialogFragment newInstance(String title) {
diff --git a/samples/HoneycombGallery/src/com/example/android/hcgallery/TitlesFragment.java b/samples/HoneycombGallery/src/com/example/android/hcgallery/TitlesFragment.java
index 85a7b68..2726679 100644
--- a/samples/HoneycombGallery/src/com/example/android/hcgallery/TitlesFragment.java
+++ b/samples/HoneycombGallery/src/com/example/android/hcgallery/TitlesFragment.java
@@ -16,62 +16,172 @@
 
 package com.example.android.hcgallery;
 
-import android.app.Fragment;
-import android.app.FragmentManager;
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.FragmentTransaction;
 import android.app.ListFragment;
 import android.content.ClipData;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.Paint;
-import android.graphics.Typeface;
 import android.os.Bundle;
-import android.text.TextPaint;
-import android.util.TypedValue;
 import android.view.View;
+import android.view.ViewTreeObserver;
 import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.ArrayAdapter;
-import android.widget.ImageView;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
 import android.widget.ListView;
 import android.widget.TextView;
-import android.widget.AdapterView.OnItemLongClickListener;
 
-public class TitlesFragment extends ListFragment {
+/**
+ * Fragment that shows the list of images
+ * As an extension of ListFragment, this fragment uses a default layout
+ * that includes a single ListView, which you can acquire with getListView()
+ * When running on a screen size smaller than "large", this fragment appears alone
+ * in MainActivity. In this case, selecting a list item opens the ContentActivity,
+ * which likewise holds only the ContentFragment.
+ */
+public class TitlesFragment extends ListFragment implements ActionBar.TabListener {
+    OnItemSelectedListener mListener;
     private int mCategory = 0;
     private int mCurPosition = 0;
+    private boolean mDualFragments = false;
 
+    /** Container Activity must implement this interface and we ensure
+     * that it does during the onAttach() callback
+     */
+    public interface OnItemSelectedListener {
+        public void onItemSelected(int category, int position);
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        // Check that the container activity has implemented the callback interface
+        try {
+            mListener = (OnItemSelectedListener) activity;
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString() 
+                    + " must implement OnItemSelectedListener");
+        }
+    }
+
+    /** This is where we perform setup for the fragment that's either
+     * not related to the fragment's layout or must be done after the layout is drawn.
+     * Notice that this fragment does not implement onCreateView(), because it extends
+     * ListFragment, which includes a ListView as the root view by default, so there's
+     * no need to set up the layout.
+     */
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
+        ContentFragment frag = (ContentFragment) getFragmentManager()
+                .findFragmentById(R.id.content_frag);
+        if (frag != null) mDualFragments = true;
+
+        ActionBar bar = getActivity().getActionBar();
+        bar.setDisplayHomeAsUpEnabled(false);
+        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+
+        // Must call in order to get callback to onCreateOptionsMenu()
+        setHasOptionsMenu(true);
+
+        Directory.initializeDirectory();
+        for (int i = 0; i < Directory.getCategoryCount(); i++) {
+            bar.addTab(bar.newTab().setText(Directory.getCategory(i).getName())
+                    .setTabListener(this));
+        }
+
         //Current position should survive screen rotations.
         if (savedInstanceState != null) {
             mCategory = savedInstanceState.getInt("category");
             mCurPosition = savedInstanceState.getInt("listPosition");
+            bar.selectTab(bar.getTabAt(mCategory));
         }
 
         populateTitles(mCategory);
         ListView lv = getListView();
-        lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-        lv.setCacheColorHint(Color.TRANSPARENT);
-        lv.setOnItemLongClickListener(new OnItemLongClickListener() {
-            public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id) {
-                final String title = (String) ((TextView) v).getText();
+        lv.setCacheColorHint(Color.TRANSPARENT); // Improves scrolling performance
 
-                // Set up clip data with the category||entry_id format.
-                final String textData = String.format("%d||%d", mCategory, pos);
-                ClipData data = ClipData.newPlainText(title, textData);
-                v.startDrag(data, new MyDragShadowBuilder(v), null, 0);
-                return true;
-            }
-        });
+        if (mDualFragments) {
+            // Highlight the currently selected item
+            lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+            // Enable drag and dropping
+            lv.setOnItemLongClickListener(new OnItemLongClickListener() {
+                public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id) {
+                    final String title = (String) ((TextView) v).getText();
 
-        selectPosition(mCurPosition);
+                    // Set up clip data with the category||entry_id format.
+                    final String textData = String.format("%d||%d", mCategory, pos);
+                    ClipData data = ClipData.newPlainText(title, textData);
+                    v.startDrag(data, new MyDragShadowBuilder(v), null, 0);
+                    return true;
+                }
+            });
+        }
+
+        // If showing both fragments, select the appropriate list item by default
+        if (mDualFragments) selectPosition(mCurPosition);
+
+        // Attach a GlobalLayoutListener so that we get a callback when the layout
+        // has finished drawing. This is necessary so that we can apply top-margin
+        // to the ListView in order to dodge the ActionBar. Ordinarily, that's not
+        // necessary, but we've set the ActionBar to "overlay" mode using our theme,
+        // so the layout does not account for the action bar position on its own.
+        ViewTreeObserver observer = getListView().getViewTreeObserver();
+        observer.addOnGlobalLayoutListener(layoutListener);
     }
 
+    @Override
+    public void onDestroyView() {
+      super.onDestroyView();
+      // Always detach ViewTreeObserver listeners when the view tears down
+      getListView().getViewTreeObserver().removeGlobalOnLayoutListener(layoutListener);
+    }
+
+    /** Attaches an adapter to the fragment's ListView to populate it with items */
+    public void populateTitles(int category) {
+        DirectoryCategory cat = Directory.getCategory(category);
+        String[] items = new String[cat.getEntryCount()];
+        for (int i = 0; i < cat.getEntryCount(); i++)
+            items[i] = cat.getEntry(i).getName();
+        // Convenience method to attach an adapter to ListFragment's ListView
+        setListAdapter(new ArrayAdapter<String>(getActivity(),
+                R.layout.title_list_item, items));
+        mCategory = category;
+    }
+
+    @Override
+    public void onListItemClick(ListView l, View v, int position, long id) {
+        // Send the event to the host activity via OnItemSelectedListener callback
+        mListener.onItemSelected(mCategory, position);
+        mCurPosition = position;
+    }
+
+    /** Called to select an item from the listview */
+    public void selectPosition(int position) {
+        // Only if we're showing both fragments should the item be "highlighted"
+        if (mDualFragments) {
+            ListView lv = getListView();
+            lv.setItemChecked(position, true);
+        }
+        // Calls the parent activity's implementation of the OnItemSelectedListener
+        // so the activity can pass the event to the sibling fragment as appropriate
+        mListener.onItemSelected(mCategory, position);
+    }
+
+    @Override
+    public void onSaveInstanceState (Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt("listPosition", mCurPosition);
+        outState.putInt("category", mCategory);
+    }
+
+    /** This defines how the draggable list items appear during a drag event */
     private class MyDragShadowBuilder extends View.DragShadowBuilder {
         private Drawable mShadow;
 
@@ -93,38 +203,53 @@
         }
     }
 
-    public void populateTitles(int category) {
-        DirectoryCategory cat = Directory.getCategory(category);
-        String[] items = new String[cat.getEntryCount()];
-        for (int i = 0; i < cat.getEntryCount(); i++)
-            items[i] = cat.getEntry(i).getName();
-        setListAdapter(new ArrayAdapter<String>(getActivity(),
-                R.layout.title_list_item, items));
-        mCategory = category;
+    // Because the fragment doesn't have a reliable callback to notify us when
+    // the activity's layout is completely drawn, this OnGlobalLayoutListener provides
+    // the necessary callback so we can add top-margin to the ListView in order to dodge
+    // the ActionBar. Which is necessary because the ActionBar is in overlay mode, meaning
+    // that it will ordinarily sit on top of the activity layout as a top layer and
+    // the ActionBar height can vary. Specifically, when on a small/normal size screen,
+    // the action bar tabs appear in a second row, making the action bar twice as tall.
+    ViewTreeObserver.OnGlobalLayoutListener layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
+        @Override
+        public void onGlobalLayout() {
+            int barHeight = getActivity().getActionBar().getHeight();
+            ListView listView = getListView();
+            FrameLayout.LayoutParams params = (LayoutParams) listView.getLayoutParams();
+            // The list view top-margin should always match the action bar height
+            if (params.topMargin != barHeight) {
+                params.topMargin = barHeight;
+                listView.setLayoutParams(params);
+            }
+            // The action bar doesn't update its height when hidden, so make top-margin zero
+            if (!getActivity().getActionBar().isShowing()) {
+              params.topMargin = 0;
+              listView.setLayoutParams(params);
+            }
+        }
+    };
+
+
+    /* The following are callbacks implemented for the ActionBar.TabListener,
+     * which this fragment implements to handle events when tabs are selected.
+     */
+
+    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
+        TitlesFragment titleFrag = (TitlesFragment) getFragmentManager()
+                .findFragmentById(R.id.titles_frag);
+        titleFrag.populateTitles(tab.getPosition());
+        
+        if (mDualFragments) {
+            titleFrag.selectPosition(0);
+        }
     }
 
-    @Override
-    public void onListItemClick(ListView l, View v, int position, long id) {
-        updateImage(position);
+    /* These must be implemented, but we don't use them */
+    
+    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
     }
 
-    private void updateImage(int position) {
-        ContentFragment frag = (ContentFragment) getFragmentManager()
-                .findFragmentById(R.id.frag_content);
-        frag.updateContentAndRecycleBitmap(mCategory, position);
-        mCurPosition = position;
+    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
     }
 
-    public void selectPosition(int position) {
-        ListView lv = getListView();
-        lv.setItemChecked(position, true);
-        updateImage(position);
-    }
-
-    @Override
-    public void onSaveInstanceState (Bundle outState) {
-        super.onSaveInstanceState(outState);
-        outState.putInt("listPosition", mCurPosition);
-        outState.putInt("category", mCategory);
-    }
 }
diff --git a/samples/RandomMusicPlayer/Android.mk b/samples/RandomMusicPlayer/Android.mk
new file mode 100644
index 0000000..91637b1
--- /dev/null
+++ b/samples/RandomMusicPlayer/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := samples
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := RandomMusicPlayer
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/samples/RandomMusicPlayer/AndroidManifest.xml b/samples/RandomMusicPlayer/AndroidManifest.xml
index 5a0fc28..6e52b61 100644
--- a/samples/RandomMusicPlayer/AndroidManifest.xml
+++ b/samples/RandomMusicPlayer/AndroidManifest.xml
@@ -1,30 +1,34 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+  Copyright (C) 2011 The Android Open Source Project
 
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
 
-          http://www.apache.org/licenses/LICENSE-2.0
+       http://www.apache.org/licenses/LICENSE-2.0
 
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="com.example.android.musicplayer"
-      android:versionCode="1"
-      android:versionName="1.0">
+    package="com.example.android.musicplayer"
+    android:versionCode="1"
+    android:versionName="1.0">
 
-    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="8" />
-    <uses-permission android:name="android.permission.WAKE_LOCK"/>
+    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="14" />
 
-    <application android:icon="@drawable/ic_launcher" android:label="Random Music Player">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <application android:icon="@drawable/ic_launcher" android:label="@string/app_title">
+
         <activity android:name=".MainActivity"
-                  android:label="Random Music Player"
-                  android:theme="@android:style/Theme.Black.NoTitleBar">
+            android:label="@string/app_title"
+            android:theme="@android:style/Theme.Black.NoTitleBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -33,6 +37,7 @@
 
         <service android:exported="false" android:name=".MusicService">
             <intent-filter>
+                <action android:name="com.example.android.musicplayer.action.TOGGLE_PLAYBACK" />
                 <action android:name="com.example.android.musicplayer.action.PLAY" />
                 <action android:name="com.example.android.musicplayer.action.PAUSE" />
                 <action android:name="com.example.android.musicplayer.action.SKIP" />
@@ -49,6 +54,10 @@
             <intent-filter>
                 <action android:name="android.media.AUDIO_BECOMING_NOISY" />
             </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.MEDIA_BUTTON" />
+            </intent-filter>
         </receiver>
+
     </application>
 </manifest>
diff --git a/samples/RandomMusicPlayer/_index.html b/samples/RandomMusicPlayer/_index.html
index 657e6c4..f719fad 100644
--- a/samples/RandomMusicPlayer/_index.html
+++ b/samples/RandomMusicPlayer/_index.html
@@ -4,5 +4,10 @@
 streamed.  It also illustrates how to use the notification system to indicate
 an ongoing task and how to deal with audio focus changes.</p>
 
+<p><strong>Update:</strong> This sample also illustrates how to use the
+<code><a href="../../../reference/android/media/RemoteControlClient.html">RemoteControlClient</a></code>
+class added in API level 14 to integrate with music playback remote controls
+such as those found on the lockscreen.</p>
+
 <img alt="" src="../images/randommusicplayer.png" />
 
diff --git a/samples/RandomMusicPlayer/default.properties b/samples/RandomMusicPlayer/default.properties
deleted file mode 100644
index e2e8061..0000000
--- a/samples/RandomMusicPlayer/default.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system use,
-# "build.properties", and override values to adapt the script to your
-# project structure.
-
-# Project target.
-target=android-8
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi-v11/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-hdpi-v11/ic_stat_playing.png
new file mode 100755
index 0000000..cc62c29
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi-v11/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi-v9/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-hdpi-v9/ic_stat_playing.png
old mode 100644
new mode 100755
index d111aab..9351f4b
--- a/samples/RandomMusicPlayer/res/drawable-hdpi-v9/ic_stat_playing.png
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi-v9/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/ic_launcher.png b/samples/RandomMusicPlayer/res/drawable-hdpi/ic_launcher.png
old mode 100644
new mode 100755
index abd9055..972c791
--- a/samples/RandomMusicPlayer/res/drawable-hdpi/ic_launcher.png
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-hdpi/ic_stat_playing.png
old mode 100644
new mode 100755
index c1dd9da..099c44e
--- a/samples/RandomMusicPlayer/res/drawable-hdpi/ic_stat_playing.png
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_eject.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_eject.xml
deleted file mode 100644
index 300e75a..0000000
--- a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_eject.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/eject_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/eject_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/eject" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_ff.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_ff.xml
deleted file mode 100644
index 2d399b4..0000000
--- a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_ff.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/ff_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/ff_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/ff" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_pause.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_pause.xml
deleted file mode 100644
index 2d6c4be..0000000
--- a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_pause.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/pause_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/pause_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/pause" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_play.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_play.xml
deleted file mode 100644
index d2eea02..0000000
--- a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_play.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/play_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/play_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/play" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_rew.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_rew.xml
deleted file mode 100644
index 5f5f88a..0000000
--- a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_rew.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/rew_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/rew_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/rew" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_stop.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_stop.xml
deleted file mode 100644
index 5778417..0000000
--- a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_stop.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/stop_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/stop_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/stop" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-ldpi-v9/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-ldpi-v9/ic_stat_playing.png
deleted file mode 100644
index 6a40823..0000000
--- a/samples/RandomMusicPlayer/res/drawable-ldpi-v9/ic_stat_playing.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-ldpi/ic_launcher.png b/samples/RandomMusicPlayer/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index 6f1277a..0000000
--- a/samples/RandomMusicPlayer/res/drawable-ldpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-ldpi/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-ldpi/ic_stat_playing.png
deleted file mode 100644
index fb21884..0000000
--- a/samples/RandomMusicPlayer/res/drawable-ldpi/ic_stat_playing.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi-v11/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-mdpi-v11/ic_stat_playing.png
new file mode 100755
index 0000000..049ff3d
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi-v11/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi-v9/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-mdpi-v9/ic_stat_playing.png
old mode 100644
new mode 100755
index b5a66df..7970cb9
--- a/samples/RandomMusicPlayer/res/drawable-mdpi-v9/ic_stat_playing.png
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi-v9/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/eject.png b/samples/RandomMusicPlayer/res/drawable-mdpi/eject.png
deleted file mode 100644
index 650b38a..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/eject.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/eject_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/eject_pressed.png
deleted file mode 100644
index 065b30d..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/eject_pressed.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/ff.png b/samples/RandomMusicPlayer/res/drawable-mdpi/ff.png
deleted file mode 100644
index 508f741..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/ff.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/ff_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/ff_pressed.png
deleted file mode 100644
index 468ae8e..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/ff_pressed.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/ic_launcher.png b/samples/RandomMusicPlayer/res/drawable-mdpi/ic_launcher.png
old mode 100644
new mode 100755
index abd9055..01b53fd
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/ic_launcher.png
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-mdpi/ic_stat_playing.png
old mode 100644
new mode 100755
index c1dd9da..5ffc8cc
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/ic_stat_playing.png
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/pause.png b/samples/RandomMusicPlayer/res/drawable-mdpi/pause.png
deleted file mode 100644
index 13581de..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/pause.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/pause_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/pause_pressed.png
deleted file mode 100644
index 9ddd07d..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/pause_pressed.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/play.png b/samples/RandomMusicPlayer/res/drawable-mdpi/play.png
deleted file mode 100644
index e34b48e..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/play.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/play_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/play_pressed.png
deleted file mode 100644
index 790cd29..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/play_pressed.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/rew.png b/samples/RandomMusicPlayer/res/drawable-mdpi/rew.png
deleted file mode 100644
index 26864b7..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/rew.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/rew_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/rew_pressed.png
deleted file mode 100644
index 54c38a7..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/rew_pressed.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_eject.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_eject.xml
deleted file mode 100644
index 300e75a..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_eject.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/eject_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/eject_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/eject" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_ff.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_ff.xml
deleted file mode 100644
index 2d399b4..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_ff.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/ff_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/ff_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/ff" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_pause.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_pause.xml
deleted file mode 100644
index 2d6c4be..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_pause.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/pause_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/pause_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/pause" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_play.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_play.xml
deleted file mode 100644
index d2eea02..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_play.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/play_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/play_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/play" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_rew.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_rew.xml
deleted file mode 100644
index 5f5f88a..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_rew.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/rew_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/rew_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/rew" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_stop.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_stop.xml
deleted file mode 100644
index 5778417..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_stop.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
-     <item android:state_pressed="true"
-           android:drawable="@drawable/stop_pressed" /> <!-- pressed -->
-     <item android:state_focused="true"
-           android:drawable="@drawable/stop_pressed" /> <!-- focused -->
-     <item android:drawable="@drawable/stop" /> <!-- default -->
- </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/stop.png b/samples/RandomMusicPlayer/res/drawable-mdpi/stop.png
deleted file mode 100644
index 45eff23..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/stop.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/stop_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/stop_pressed.png
deleted file mode 100644
index c7bda81..0000000
--- a/samples/RandomMusicPlayer/res/drawable-mdpi/stop_pressed.png
+++ /dev/null
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-nodpi/dummy_album_art.png b/samples/RandomMusicPlayer/res/drawable-nodpi/dummy_album_art.png
new file mode 100644
index 0000000..e50b97e
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-nodpi/dummy_album_art.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-xhdpi-v11/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-xhdpi-v11/ic_stat_playing.png
new file mode 100755
index 0000000..f940498
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-xhdpi-v11/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-xhdpi-v9/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-xhdpi-v9/ic_stat_playing.png
new file mode 100755
index 0000000..d0f2a2b
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-xhdpi-v9/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-xhdpi/ic_launcher.png b/samples/RandomMusicPlayer/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..af762f2
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-xhdpi/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-xhdpi/ic_stat_playing.png
new file mode 100755
index 0000000..aa46a0c
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-xhdpi/ic_stat_playing.png
Binary files differ
diff --git a/samples/HoneycombGallery/res/layout/action_bar_custom.xml b/samples/RandomMusicPlayer/res/drawable/btn_eject.xml
similarity index 63%
copy from samples/HoneycombGallery/res/layout/action_bar_custom.xml
copy to samples/RandomMusicPlayer/res/drawable/btn_eject.xml
index 5f111d9..e3e40ae 100644
--- a/samples/HoneycombGallery/res/layout/action_bar_custom.xml
+++ b/samples/RandomMusicPlayer/res/drawable/btn_eject.xml
@@ -12,13 +12,10 @@
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
- -->
+  -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">Hello Action Bar</TextView>
-</LinearLayout>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:drawable="@drawable/eject_pressed" />
+    <item android:state_focused="true" android:drawable="@drawable/eject_pressed" />
+    <item android:drawable="@drawable/eject" />
+</selector>
diff --git a/samples/HoneycombGallery/res/layout/action_bar_custom.xml b/samples/RandomMusicPlayer/res/drawable/btn_ff.xml
similarity index 63%
copy from samples/HoneycombGallery/res/layout/action_bar_custom.xml
copy to samples/RandomMusicPlayer/res/drawable/btn_ff.xml
index 5f111d9..c87fa06 100644
--- a/samples/HoneycombGallery/res/layout/action_bar_custom.xml
+++ b/samples/RandomMusicPlayer/res/drawable/btn_ff.xml
@@ -12,13 +12,10 @@
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
- -->
+  -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">Hello Action Bar</TextView>
-</LinearLayout>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:drawable="@drawable/ff_pressed" />
+    <item android:state_focused="true" android:drawable="@drawable/ff_pressed" />
+    <item android:drawable="@drawable/ff" />
+</selector>
diff --git a/samples/HoneycombGallery/res/layout/action_bar_custom.xml b/samples/RandomMusicPlayer/res/drawable/btn_pause.xml
similarity index 63%
copy from samples/HoneycombGallery/res/layout/action_bar_custom.xml
copy to samples/RandomMusicPlayer/res/drawable/btn_pause.xml
index 5f111d9..7aadd2f 100644
--- a/samples/HoneycombGallery/res/layout/action_bar_custom.xml
+++ b/samples/RandomMusicPlayer/res/drawable/btn_pause.xml
@@ -12,13 +12,10 @@
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
- -->
+  -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">Hello Action Bar</TextView>
-</LinearLayout>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:drawable="@drawable/pause_pressed" />
+    <item android:state_focused="true" android:drawable="@drawable/pause_pressed" />
+    <item android:drawable="@drawable/pause" />
+</selector>
diff --git a/samples/HoneycombGallery/res/layout/action_bar_custom.xml b/samples/RandomMusicPlayer/res/drawable/btn_play.xml
similarity index 63%
copy from samples/HoneycombGallery/res/layout/action_bar_custom.xml
copy to samples/RandomMusicPlayer/res/drawable/btn_play.xml
index 5f111d9..dc319c5 100644
--- a/samples/HoneycombGallery/res/layout/action_bar_custom.xml
+++ b/samples/RandomMusicPlayer/res/drawable/btn_play.xml
@@ -12,13 +12,10 @@
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
- -->
+  -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">Hello Action Bar</TextView>
-</LinearLayout>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:drawable="@drawable/play_pressed" />
+    <item android:state_focused="true" android:drawable="@drawable/play_pressed" />
+    <item android:drawable="@drawable/play" />
+</selector>
diff --git a/samples/HoneycombGallery/res/layout/action_bar_custom.xml b/samples/RandomMusicPlayer/res/drawable/btn_rew.xml
similarity index 63%
copy from samples/HoneycombGallery/res/layout/action_bar_custom.xml
copy to samples/RandomMusicPlayer/res/drawable/btn_rew.xml
index 5f111d9..cc4dad8 100644
--- a/samples/HoneycombGallery/res/layout/action_bar_custom.xml
+++ b/samples/RandomMusicPlayer/res/drawable/btn_rew.xml
@@ -12,13 +12,10 @@
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
- -->
+  -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">Hello Action Bar</TextView>
-</LinearLayout>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:drawable="@drawable/rew_pressed" />
+    <item android:state_focused="true" android:drawable="@drawable/rew_pressed" />
+    <item android:drawable="@drawable/rew" />
+</selector>
diff --git a/samples/HoneycombGallery/res/layout/action_bar_custom.xml b/samples/RandomMusicPlayer/res/drawable/btn_stop.xml
similarity index 63%
copy from samples/HoneycombGallery/res/layout/action_bar_custom.xml
copy to samples/RandomMusicPlayer/res/drawable/btn_stop.xml
index 5f111d9..5ce2d17 100644
--- a/samples/HoneycombGallery/res/layout/action_bar_custom.xml
+++ b/samples/RandomMusicPlayer/res/drawable/btn_stop.xml
@@ -12,13 +12,10 @@
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
- -->
+  -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">Hello Action Bar</TextView>
-</LinearLayout>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:drawable="@drawable/stop_pressed" />
+    <item android:state_focused="true" android:drawable="@drawable/stop_pressed" />
+    <item android:drawable="@drawable/stop" />
+</selector>
diff --git a/samples/RandomMusicPlayer/res/layout-land/main.xml b/samples/RandomMusicPlayer/res/layout-land/main.xml
index c9072bf..b8070bb 100644
--- a/samples/RandomMusicPlayer/res/layout-land/main.xml
+++ b/samples/RandomMusicPlayer/res/layout-land/main.xml
@@ -1,83 +1,68 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+  Copyright (C) 2011 The Android Open Source Project
 
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
 
-          http://www.apache.org/licenses/LICENSE-2.0
+       http://www.apache.org/licenses/LICENSE-2.0
 
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:gravity="center"
-    android:background="#000040"
-    >
+    android:background="#000040">
 
-<TextView android:text="Random Music Player"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:padding="20dp"
-          android:textColor="#ffffff"
-          android:textSize="20sp"
-          android:textStyle="bold"
-          />
+    <TextView android:text="@string/app_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="20dp"
+        android:textColor="#ffffff"
+        android:textSize="20sp"
+        android:textStyle="bold" />
 
-<LinearLayout
-    android:orientation="horizontal"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    >
-<Button
-    android:id="@+id/rewindbutton"
-    android:background="@drawable/selector_rew"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-<Button
-    android:id="@+id/playbutton"
-    android:background="@drawable/selector_play"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-<Button
-    android:id="@+id/pausebutton"
-    android:background="@drawable/selector_pause"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-<Button
-    android:id="@+id/skipbutton"
-    android:background="@drawable/selector_ff"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-<Button
-    android:id="@+id/stopbutton"
-    android:background="@drawable/selector_stop"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-<Button
-    android:id="@+id/ejectbutton"
-    android:background="@drawable/selector_eject"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
+    <LinearLayout android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center">
+        <Button android:id="@+id/rewindbutton"
+            android:background="@drawable/btn_rew"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+        <Button android:id="@+id/playbutton"
+            android:background="@drawable/btn_play"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+        <Button android:id="@+id/pausebutton"
+            android:background="@drawable/btn_pause"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+        <Button android:id="@+id/skipbutton"
+            android:background="@drawable/btn_ff"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+        <Button android:id="@+id/stopbutton"
+            android:background="@drawable/btn_stop"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+        <Button android:id="@+id/ejectbutton"
+            android:background="@drawable/btn_eject"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
 
-</LinearLayout>
+    </LinearLayout>
 </LinearLayout>
diff --git a/samples/RandomMusicPlayer/res/layout-port/main.xml b/samples/RandomMusicPlayer/res/layout-port/main.xml
deleted file mode 100644
index ab86ae5..0000000
--- a/samples/RandomMusicPlayer/res/layout-port/main.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License. -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:gravity="center"
-    android:background="#000040"
-    >
-
-<TextView android:text="Random Music Player"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:padding="20dp"
-          android:textColor="#ffffff"
-          android:textSize="20sp"
-          android:textStyle="bold"
-          />
-
-<LinearLayout
-    android:orientation="horizontal"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    android:layout_margin="10dp"
-    >
-<Button
-    android:id="@+id/rewindbutton"
-    android:background="@drawable/selector_rew"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-<Button
-    android:id="@+id/playbutton"
-    android:background="@drawable/selector_play"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-<Button
-    android:id="@+id/pausebutton"
-    android:background="@drawable/selector_pause"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-<Button
-    android:id="@+id/skipbutton"
-    android:background="@drawable/selector_ff"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-</LinearLayout>
-
-<LinearLayout
-    android:orientation="horizontal"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    android:layout_margin="10dp"
-    >
-<Button
-    android:id="@+id/stopbutton"
-    android:background="@drawable/selector_stop"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-<Button
-    android:id="@+id/ejectbutton"
-    android:background="@drawable/selector_eject"
-    android:layout_width="64dp"
-    android:layout_height="64dp"
-    android:layout_margin="5dp"
-    />
-
-</LinearLayout>
-</LinearLayout>
diff --git a/samples/RandomMusicPlayer/res/layout/main.xml b/samples/RandomMusicPlayer/res/layout/main.xml
new file mode 100644
index 0000000..a41a710
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/layout/main.xml
@@ -0,0 +1,76 @@
+<!--
+  Copyright (C) 2011 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:gravity="center"
+    android:background="#000040">
+
+    <TextView android:text="@string/app_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="20dp"
+        android:textColor="#ffffff"
+        android:textSize="20sp"
+        android:textStyle="bold" />
+
+    <LinearLayout android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:layout_margin="10dp">
+        <Button android:id="@+id/rewindbutton"
+            android:background="@drawable/btn_rew"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+        <Button android:id="@+id/playbutton"
+            android:background="@drawable/btn_play"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+        <Button android:id="@+id/pausebutton"
+            android:background="@drawable/btn_pause"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+        <Button android:id="@+id/skipbutton"
+            android:background="@drawable/btn_ff"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+    </LinearLayout>
+
+    <LinearLayout android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:layout_margin="10dp">
+        <Button android:id="@+id/stopbutton"
+            android:background="@drawable/btn_stop"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+        <Button android:id="@+id/ejectbutton"
+            android:background="@drawable/btn_eject"
+            android:layout_width="64dp"
+            android:layout_height="64dp"
+            android:layout_margin="5dp" />
+
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/HoneycombGallery/res/layout/action_bar_custom.xml b/samples/RandomMusicPlayer/res/values/strings.xml
similarity index 63%
copy from samples/HoneycombGallery/res/layout/action_bar_custom.xml
copy to samples/RandomMusicPlayer/res/values/strings.xml
index 5f111d9..39db75e 100644
--- a/samples/HoneycombGallery/res/layout/action_bar_custom.xml
+++ b/samples/RandomMusicPlayer/res/values/strings.xml
@@ -12,13 +12,8 @@
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
- -->
+  -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">Hello Action Bar</TextView>
-</LinearLayout>
+<resources>
+    <string name="app_title">Random Music Player</string>
+</resources>
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/AudioFocusHelper.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/AudioFocusHelper.java
index 4b8b54a..980bac8 100644
--- a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/AudioFocusHelper.java
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/AudioFocusHelper.java
@@ -51,7 +51,6 @@
      * Called by AudioManager on audio focus changes. We implement this by calling our
      * MusicFocusable appropriately to relay the message.
      */
-    @Override
     public void onAudioFocusChange(int focusChange) {
         if (mFocusable == null) return;
         switch (focusChange) {
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MainActivity.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MainActivity.java
index 4974a21..4d5224b 100644
--- a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MainActivity.java
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MainActivity.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
+import android.view.KeyEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
@@ -71,7 +72,6 @@
         mEjectButton.setOnClickListener(this);
     }
 
-    @Override
     public void onClick(View target) {
         // Send the correct intent to the MusicService, according to the button that was clicked
         if (target == mPlayButton)
@@ -119,4 +119,15 @@
 
         alertBuilder.show();
     }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+                startService(new Intent(MusicService.ACTION_TOGGLE_PLAYBACK));
+                return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
 }
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MediaButtonHelper.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MediaButtonHelper.java
new file mode 100644
index 0000000..1bacee5
--- /dev/null
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MediaButtonHelper.java
@@ -0,0 +1,85 @@
+package com.example.android.musicplayer;
+
+import android.content.ComponentName;
+import android.media.AudioManager;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Class that assists with handling new media button APIs available in API level 8.
+ */
+public class MediaButtonHelper {
+    // Backwards compatibility code (methods available as of API Level 8)
+    private static final String TAG = "MediaButtonHelper";
+
+    static {
+        initializeStaticCompatMethods();
+    }
+
+    static Method sMethodRegisterMediaButtonEventReceiver;
+    static Method sMethodUnregisterMediaButtonEventReceiver;
+
+    static void initializeStaticCompatMethods() {
+        try {
+            sMethodRegisterMediaButtonEventReceiver = AudioManager.class.getMethod(
+                    "registerMediaButtonEventReceiver",
+                    new Class[] { ComponentName.class });
+            sMethodUnregisterMediaButtonEventReceiver = AudioManager.class.getMethod(
+                    "unregisterMediaButtonEventReceiver",
+                    new Class[] { ComponentName.class });
+        } catch (NoSuchMethodException e) {
+            // Silently fail when running on an OS before API level 8.
+        }
+    }
+
+    public static void registerMediaButtonEventReceiverCompat(AudioManager audioManager,
+            ComponentName receiver) {
+        if (sMethodRegisterMediaButtonEventReceiver == null)
+            return;
+
+        try {
+            sMethodRegisterMediaButtonEventReceiver.invoke(audioManager, receiver);
+        } catch (InvocationTargetException e) {
+            // Unpack original exception when possible
+            Throwable cause = e.getCause();
+            if (cause instanceof RuntimeException) {
+                throw (RuntimeException) cause;
+            } else if (cause instanceof Error) {
+                throw (Error) cause;
+            } else {
+                // Unexpected checked exception; wrap and re-throw
+                throw new RuntimeException(e);
+            }
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "IllegalAccessException invoking registerMediaButtonEventReceiver.");
+            e.printStackTrace();
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static void unregisterMediaButtonEventReceiverCompat(AudioManager audioManager,
+            ComponentName receiver) {
+        if (sMethodUnregisterMediaButtonEventReceiver == null)
+            return;
+
+        try {
+            sMethodUnregisterMediaButtonEventReceiver.invoke(audioManager, receiver);
+        } catch (InvocationTargetException e) {
+            // Unpack original exception when possible
+            Throwable cause = e.getCause();
+            if (cause instanceof RuntimeException) {
+                throw (RuntimeException) cause;
+            } else if (cause instanceof Error) {
+                throw (Error) cause;
+            } else {
+                // Unexpected checked exception; wrap and re-throw
+                throw new RuntimeException(e);
+            }
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "IllegalAccessException invoking unregisterMediaButtonEventReceiver.");
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicIntentReceiver.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicIntentReceiver.java
index cc03d5e..28f19d4 100644
--- a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicIntentReceiver.java
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicIntentReceiver.java
@@ -19,22 +19,53 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.util.Log;
+import android.view.KeyEvent;
 import android.widget.Toast;
 
 /**
  * Receives broadcasted intents. In particular, we are interested in the
- * android.media.AUDIO_BECOMING_NOISY intent, which is broadcast, for example, when the user
- * disconnects the headphones. This class works because we are declaring it in a &lt;receiver&gt;
- * tag in AndroidManifest.xml.
+ * android.media.AUDIO_BECOMING_NOISY and android.intent.action.MEDIA_BUTTON intents, which is
+ * broadcast, for example, when the user disconnects the headphones. This class works because we are
+ * declaring it in a &lt;receiver&gt; tag in AndroidManifest.xml.
  */
 public class MusicIntentReceiver extends BroadcastReceiver {
     @Override
-    public void onReceive(Context ctx, Intent intent) {
+    public void onReceive(Context context, Intent intent) {
         if (intent.getAction().equals(android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
-            Toast.makeText(ctx, "Headphones disconnected.", Toast.LENGTH_SHORT).show();
+            Toast.makeText(context, "Headphones disconnected.", Toast.LENGTH_SHORT).show();
 
             // send an intent to our MusicService to telling it to pause the audio
-            ctx.startService(new Intent(MusicService.ACTION_PAUSE));
+            context.startService(new Intent(MusicService.ACTION_PAUSE));
+
+        } else if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) {
+            KeyEvent keyEvent = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
+            if (keyEvent.getAction() != KeyEvent.ACTION_DOWN)
+                return;
+
+            switch (keyEvent.getKeyCode()) {
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                    context.startService(new Intent(MusicService.ACTION_TOGGLE_PLAYBACK));
+                    break;
+                case KeyEvent.KEYCODE_MEDIA_PLAY:
+                    context.startService(new Intent(MusicService.ACTION_PLAY));
+                    break;
+                case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                    context.startService(new Intent(MusicService.ACTION_PAUSE));
+                    break;
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                    context.startService(new Intent(MusicService.ACTION_STOP));
+                    break;
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                    context.startService(new Intent(MusicService.ACTION_SKIP));
+                    break;
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                    // TODO: ensure that doing this in rapid succession actually plays the
+                    // previous song
+                    context.startService(new Intent(MusicService.ACTION_REWIND));
+                    break;
+            }
         }
     }
 }
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicRetriever.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicRetriever.java
index 44d6447..5e6f2f1 100644
--- a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicRetriever.java
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicRetriever.java
@@ -16,16 +16,17 @@
 
 package com.example.android.musicplayer;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.database.Cursor;
 import android.net.Uri;
+import android.provider.MediaStore;
 import android.util.Log;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
 /**
  * Retrieves and organizes media to play. Before being used, you must call {@link #prepare()},
  * which will retrieve all of the music on the user's device (by performing a query on a content
@@ -57,7 +58,8 @@
 
         // Perform a query on the content resolver. The URI we're passing specifies that we
         // want to query for all audio media on external storage (e.g. SD card)
-        Cursor cur = mContentResolver.query(uri, null, null, null, null);
+        Cursor cur = mContentResolver.query(uri, null,
+                MediaStore.Audio.Media.IS_MUSIC + " = 1", null, null);
         Log.i(TAG, "Query finished. " + (cur == null ? "Returned NULL." : "Returned a cursor."));
 
         if (cur == null) {
@@ -73,9 +75,12 @@
 
         Log.i(TAG, "Listing...");
 
-        // retrieve the indices of the columns where the ID and title of the song are
-        int titleColumn = cur.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
-        int idColumn = cur.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
+        // retrieve the indices of the columns where the ID, title, etc. of the song are
+        int artistColumn = cur.getColumnIndex(MediaStore.Audio.Media.ARTIST);
+        int titleColumn = cur.getColumnIndex(MediaStore.Audio.Media.TITLE);
+        int albumColumn = cur.getColumnIndex(MediaStore.Audio.Media.ALBUM);
+        int durationColumn = cur.getColumnIndex(MediaStore.Audio.Media.DURATION);
+        int idColumn = cur.getColumnIndex(MediaStore.Audio.Media._ID);
 
         Log.i(TAG, "Title column index: " + String.valueOf(titleColumn));
         Log.i(TAG, "ID column index: " + String.valueOf(titleColumn));
@@ -83,7 +88,12 @@
         // add each song to mItems
         do {
             Log.i(TAG, "ID: " + cur.getString(idColumn) + " Title: " + cur.getString(titleColumn));
-            mItems.add(new Item(cur.getLong(idColumn), cur.getString(titleColumn)));
+            mItems.add(new Item(
+                    cur.getLong(idColumn),
+                    cur.getString(artistColumn),
+                    cur.getString(titleColumn),
+                    cur.getString(albumColumn),
+                    cur.getLong(durationColumn)));
         } while (cur.moveToNext());
 
         Log.i(TAG, "Done querying media. MusicRetriever is ready.");
@@ -99,17 +109,41 @@
         return mItems.get(mRandom.nextInt(mItems.size()));
     }
 
-    public class Item {
+    public static class Item {
         long id;
+        String artist;
         String title;
+        String album;
+        long duration;
 
-        public Item(long id, String title) {
+        public Item(long id, String artist, String title, String album, long duration) {
             this.id = id;
+            this.artist = artist;
             this.title = title;
+            this.album = album;
+            this.duration = duration;
         }
 
-        public long getId() { return id; }
-        public String getTitle() { return title; }
+        public long getId() {
+            return id;
+        }
+
+        public String getArtist() {
+            return artist;
+        }
+
+        public String getTitle() {
+            return title;
+        }
+
+        public String getAlbum() {
+            return album;
+        }
+
+        public long getDuration() {
+            return duration;
+        }
+
         public Uri getURI() {
             return ContentUris.withAppendedId(
                     android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicService.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicService.java
index 9bd1251..25f5d81 100644
--- a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicService.java
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicService.java
@@ -16,19 +16,22 @@
 
 package com.example.android.musicplayer;
 
-import java.io.IOException;
-
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.media.AudioManager;
+import android.media.MediaMetadataRetriever;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.media.MediaPlayer.OnPreparedListener;
+import android.media.RemoteControlClient;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.WifiLock;
@@ -37,9 +40,11 @@
 import android.util.Log;
 import android.widget.Toast;
 
+import java.io.IOException;
+
 /**
  * Service that handles media playback. This is the Service through which we perform all the media
- * handling in our application. Upon initialization, it starts a {@link MediaRetriever} to scan
+ * handling in our application. Upon initialization, it starts a {@link MusicRetriever} to scan
  * the user's media. Then, it waits for Intents (which come from our main activity,
  * {@link MainActivity}, which signal the service to perform specific operations: Play, Pause,
  * Rewind, Skip, etc.
@@ -48,7 +53,25 @@
                 OnErrorListener, MusicFocusable,
                 PrepareMusicRetrieverTask.MusicRetrieverPreparedListener {
 
-    NotificationManager mNotificationManager;
+    // The tag we put on debug messages
+    final static String TAG = "RandomMusicPlayer";
+
+    // These are the Intent actions that we are prepared to handle. Notice that the fact these
+    // constants exist in our class is a mere convenience: what really defines the actions our
+    // service can handle are the <action> tags in the <intent-filters> tag for our service in
+    // AndroidManifest.xml.
+    public static final String ACTION_TOGGLE_PLAYBACK =
+            "com.example.android.musicplayer.action.TOGGLE_PLAYBACK";
+    public static final String ACTION_PLAY = "com.example.android.musicplayer.action.PLAY";
+    public static final String ACTION_PAUSE = "com.example.android.musicplayer.action.PAUSE";
+    public static final String ACTION_STOP = "com.example.android.musicplayer.action.STOP";
+    public static final String ACTION_SKIP = "com.example.android.musicplayer.action.SKIP";
+    public static final String ACTION_REWIND = "com.example.android.musicplayer.action.REWIND";
+    public static final String ACTION_URL = "com.example.android.musicplayer.action.URL";
+
+    // The volume we set the media player to when we lose audio focus, but are allowed to reduce
+    // the volume instead of stopping playback.
+    public static final float DUCK_VOLUME = 0.1f;
 
     // our media player
     MediaPlayer mPlayer = null;
@@ -104,24 +127,6 @@
     // device from shutting off the Wifi radio
     WifiLock mWifiLock;
 
-    // The tag we put on debug messages
-    final static String TAG = "RandomMusicPlayer";
-
-    // These are the Intent actions that we are prepared to handle. Notice that the fact these
-    // constants exist in our class is a mere convenience: what really defines the actions our
-    // service can handle are the <action> tags in the <intent-filters> tag for our service in
-    // AndroidManifest.xml.
-    public static final String ACTION_PLAY = "com.example.android.musicplayer.action.PLAY";
-    public static final String ACTION_PAUSE = "com.example.android.musicplayer.action.PAUSE";
-    public static final String ACTION_STOP = "com.example.android.musicplayer.action.STOP";
-    public static final String ACTION_SKIP = "com.example.android.musicplayer.action.SKIP";
-    public static final String ACTION_REWIND = "com.example.android.musicplayer.action.REWIND";
-    public static final String ACTION_URL = "com.example.android.musicplayer.action.URL";
-
-    // The volume we set the media player to when we lose audio focus, but are allowed to reduce
-    // the volume instead of stopping playback.
-    public final float DUCK_VOLUME = 0.1f;
-
     // The ID we use for the notification (the onscreen alert that appears at the notification
     // area at the top of the screen as an icon -- and as text as well if the user expands the
     // notification area).
@@ -131,6 +136,20 @@
     // providing titles and URIs as we need.
     MusicRetriever mRetriever;
 
+    // our RemoteControlClient object, which will use remote control APIs available in
+    // SDK level >= 14, if they're available.
+    RemoteControlClientCompat mRemoteControlClientCompat;
+
+    // Dummy album art we will pass to the remote control (if the APIs are available).
+    Bitmap mDummyAlbumArt;
+
+    // The component name of MusicIntentReceiver, for use with media button and remote control
+    // APIs
+    ComponentName mMediaButtonReceiverComponent;
+
+    AudioManager mAudioManager;
+    NotificationManager mNotificationManager;
+
     Notification mNotification = null;
 
     /**
@@ -167,6 +186,7 @@
                         .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
 
         mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+        mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
 
         // Create the retriever and start an asynchronous task that will prepare it.
         mRetriever = new MusicRetriever(getContentResolver());
@@ -177,6 +197,10 @@
             mAudioFocusHelper = new AudioFocusHelper(getApplicationContext(), this);
         else
             mAudioFocus = AudioFocus.Focused; // no focus feature, so we always "have" audio focus
+
+        mDummyAlbumArt = BitmapFactory.decodeResource(getResources(), R.drawable.dummy_album_art);
+
+        mMediaButtonReceiverComponent = new ComponentName(this, MusicIntentReceiver.class);
     }
 
     /**
@@ -187,7 +211,8 @@
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         String action = intent.getAction();
-        if (action.equals(ACTION_PLAY)) processPlayRequest();
+        if (action.equals(ACTION_TOGGLE_PLAYBACK)) processTogglePlaybackRequest();
+        else if (action.equals(ACTION_PLAY)) processPlayRequest();
         else if (action.equals(ACTION_PAUSE)) processPauseRequest();
         else if (action.equals(ACTION_SKIP)) processSkipRequest();
         else if (action.equals(ACTION_STOP)) processStopRequest();
@@ -198,6 +223,14 @@
                                  // restart in case it's killed.
     }
 
+    void processTogglePlaybackRequest() {
+        if (mState == State.Paused || mState == State.Stopped) {
+            processPlayRequest();
+        } else {
+            processPauseRequest();
+        }
+    }
+
     void processPlayRequest() {
         if (mState == State.Retrieving) {
             // If we are still retrieving media, just set the flag to start playing when we're
@@ -209,6 +242,8 @@
 
         tryToGetAudioFocus();
 
+        // actually play the song
+
         if (mState == State.Stopped) {
             // If we're stopped, just go ahead to the next song and start playing
             playNextSong(null);
@@ -219,6 +254,12 @@
             setUpAsForeground(mSongTitle + " (playing)");
             configAndStartMediaPlayer();
         }
+
+        // Tell any remote controls that our playback state is 'playing'.
+        if (mRemoteControlClientCompat != null) {
+            mRemoteControlClientCompat
+                    .setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
+        }
     }
 
     void processPauseRequest() {
@@ -234,7 +275,13 @@
             mState = State.Paused;
             mPlayer.pause();
             relaxResources(false); // while paused, we always retain the MediaPlayer
-            giveUpAudioFocus();
+            // do not give up audio focus
+        }
+
+        // Tell any remote controls that our playback state is 'paused'.
+        if (mRemoteControlClientCompat != null) {
+            mRemoteControlClientCompat
+                    .setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED);
         }
     }
 
@@ -251,13 +298,23 @@
     }
 
     void processStopRequest() {
-        if (mState == State.Playing || mState == State.Paused) {
+        processStopRequest(false);
+    }
+
+    void processStopRequest(boolean force) {
+        if (mState == State.Playing || mState == State.Paused || force) {
             mState = State.Stopped;
 
             // let go of all resources...
             relaxResources(true);
             giveUpAudioFocus();
 
+            // Tell any remote controls that our playback state is 'paused'.
+            if (mRemoteControlClientCompat != null) {
+                mRemoteControlClientCompat
+                        .setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED);
+            }
+
             // service is no longer necessary. Will be started again if needed.
             stopSelf();
         }
@@ -330,14 +387,6 @@
         }
     }
 
-    /**
-     * Shortcut to making and displaying a toast. Seemed cleaner than repeating
-     * this code everywhere, at least for this sample.
-     */
-    void say(String message) {
-        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
-    }
-
     void tryToGetAudioFocus() {
         if (mAudioFocus != AudioFocus.Focused && mAudioFocusHelper != null
                         && mAudioFocusHelper.requestFocus())
@@ -355,34 +404,80 @@
         relaxResources(false); // release everything except MediaPlayer
 
         try {
+            MusicRetriever.Item playingItem = null;
             if (manualUrl != null) {
                 // set the source of the media player to a manual URL or path
                 createMediaPlayerIfNeeded();
                 mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                 mPlayer.setDataSource(manualUrl);
-                mSongTitle = manualUrl;
                 mIsStreaming = manualUrl.startsWith("http:") || manualUrl.startsWith("https:");
+
+                playingItem = new MusicRetriever.Item(0, null, manualUrl, null, 0);
             }
             else {
                 mIsStreaming = false; // playing a locally available song
 
-                MusicRetriever.Item item = mRetriever.getRandomItem();
-                if (item == null) {
-                    say("No song to play :-(");
+                playingItem = mRetriever.getRandomItem();
+                if (playingItem == null) {
+                    Toast.makeText(this,
+                            "No available music to play. Place some music on your external storage "
+                            + "device (e.g. your SD card) and try again.",
+                            Toast.LENGTH_LONG).show();
+                    processStopRequest(true); // stop everything!
                     return;
                 }
 
                 // set the source of the media player a a content URI
                 createMediaPlayerIfNeeded();
                 mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
-                mPlayer.setDataSource(getApplicationContext(), item.getURI());
-                mSongTitle = item.getTitle();
+                mPlayer.setDataSource(getApplicationContext(), playingItem.getURI());
             }
 
+            mSongTitle = playingItem.getTitle();
 
             mState = State.Preparing;
             setUpAsForeground(mSongTitle + " (loading)");
 
+            // Use the media button APIs (if available) to register ourselves for media button
+            // events
+
+            MediaButtonHelper.registerMediaButtonEventReceiverCompat(
+                    mAudioManager, mMediaButtonReceiverComponent);
+
+            // Use the remote control APIs (if available) to set the playback state
+
+            if (mRemoteControlClientCompat == null) {
+                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+                intent.setComponent(mMediaButtonReceiverComponent);
+                mRemoteControlClientCompat = new RemoteControlClientCompat(
+                        PendingIntent.getBroadcast(this /*context*/,
+                                0 /*requestCode, ignored*/, intent /*intent*/, 0 /*flags*/));
+                RemoteControlHelper.registerRemoteControlClient(mAudioManager,
+                        mRemoteControlClientCompat);
+            }
+
+            mRemoteControlClientCompat.setPlaybackState(
+                    RemoteControlClient.PLAYSTATE_PLAYING);
+
+            mRemoteControlClientCompat.setTransportControlFlags(
+                    RemoteControlClient.FLAG_KEY_MEDIA_PLAY |
+                    RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
+                    RemoteControlClient.FLAG_KEY_MEDIA_NEXT |
+                    RemoteControlClient.FLAG_KEY_MEDIA_STOP);
+
+            // Update the remote controls
+            mRemoteControlClientCompat.editMetadata(true)
+                    .putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, playingItem.getArtist())
+                    .putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, playingItem.getAlbum())
+                    .putString(MediaMetadataRetriever.METADATA_KEY_TITLE, playingItem.getTitle())
+                    .putLong(MediaMetadataRetriever.METADATA_KEY_DURATION,
+                            playingItem.getDuration())
+                    // TODO: fetch real item artwork
+                    .putBitmap(
+                            RemoteControlClientCompat.MetadataEditorCompat.METADATA_KEY_ARTWORK,
+                            mDummyAlbumArt)
+                    .apply();
+
             // starts preparing the media player in the background. When it's done, it will call
             // our OnPreparedListener (that is, the onPrepared() method on this class, since we set
             // the listener to 'this').
@@ -403,14 +498,12 @@
     }
 
     /** Called when media player is done playing current song. */
-    @Override
     public void onCompletion(MediaPlayer player) {
         // The media player finished playing the current song, so we go ahead and start the next.
         playNextSong(null);
     }
 
     /** Called when media player is done preparing. */
-    @Override
     public void onPrepared(MediaPlayer player) {
         // The media player is done preparing. That means we can start playing!
         mState = State.Playing;
@@ -449,7 +542,6 @@
      * Called when there's an error playing media. When this happens, the media player goes to
      * the Error state. We warn the user about the error and reset the media player.
      */
-    @Override
     public boolean onError(MediaPlayer mp, int what, int extra) {
         Toast.makeText(getApplicationContext(), "Media player error! Resetting.",
             Toast.LENGTH_SHORT).show();
@@ -461,7 +553,6 @@
         return true; // true indicates we handled the error
     }
 
-    @Override
     public void onGainedAudioFocus() {
         Toast.makeText(getApplicationContext(), "gained audio focus.", Toast.LENGTH_SHORT).show();
         mAudioFocus = AudioFocus.Focused;
@@ -471,7 +562,6 @@
             configAndStartMediaPlayer();
     }
 
-    @Override
     public void onLostAudioFocus(boolean canDuck) {
         Toast.makeText(getApplicationContext(), "lost audio focus." + (canDuck ? "can duck" :
             "no duck"), Toast.LENGTH_SHORT).show();
@@ -482,7 +572,6 @@
             configAndStartMediaPlayer();
     }
 
-    @Override
     public void onMusicRetrieverPrepared() {
         // Done retrieving!
         mState = State.Stopped;
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/RemoteControlClientCompat.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/RemoteControlClientCompat.java
new file mode 100644
index 0000000..9541a91
--- /dev/null
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/RemoteControlClientCompat.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.musicplayer;
+
+import android.app.PendingIntent;
+import android.graphics.Bitmap;
+import android.os.Looper;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * RemoteControlClient enables exposing information meant to be consumed by remote controls capable
+ * of displaying metadata, artwork and media transport control buttons. A remote control client
+ * object is associated with a media button event receiver. This event receiver must have been
+ * previously registered with
+ * {@link android.media.AudioManager#registerMediaButtonEventReceiver(android.content.ComponentName)}
+ * before the RemoteControlClient can be registered through
+ * {@link android.media.AudioManager#registerRemoteControlClient(android.media.RemoteControlClient)}.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class RemoteControlClientCompat {
+
+    private static final String TAG = "RemoteControlCompat";
+
+    private static Class sRemoteControlClientClass;
+
+    // RCC short for RemoteControlClient
+    private static Method sRCCEditMetadataMethod;
+    private static Method sRCCSetPlayStateMethod;
+    private static Method sRCCSetTransportControlFlags;
+
+    private static boolean sHasRemoteControlAPIs = false;
+
+    static {
+        try {
+            ClassLoader classLoader = RemoteControlClientCompat.class.getClassLoader();
+            sRemoteControlClientClass = getActualRemoteControlClientClass(classLoader);
+            // dynamically populate the playstate and flag values in case they change
+            // in future versions.
+            for (Field field : RemoteControlClientCompat.class.getFields()) {
+                try {
+                    Field realField = sRemoteControlClientClass.getField(field.getName());
+                    Object realValue = realField.get(null);
+                    field.set(null, realValue);
+                } catch (NoSuchFieldException e) {
+                    Log.w(TAG, "Could not get real field: " + field.getName());
+                } catch (IllegalArgumentException e) {
+                    Log.w(TAG, "Error trying to pull field value for: " + field.getName()
+                            + " " + e.getMessage());
+                } catch (IllegalAccessException e) {
+                    Log.w(TAG, "Error trying to pull field value for: " + field.getName()
+                            + " " + e.getMessage());
+                }
+            }
+
+            // get the required public methods on RemoteControlClient
+            sRCCEditMetadataMethod = sRemoteControlClientClass.getMethod("editMetadata",
+                    boolean.class);
+            sRCCSetPlayStateMethod = sRemoteControlClientClass.getMethod("setPlaybackState",
+                    int.class);
+            sRCCSetTransportControlFlags = sRemoteControlClientClass.getMethod(
+                    "setTransportControlFlags", int.class);
+
+            sHasRemoteControlAPIs = true;
+        } catch (ClassNotFoundException e) {
+            // Silently fail when running on an OS before ICS.
+        } catch (NoSuchMethodException e) {
+            // Silently fail when running on an OS before ICS.
+        } catch (IllegalArgumentException e) {
+            // Silently fail when running on an OS before ICS.
+        } catch (SecurityException e) {
+            // Silently fail when running on an OS before ICS.
+        }
+    }
+
+    public static Class getActualRemoteControlClientClass(ClassLoader classLoader)
+            throws ClassNotFoundException {
+        return classLoader.loadClass("android.media.RemoteControlClient");
+    }
+
+    private Object mActualRemoteControlClient;
+
+    public RemoteControlClientCompat(PendingIntent pendingIntent) {
+        if (!sHasRemoteControlAPIs) {
+            return;
+        }
+        try {
+            mActualRemoteControlClient =
+                    sRemoteControlClientClass.getConstructor(PendingIntent.class)
+                            .newInstance(pendingIntent);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public RemoteControlClientCompat(PendingIntent pendingIntent, Looper looper) {
+        if (!sHasRemoteControlAPIs) {
+            return;
+        }
+
+        try {
+            mActualRemoteControlClient =
+                    sRemoteControlClientClass.getConstructor(PendingIntent.class, Looper.class)
+                            .newInstance(pendingIntent, looper);
+        } catch (Exception e) {
+            Log.e(TAG, "Error creating new instance of " + sRemoteControlClientClass.getName(), e);
+        }
+    }
+
+    /**
+     * Class used to modify metadata in a {@link android.media.RemoteControlClient} object. Use
+     * {@link android.media.RemoteControlClient#editMetadata(boolean)} to create an instance of an
+     * editor, on which you set the metadata for the RemoteControlClient instance. Once all the
+     * information has been set, use {@link #apply()} to make it the new metadata that should be
+     * displayed for the associated client. Once the metadata has been "applied", you cannot reuse
+     * this instance of the MetadataEditor.
+     */
+    public class MetadataEditorCompat {
+
+        private Method mPutStringMethod;
+        private Method mPutBitmapMethod;
+        private Method mPutLongMethod;
+        private Method mClearMethod;
+        private Method mApplyMethod;
+
+        private Object mActualMetadataEditor;
+
+        /**
+         * The metadata key for the content artwork / album art.
+         */
+        public final static int METADATA_KEY_ARTWORK = 100;
+
+        private MetadataEditorCompat(Object actualMetadataEditor) {
+            if (sHasRemoteControlAPIs && actualMetadataEditor == null) {
+                throw new IllegalArgumentException("Remote Control API's exist, " +
+                        "should not be given a null MetadataEditor");
+            }
+            if (sHasRemoteControlAPIs) {
+                Class metadataEditorClass = actualMetadataEditor.getClass();
+
+                try {
+                    mPutStringMethod = metadataEditorClass.getMethod("putString",
+                            int.class, String.class);
+                    mPutBitmapMethod = metadataEditorClass.getMethod("putBitmap",
+                            int.class, Bitmap.class);
+                    mPutLongMethod = metadataEditorClass.getMethod("putLong",
+                            int.class, long.class);
+                    mClearMethod = metadataEditorClass.getMethod("clear", new Class[]{});
+                    mApplyMethod = metadataEditorClass.getMethod("apply", new Class[]{});
+                } catch (Exception e) {
+                    throw new RuntimeException(e.getMessage(), e);
+                }
+            }
+            mActualMetadataEditor = actualMetadataEditor;
+        }
+
+        /**
+         * Adds textual information to be displayed.
+         * Note that none of the information added after {@link #apply()} has been called,
+         * will be displayed.
+         * @param key The identifier of a the metadata field to set. Valid values are
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
+         * @param value The text for the given key, or {@code null} to signify there is no valid
+         *      information for the field.
+         * @return Returns a reference to the same MetadataEditor object, so you can chain put
+         *      calls together.
+         */
+        public MetadataEditorCompat putString(int key, String value) {
+            if (sHasRemoteControlAPIs) {
+                try {
+                    mPutStringMethod.invoke(mActualMetadataEditor, key, value);
+                } catch (Exception e) {
+                    throw new RuntimeException(e.getMessage(), e);
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Sets the album / artwork picture to be displayed on the remote control.
+         * @param key the identifier of the bitmap to set. The only valid value is
+         *      {@link #METADATA_KEY_ARTWORK}
+         * @param bitmap The bitmap for the artwork, or null if there isn't any.
+         * @return Returns a reference to the same MetadataEditor object, so you can chain put
+         *      calls together.
+         * @throws IllegalArgumentException
+         * @see android.graphics.Bitmap
+         */
+        public MetadataEditorCompat putBitmap(int key, Bitmap bitmap) {
+            if (sHasRemoteControlAPIs) {
+                try {
+                    mPutBitmapMethod.invoke(mActualMetadataEditor, key, bitmap);
+                } catch (Exception e) {
+                    throw new RuntimeException(e.getMessage(), e);
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Adds numerical information to be displayed.
+         * Note that none of the information added after {@link #apply()} has been called,
+         * will be displayed.
+         * @param key the identifier of a the metadata field to set. Valid values are
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
+         *      expressed in milliseconds),
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+         * @param value The long value for the given key
+         * @return Returns a reference to the same MetadataEditor object, so you can chain put
+         *      calls together.
+         * @throws IllegalArgumentException
+         */
+        public MetadataEditorCompat putLong(int key, long value) {
+            if (sHasRemoteControlAPIs) {
+                try {
+                    mPutLongMethod.invoke(mActualMetadataEditor, key, value);
+                } catch (Exception e) {
+                    throw new RuntimeException(e.getMessage(), e);
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Clears all the metadata that has been set since the MetadataEditor instance was
+         * created with {@link android.media.RemoteControlClient#editMetadata(boolean)}.
+         */
+        public void clear() {
+            if (sHasRemoteControlAPIs) {
+                try {
+                    mClearMethod.invoke(mActualMetadataEditor, (Object[]) null);
+                } catch (Exception e) {
+                    throw new RuntimeException(e.getMessage(), e);
+                }
+            }
+        }
+
+        /**
+         * Associates all the metadata that has been set since the MetadataEditor instance was
+         * created with {@link android.media.RemoteControlClient#editMetadata(boolean)}, or since
+         * {@link #clear()} was called, with the RemoteControlClient. Once "applied", this
+         * MetadataEditor cannot be reused to edit the RemoteControlClient's metadata.
+         */
+        public void apply() {
+            if (sHasRemoteControlAPIs) {
+                try {
+                    mApplyMethod.invoke(mActualMetadataEditor, (Object[]) null);
+                } catch (Exception e) {
+                    throw new RuntimeException(e.getMessage(), e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates a {@link android.media.RemoteControlClient.MetadataEditor}.
+     * @param startEmpty Set to false if you want the MetadataEditor to contain the metadata that
+     *     was previously applied to the RemoteControlClient, or true if it is to be created empty.
+     * @return a new MetadataEditor instance.
+     */
+    public MetadataEditorCompat editMetadata(boolean startEmpty) {
+        Object metadataEditor;
+        if (sHasRemoteControlAPIs) {
+            try {
+                metadataEditor = sRCCEditMetadataMethod.invoke(mActualRemoteControlClient,
+                        startEmpty);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        } else {
+            metadataEditor = null;
+        }
+        return new MetadataEditorCompat(metadataEditor);
+    }
+
+    /**
+     * Sets the current playback state.
+     * @param state The current playback state, one of the following values:
+     *       {@link android.media.RemoteControlClient#PLAYSTATE_STOPPED},
+     *       {@link android.media.RemoteControlClient#PLAYSTATE_PAUSED},
+     *       {@link android.media.RemoteControlClient#PLAYSTATE_PLAYING},
+     *       {@link android.media.RemoteControlClient#PLAYSTATE_FAST_FORWARDING},
+     *       {@link android.media.RemoteControlClient#PLAYSTATE_REWINDING},
+     *       {@link android.media.RemoteControlClient#PLAYSTATE_SKIPPING_FORWARDS},
+     *       {@link android.media.RemoteControlClient#PLAYSTATE_SKIPPING_BACKWARDS},
+     *       {@link android.media.RemoteControlClient#PLAYSTATE_BUFFERING},
+     *       {@link android.media.RemoteControlClient#PLAYSTATE_ERROR}.
+     */
+    public void setPlaybackState(int state) {
+        if (sHasRemoteControlAPIs) {
+            try {
+                sRCCSetPlayStateMethod.invoke(mActualRemoteControlClient, state);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Sets the flags for the media transport control buttons that this client supports.
+     * @param transportControlFlags A combination of the following flags:
+     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PREVIOUS},
+     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_REWIND},
+     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY},
+     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY_PAUSE},
+     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PAUSE},
+     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_STOP},
+     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_FAST_FORWARD},
+     *      {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_NEXT}
+     */
+    public void setTransportControlFlags(int transportControlFlags) {
+        if (sHasRemoteControlAPIs) {
+            try {
+                sRCCSetTransportControlFlags.invoke(mActualRemoteControlClient,
+                        transportControlFlags);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public final Object getActualRemoteControlClientObject() {
+        return mActualRemoteControlClient;
+    }
+}
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/RemoteControlHelper.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/RemoteControlHelper.java
new file mode 100644
index 0000000..714d3c5
--- /dev/null
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/RemoteControlHelper.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.musicplayer;
+
+import android.media.AudioManager;
+import android.util.Log;
+
+import java.lang.reflect.Method;
+
+/**
+ * Contains methods to handle registering/unregistering remote control clients.  These methods only
+ * run on ICS devices.  On previous devices, all methods are no-ops.
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public class RemoteControlHelper {
+    private static final String TAG = "RemoteControlHelper";
+
+    private static boolean sHasRemoteControlAPIs = false;
+
+    private static Method sRegisterRemoteControlClientMethod;
+    private static Method sUnregisterRemoteControlClientMethod;
+
+    static {
+        try {
+            ClassLoader classLoader = RemoteControlHelper.class.getClassLoader();
+            Class sRemoteControlClientClass =
+                    RemoteControlClientCompat.getActualRemoteControlClientClass(classLoader);
+            sRegisterRemoteControlClientMethod = AudioManager.class.getMethod(
+                    "registerRemoteControlClient", new Class[]{sRemoteControlClientClass});
+            sUnregisterRemoteControlClientMethod = AudioManager.class.getMethod(
+                    "unregisterRemoteControlClient", new Class[]{sRemoteControlClientClass});
+            sHasRemoteControlAPIs = true;
+        } catch (ClassNotFoundException e) {
+            // Silently fail when running on an OS before ICS.
+        } catch (NoSuchMethodException e) {
+            // Silently fail when running on an OS before ICS.
+        } catch (IllegalArgumentException e) {
+            // Silently fail when running on an OS before ICS.
+        } catch (SecurityException e) {
+            // Silently fail when running on an OS before ICS.
+        }
+    }
+
+    public static void registerRemoteControlClient(AudioManager audioManager,
+            RemoteControlClientCompat remoteControlClient) {
+        if (!sHasRemoteControlAPIs) {
+            return;
+        }
+
+        try {
+            sRegisterRemoteControlClientMethod.invoke(audioManager,
+                    remoteControlClient.getActualRemoteControlClientObject());
+        } catch (Exception e) {
+            Log.e(TAG, e.getMessage(), e);
+        }
+    }
+
+
+    public static void unregisterRemoteControlClient(AudioManager audioManager,
+            RemoteControlClientCompat remoteControlClient) {
+        if (!sHasRemoteControlAPIs) {
+            return;
+        }
+
+        try {
+            sUnregisterRemoteControlClientMethod.invoke(audioManager,
+                    remoteControlClient.getActualRemoteControlClientObject());
+        } catch (Exception e) {
+            Log.e(TAG, e.getMessage(), e);
+        }
+    }
+}
+
diff --git a/samples/RenderScript/Balls/AndroidManifest.xml b/samples/RenderScript/Balls/AndroidManifest.xml
index c0ae2ff..80e6b39 100644
--- a/samples/RenderScript/Balls/AndroidManifest.xml
+++ b/samples/RenderScript/Balls/AndroidManifest.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.example.android.rs.balls">
-    <uses-sdk android:minSdkVersion="11" />
+    <uses-sdk android:minSdkVersion="14" />
     <application 
         android:label="RsBalls"
         android:icon="@drawable/test_pattern">
diff --git a/samples/SampleSpellCheckerService/Android.mk b/samples/SampleSpellCheckerService/Android.mk
new file mode 100755
index 0000000..adf65d9
--- /dev/null
+++ b/samples/SampleSpellCheckerService/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := samples
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := SampleSpellChecker
+
+include $(BUILD_PACKAGE)
diff --git a/samples/SampleSpellCheckerService/AndroidManifest.xml b/samples/SampleSpellCheckerService/AndroidManifest.xml
new file mode 100644
index 0000000..fcb1671
--- /dev/null
+++ b/samples/SampleSpellCheckerService/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.samplespellcheckerservice" >
+
+    <uses-sdk android:minSdkVersion="14"/>
+    <application
+        android:label="@string/app_name" >
+        <service
+            android:label="@string/app_name"
+            android:name=".SampleSpellCheckerService"
+            android:permission="android.permission.BIND_TEXT_SERVICE" >
+            <intent-filter >
+                <action android:name="android.service.textservice.SpellCheckerService" />
+            </intent-filter>
+
+            <meta-data
+                android:name="android.view.textservice.scs"
+                android:resource="@xml/spellchecker" />
+        </service>
+
+        <activity
+            android:label="@string/sample_settings"
+            android:name="SpellCheckerSettingsActivity" >
+            <intent-filter >
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/SampleSpellCheckerService/_index.html b/samples/SampleSpellCheckerService/_index.html
new file mode 100755
index 0000000..d6dada9
--- /dev/null
+++ b/samples/SampleSpellCheckerService/_index.html
@@ -0,0 +1,5 @@
+<p>A sample showing how to create a spell checker with the <code><a
+href="../../../reference/android/service/textservice/SpellCheckerService.html">SpellCheckerService</a></code>
+APIs introduced in Android 4.0 (API level 14).</p>
+<p>This app does not have a launcher activity. Once you install it, go to the system's input settings and enable
+"Sample correction" as the spelling correction service. </p>
diff --git a/samples/SampleSpellCheckerService/res/values/strings.xml b/samples/SampleSpellCheckerService/res/values/strings.xml
new file mode 100644
index 0000000..79da5c6
--- /dev/null
+++ b/samples/SampleSpellCheckerService/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+    <string name="app_name">SampleSpellCheckerService</string>
+    <string name="spellchecker_name">Sample correction</string>
+    <string name="subtype_generic" translatable="false">%s</string>
+    <string name="sample_settings">Sample settings</string>
+    <string name="sample_preference">Sample preference</string>
+</resources>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/values/styles.xml b/samples/SampleSpellCheckerService/res/xml/spell_checker_settings.xml
similarity index 61%
copy from samples/SampleSyncAdapter/res/values/styles.xml
copy to samples/SampleSpellCheckerService/res/xml/spell_checker_settings.xml
index 074613e..e04d50e 100644
--- a/samples/SampleSyncAdapter/res/values/styles.xml
+++ b/samples/SampleSpellCheckerService/res/xml/spell_checker_settings.xml
@@ -14,14 +14,11 @@
      limitations under the License.
 -->
 
-<resources>
-    <!--
-        These styles will only be used in Honeycomb and later because
-        Android doesn't support third-party contact editing in pre-
-        Honeycomb versions.
-    -->
-    <color name="EditPanelBackgroundColor">#ffffff</color>
-    <color name="EditPanelBorderColor">#cccccc</color>
-    <style name="ContactEditTheme" parent="android:Theme.Holo.Light">
-    </style>
-</resources>
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/sample_settings">
+  <CheckBoxPreference
+     android:title="@string/sample_preference"
+     android:persistent="true"
+     android:defaultValue="true" />
+</PreferenceScreen>
diff --git a/samples/SampleSpellCheckerService/res/xml/spellchecker.xml b/samples/SampleSpellCheckerService/res/xml/spellchecker.xml
new file mode 100644
index 0000000..f4601d2
--- /dev/null
+++ b/samples/SampleSpellCheckerService/res/xml/spellchecker.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<!-- The attributes in this XML file provide the configuration information -->
+<!-- for the spell checker -->
+
+<spell-checker xmlns:android="http://schemas.android.com/apk/res/android"
+        android:label="@string/spellchecker_name"
+        android:settingsActivity="com.example.android.samplespellcheckerservice.SpellCheckerSettingsActivity">
+    <subtype
+            android:label="@string/subtype_generic"
+            android:subtypeLocale="en"
+    />
+</spell-checker>
diff --git a/samples/SampleSpellCheckerService/src/com/example/android/samplespellcheckerservice/SampleSpellCheckerService.java b/samples/SampleSpellCheckerService/src/com/example/android/samplespellcheckerservice/SampleSpellCheckerService.java
new file mode 100644
index 0000000..dc85587
--- /dev/null
+++ b/samples/SampleSpellCheckerService/src/com/example/android/samplespellcheckerservice/SampleSpellCheckerService.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.samplespellcheckerservice;
+
+import android.service.textservice.SpellCheckerService;
+import android.util.Log;
+import android.view.textservice.SuggestionsInfo;
+import android.view.textservice.TextInfo;
+
+public class SampleSpellCheckerService extends SpellCheckerService {
+    private static final String TAG = SampleSpellCheckerService.class.getSimpleName();
+    private static final boolean DBG = true;
+    @Override
+    public Session createSession() {
+        return new AndroidSpellCheckerSession();
+    }
+
+    private static class AndroidSpellCheckerSession extends Session {
+        private String mLocale;
+        @Override
+        public void onCreate() {
+            mLocale = getLocale();
+        }
+
+        @Override
+        public SuggestionsInfo onGetSuggestions(TextInfo textInfo, int suggestionsLimit) {
+            if (DBG) {
+                Log.d(TAG, "onGetSuggestions: " + textInfo.getText());
+            }
+            final String input = textInfo.getText();
+            final int length = input.length();
+            // Just a fake logic:
+            // length <= 3 for short words that we assume are in the fake dictionary
+            // length > 20 for too long words that we assume can't be recognized (such as CJK words)
+            final int flags = length <= 3 ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY
+                    : length <= 20 ? SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO : 0;
+            return new SuggestionsInfo(flags,
+                    new String[] {"aaa", "bbb", "Candidate for " + input, mLocale});
+        }
+    }
+}
diff --git a/samples/SampleSpellCheckerService/src/com/example/android/samplespellcheckerservice/SpellCheckerSettingsActivity.java b/samples/SampleSpellCheckerService/src/com/example/android/samplespellcheckerservice/SpellCheckerSettingsActivity.java
new file mode 100644
index 0000000..f223ef7
--- /dev/null
+++ b/samples/SampleSpellCheckerService/src/com/example/android/samplespellcheckerservice/SpellCheckerSettingsActivity.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.example.android.samplespellcheckerservice;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+/**
+ * Spell checker preference screen.
+ */
+public class SpellCheckerSettingsActivity extends PreferenceActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public Intent getIntent() {
+        final Intent modIntent = new Intent(super.getIntent());
+        modIntent.putExtra(EXTRA_SHOW_FRAGMENT, SpellCheckerSettingsFragment.class.getName());
+        modIntent.putExtra(EXTRA_NO_HEADERS, true);
+        return modIntent;
+    }
+}
diff --git a/samples/SampleSpellCheckerService/src/com/example/android/samplespellcheckerservice/SpellCheckerSettingsFragment.java b/samples/SampleSpellCheckerService/src/com/example/android/samplespellcheckerservice/SpellCheckerSettingsFragment.java
new file mode 100644
index 0000000..cd2efcc
--- /dev/null
+++ b/samples/SampleSpellCheckerService/src/com/example/android/samplespellcheckerservice/SpellCheckerSettingsFragment.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.example.android.samplespellcheckerservice;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+
+/**
+ * Preference screen.
+ */
+public class SpellCheckerSettingsFragment extends PreferenceFragment {
+
+    /**
+     * Empty constructor for fragment generation.
+     */
+    public SpellCheckerSettingsFragment() {
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        addPreferencesFromResource(R.xml.spell_checker_settings);
+    }
+}
diff --git a/samples/SampleSyncAdapter/AndroidManifest.xml b/samples/SampleSyncAdapter/AndroidManifest.xml
index 25e9e99..285abfb 100644
--- a/samples/SampleSyncAdapter/AndroidManifest.xml
+++ b/samples/SampleSyncAdapter/AndroidManifest.xml
@@ -46,7 +46,7 @@
     <uses-permission
         android:name="android.permission.WRITE_SYNC_SETTINGS" />
 
-    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="11"/>
+    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="14"/>
 
     <application
         android:icon="@drawable/icon"
@@ -100,27 +100,8 @@
         </activity>
 
         <activity
-            android:name=".editor.ContactEditorActivity"
-            android:theme="@style/ContactEditTheme"
-            android:windowSoftInputMode="adjustResize">
-            <intent-filter>
-                <action
-                    android:name="android.intent.action.INSERT" />
-                <data
-                    android:mimeType="vnd.android.cursor.item/contact" />
-            </intent-filter>
-
-            <!--
-                Note that the editor gets a raw contact URI, but is expected to call
-                setResult with the corresponding aggregate contact URI, not raw contact
-                URI.
-            -->
-            <intent-filter>
-                <action
-                    android:name="android.intent.action.EDIT" />
-                <data
-                    android:mimeType="vnd.android.cursor.item/raw_contact" />
-            </intent-filter>
+            android:name=".activites.InviteContactActivity"
+            android:theme="@android:style/Theme.Dialog">
             <!--
                 We use the INVITE intent to add a raw contact to an existing contact.
                 It always comes with a lookup URI.
@@ -132,5 +113,50 @@
                     android:mimeType="vnd.android.cursor.item/contact" />
             </intent-filter>
         </activity>
+
+        <activity
+            android:name=".activities.ViewGroupActivity"
+            android:theme="@android:style/Theme.Dialog">
+            <!--
+                We use the VIEW intent to view a group in our app.
+                It always comes with a lookup URI.
+            -->
+            <intent-filter>
+                <action
+                    android:name="android.intent.action.VIEW" />
+                <data
+                    android:mimeType="vnd.android.cursor.item/group" />
+            </intent-filter>
+        </activity>
+
+        <activity
+            android:name=".activities.ViewStreamItemActivity"
+            android:theme="@android:style/Theme.Dialog">
+            <!--
+                We use the VIEW intent to view a stream item in our app.
+                It always comes with a lookup URI.
+            -->
+            <intent-filter>
+                <action
+                    android:name="android.intent.action.VIEW" />
+                <data
+                    android:mimeType="vnd.android.cursor.item/stream_item" />
+            </intent-filter>
+        </activity>
+
+        <activity
+            android:name=".activities.ViewStreamItemPhotoActivity"
+            android:theme="@android:style/Theme.Dialog">
+            <!--
+                We use the VIEW intent to view a stream item photo in our app.
+                It always comes with a lookup URI.
+            -->
+            <intent-filter>
+                <action
+                    android:name="android.intent.action.VIEW" />
+                <data
+                    android:mimeType="vnd.android.cursor.item/stream_item_photo" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/samples/SampleSyncAdapter/res/drawable/border.xml b/samples/SampleSyncAdapter/res/drawable/border.xml
deleted file mode 100644
index ab71f2c..0000000
--- a/samples/SampleSyncAdapter/res/drawable/border.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-  <solid android:color="@color/EditPanelBackgroundColor" />
-  <stroke android:width="2dip" android:color="@color/EditPanelBorderColor" />
-  <padding android:left="5dip" android:top="5dip" android:right="5dip" android:bottom="5dip" />
-</shape>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/drawable/done_menu_icon.png b/samples/SampleSyncAdapter/res/drawable/done_menu_icon.png
deleted file mode 100644
index 3468bbd..0000000
--- a/samples/SampleSyncAdapter/res/drawable/done_menu_icon.png
+++ /dev/null
Binary files differ
diff --git a/samples/SampleSyncAdapter/res/layout-xlarge/editor.xml b/samples/SampleSyncAdapter/res/layout-xlarge/editor.xml
deleted file mode 100644
index 3b7d97b..0000000
--- a/samples/SampleSyncAdapter/res/layout-xlarge/editor.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:gravity="center_horizontal">
-    <LinearLayout
-      xmlns:android="http://schemas.android.com/apk/res/android"
-      android:layout_width="600dip"
-      android:layout_height="match_parent"
-      android:orientation="vertical"
-      android:background="@drawable/border">
-      <include layout="@layout/editor_header" />
-      <ScrollView
-          android:layout_width="match_parent"
-          android:layout_height="0dip"
-          android:paddingTop="20dip"
-          android:paddingRight="20dip"
-          android:paddingBottom="20dip"
-          android:paddingLeft="20dip"
-          android:layout_weight="1">
-          <include layout="@layout/editor_fields" />
-      </ScrollView>
-    </LinearLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/layout-xlarge/editor_header.xml b/samples/SampleSyncAdapter/res/layout-xlarge/editor_header.xml
deleted file mode 100644
index 648e6f9..0000000
--- a/samples/SampleSyncAdapter/res/layout-xlarge/editor_header.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-
-<!-- Account info header -->
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="64dip"
-    android:layout_width="match_parent"
-    android:background="?android:attr/selectableItemBackground">
-
-    <ImageView
-        android:id="@+id/header_account_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="7dip"
-        android:layout_marginRight="7dip"
-        android:layout_centerVertical="true"
-        android:layout_alignParentRight="true"
-        android:src="@drawable/icon" />
-
-    <TextView
-        android:id="@+id/header_account_type"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_toLeftOf="@+id/header_account_icon"
-        android:layout_alignTop="@id/header_account_icon"
-        android:layout_marginTop="-4dip"
-        android:textSize="24sp"
-        android:textColor="?android:attr/textColorPrimary"
-        android:singleLine="true"
-        android:text="@string/header_account_type" />
-
-    <TextView
-        android:id="@+id/header_account_name"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_toLeftOf="@+id/header_account_icon"
-        android:layout_alignBottom="@+id/header_account_icon"
-        android:layout_marginBottom="2dip"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:textColor="?android:attr/textColorPrimary"
-        android:singleLine="true" />
-
-</RelativeLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/editor_fields.xml b/samples/SampleSyncAdapter/res/layout/editor_fields.xml
deleted file mode 100644
index 31d0128..0000000
--- a/samples/SampleSyncAdapter/res/layout/editor_fields.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-
-<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-  android:layout_width="fill_parent"
-  android:layout_height="fill_parent"
-  android:stretchColumns="2">
-
-  <TableRow>
-    <TextView
-      android:layout_column="1"
-      android:textStyle="bold"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:text="@string/label_name"
-      android:padding="3dip" />
-    <EditText
-      android:layout_column="2"
-      android:id="@+id/editor_name"
-      android:singleLine="true"
-      android:inputType="textPersonName"
-      android:layout_width="fill_parent"
-      android:layout_height="wrap_content"
-      android:minWidth="250dip"
-      android:scrollHorizontally="true"
-      android:capitalize="none"
-      android:textSize="@dimen/contact_name_text_size"
-      android:gravity="fill_horizontal"
-      android:autoText="false" />
-  </TableRow>
-  <TableRow>
-    <TextView
-      android:layout_column="1"
-      android:textStyle="bold"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:text="@string/label_phone_home"
-      android:padding="3dip" />
-    <EditText
-      android:id="@+id/editor_phone_home"
-      android:singleLine="true"
-      android:inputType="phone"
-      android:layout_width="fill_parent"
-      android:layout_height="wrap_content"
-      android:minWidth="250dip"
-      android:scrollHorizontally="true"
-      android:capitalize="none"
-      android:gravity="fill_horizontal"
-      android:autoText="false" />
-  </TableRow>
-  <TableRow>
-    <TextView
-      android:layout_column="1"
-      android:textStyle="bold"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:text="@string/label_phone_mobile"
-      android:padding="3dip" />
-    <EditText
-      android:id="@+id/editor_phone_mobile"
-      android:singleLine="true"
-      android:inputType="phone"
-      android:layout_width="fill_parent"
-      android:layout_height="wrap_content"
-      android:minWidth="250dip"
-      android:scrollHorizontally="true"
-      android:capitalize="none"
-      android:gravity="fill_horizontal"
-      android:autoText="false" />
-  </TableRow>
-  <TableRow>
-    <TextView
-      android:layout_column="1"
-      android:textStyle="bold"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:text="@string/label_phone_work"
-      android:padding="3dip" />
-    <EditText
-      android:id="@+id/editor_phone_work"
-      android:singleLine="true"
-      android:phoneNumber="true"
-      android:autoText="true"
-      android:layout_width="fill_parent"
-      android:layout_height="wrap_content"
-      android:minWidth="250dip"
-      android:scrollHorizontally="true"
-      android:capitalize="none"
-      android:gravity="fill_horizontal" />
-  </TableRow>
-  <TableRow>
-    <TextView
-      android:layout_column="1"
-      android:textStyle="bold"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:text="@string/label_email"
-      android:padding="3dip" />
-    <EditText
-      android:id="@+id/editor_email"
-      android:singleLine="true"
-      android:inputType="textEmailAddress"
-      android:layout_width="fill_parent"
-      android:layout_height="wrap_content"
-      android:minWidth="250dip"
-      android:scrollHorizontally="true"
-      android:capitalize="none"
-      android:gravity="fill_horizontal"
-      android:autoText="false" />
-  </TableRow>
-</TableLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/editor.xml b/samples/SampleSyncAdapter/res/layout/invite_contact_activity.xml
similarity index 61%
rename from samples/SampleSyncAdapter/res/layout/editor.xml
rename to samples/SampleSyncAdapter/res/layout/invite_contact_activity.xml
index a0c36d2..1e09d5b 100644
--- a/samples/SampleSyncAdapter/res/layout/editor.xml
+++ b/samples/SampleSyncAdapter/res/layout/invite_contact_activity.xml
@@ -18,19 +18,15 @@
 -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <ScrollView
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:paddingTop="20dip"
-        android:paddingRight="20dip"
-        android:paddingBottom="20dip"
-        android:paddingLeft="20dip"
-        android:layout_weight="1">
-        <include layout="@layout/editor_fields" />
-    </ScrollView>
-
-</LinearLayout>
\ No newline at end of file
+    android:orientation="vertical"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+    <TextView
+        android:text="@string/invite_contact_description"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+    <TextView
+        android:id="@+id/invite_contact_uri"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/login_activity.xml b/samples/SampleSyncAdapter/res/layout/login_activity.xml
index 7408ffe..6c93f90 100644
--- a/samples/SampleSyncAdapter/res/layout/login_activity.xml
+++ b/samples/SampleSyncAdapter/res/layout/login_activity.xml
@@ -55,7 +55,8 @@
                 android:scrollHorizontally="true"
                 android:capitalize="none"
                 android:autoText="false"
-                android:inputType="textEmailAddress" />
+                android:inputType="textEmailAddress"
+                android:text="user" />
             <TextView
                 android:id="@+id/username_fixed"
                 android:textAppearance="?android:attr/textAppearanceSmall"
@@ -81,7 +82,8 @@
                 android:capitalize="none"
                 android:autoText="false"
                 android:password="true"
-                android:inputType="textPassword" />
+                android:inputType="textPassword"
+                android:text="test" />
             <TextView
                 android:id="@+id/message_bottom"
                 android:textAppearance="?android:attr/textAppearanceSmall"
diff --git a/samples/SampleSyncAdapter/res/layout/view_group_activity.xml b/samples/SampleSyncAdapter/res/layout/view_group_activity.xml
new file mode 100644
index 0000000..45212d9
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/layout/view_group_activity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+    <TextView
+        android:text="@string/view_group_description"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+    <TextView
+        android:id="@+id/view_group_uri"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml b/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml
new file mode 100644
index 0000000..a04d07f
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/layout/view_stream_item_activity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+    <TextView
+        android:text="@string/view_stream_item_description"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+    <TextView
+        android:id="@+id/view_stream_item_uri"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml b/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml
new file mode 100644
index 0000000..ddc09d0
--- /dev/null
+++ b/samples/SampleSyncAdapter/res/layout/view_stream_item_photo_activity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+    <TextView
+        android:text="@string/view_stream_item_photo_description"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+    <TextView
+        android:id="@+id/view_stream_item_photo_uri"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/menu/edit.xml b/samples/SampleSyncAdapter/res/menu/edit.xml
deleted file mode 100644
index 1227584..0000000
--- a/samples/SampleSyncAdapter/res/menu/edit.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:id="@+id/menu_done"
-        android:alphabeticShortcut="\n"
-        android:icon="@drawable/done_menu_icon"
-        android:title="@string/menu_done"
-        android:showAsAction="always|withText" />
-
-    <item
-        android:id="@+id/menu_cancel"
-        android:alphabeticShortcut="q"
-        android:title="@string/menu_cancel"
-        android:showAsAction="always|withText" />
-</menu>
diff --git a/samples/SampleSyncAdapter/res/values/strings.xml b/samples/SampleSyncAdapter/res/values/strings.xml
index 7ac95f5..22fe14e 100644
--- a/samples/SampleSyncAdapter/res/values/strings.xml
+++ b/samples/SampleSyncAdapter/res/values/strings.xml
@@ -109,4 +109,34 @@
     <!-- The label of the button to add contact to this contact provider  -->
     <string name="invite_action_label">Add to Sample SyncAdaper</string>
 
+    <!-- The description for the invite contact flow -->
+    <string name="invite_contact_description">Congratulations! The user wants to add the contact
+        to the amazing Sample SyncAdapter social network. If this was a real app, it should now
+        make best efforts to add the contact to this network. This would probably involve
+        looking up the person on the network, inviting if he is not there already and syncing
+        the new contact down.
+
+        Ideally, when the user gets back to the People app, the new contact should already
+        be there, enriching the original contact.
+
+        This is the information we got to lookup the contact:</string>
+
+    <!-- The label of the button to view a group -->
+    <string name="view_group_action_label">Show sample group details</string>
+
+    <!-- The description for the view group button -->
+    <string name="view_group_description">This would now show the details of the group.
+
+        This is the group uri:</string>
+
+    <!-- The description for the view stream item -->
+    <string name="view_stream_item_description">This would now show the details of the stream item.
+
+        This is the uri of the stream item:</string>
+
+    <!-- The description for the view stream item photo -->
+    <string name="view_stream_item_photo_description">This would now show the details of the stream item photo.
+
+        This is the uri of the photo:</string>
+
 </resources>
\ No newline at end of file
diff --git a/samples/SampleSyncAdapter/res/xml-v11/contacts.xml b/samples/SampleSyncAdapter/res/xml-v11/contacts.xml
index 62dfa80..48cf503 100644
--- a/samples/SampleSyncAdapter/res/xml-v11/contacts.xml
+++ b/samples/SampleSyncAdapter/res/xml-v11/contacts.xml
@@ -19,8 +19,6 @@
 
 <ContactsAccountType
     xmlns:android="http://schemas.android.com/apk/res/android"
-    editContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
-    createContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
 >
 
     <ContactsDataKind
diff --git a/samples/SampleSyncAdapter/res/xml-v14/contacts.xml b/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
index b900c72..48e079a 100644
--- a/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
+++ b/samples/SampleSyncAdapter/res/xml-v14/contacts.xml
@@ -17,18 +17,15 @@
  */
 -->
 
-<!-- This sample doesn't currently support groups or stream items. viewGroupActivity and
-     viewStreamItemActivity and viewStreamItemPhotoActivity or just here for reference -->
 <ContactsAccountType
     xmlns:android="http://schemas.android.com/apk/res/android"
-    editContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
-    createContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
-    inviteContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
+    inviteContactActivity="com.example.android.samplesync.activities.InviteContactActivity"
     inviteContactActionLabel="@string/invite_action_label"
     viewContactNotifyService="com.example.android.samplesync.notifier.NotifierService"
-    viewGroupActivity="com.example.android.samplesync.viewer.ViewGroupActivity"
-    viewStreamItemActivity="com.example.android.samplesync.viewer.ViewStreamItemActivity"
-    viewStreamItemPhotoActivity="com.example.android.samplesync.viewer.ViewStreamItemPhotoActivity"
+    viewGroupActivity="com.example.android.samplesync.activities.ViewGroupActivity"
+    viewGroupActionLabel="@string/view_group_action_label"
+    viewStreamItemActivity="com.example.android.samplesync.activities.ViewStreamItemActivity"
+    viewStreamItemPhotoActivity="com.example.android.samplesync.activities.ViewStreamItemPhotoActivity"
 >
 
     <ContactsDataKind
diff --git a/samples/SampleSyncAdapter/res/xml/contacts.xml b/samples/SampleSyncAdapter/res/xml/contacts.xml
index b46257d..06ecf6a 100644
--- a/samples/SampleSyncAdapter/res/xml/contacts.xml
+++ b/samples/SampleSyncAdapter/res/xml/contacts.xml
@@ -19,8 +19,6 @@
 
 <ContactsSource
     xmlns:android="http://schemas.android.com/apk/res/android"
-    editContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
-    createContactActivity="com.example.android.samplesync.editor.ContactEditorActivity"
 >
 
     <ContactsDataKind
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/InviteContactActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/InviteContactActivity.java
new file mode 100644
index 0000000..1923fc2
--- /dev/null
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/InviteContactActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.example.android.samplesync.activities;
+
+import com.example.android.samplesync.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Activity to handle the invite-intent. In a real app, this would look up the user on the network
+ * and either connect ("add as friend", "follow") or invite them to the network
+ */
+public class InviteContactActivity extends Activity {
+    private static final String TAG = "InviteContactActivity";
+
+    private TextView mUriTextView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.invite_contact_activity);
+
+        mUriTextView = (TextView) findViewById(R.id.invite_contact_uri);
+        mUriTextView.setText(getIntent().getDataString());
+    }
+}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewGroupActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewGroupActivity.java
new file mode 100644
index 0000000..1b32784
--- /dev/null
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewGroupActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.example.android.samplesync.activities;
+
+import com.example.android.samplesync.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Activity to handle the view-group action. In a real app, this would show a rich view of the
+ * group, like members, updates etc.
+ */
+public class ViewGroupActivity extends Activity {
+    private static final String TAG = "ViewGroupActivity";
+
+    private TextView mUriTextView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.view_group_activity);
+
+        mUriTextView = (TextView) findViewById(R.id.view_group_uri);
+        mUriTextView.setText(getIntent().getDataString());
+    }
+}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java
new file mode 100644
index 0000000..6d54f31
--- /dev/null
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.example.android.samplesync.activities;
+
+import com.example.android.samplesync.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Activity to handle view a stream-item. In a real app, this would show a rich view of the
+ * item.
+ */
+public class ViewStreamItemActivity extends Activity {
+    private static final String TAG = "ViewStreamItemActivity";
+
+    private TextView mUriTextView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.view_stream_item_activity);
+
+        mUriTextView = (TextView) findViewById(R.id.view_stream_item_uri);
+        mUriTextView.setText(getIntent().getDataString());
+    }
+}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java
new file mode 100644
index 0000000..962bc70
--- /dev/null
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/activities/ViewStreamItemPhotoActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.example.android.samplesync.activities;
+
+import com.example.android.samplesync.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Activity to view a stream-item-photo. In a real app, this would show a fullscreen view of the
+ * photo, potentially with ways to interact with it
+ */
+public class ViewStreamItemPhotoActivity extends Activity {
+    private static final String TAG = "ViewStreamItemPhotoActivity";
+
+    private TextView mUriTextView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.view_stream_item_photo_activity);
+
+        mUriTextView = (TextView) findViewById(R.id.view_stream_item_photo_uri);
+        mUriTextView.setText(getIntent().getDataString());
+    }
+}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java
index 2a3c0fc..5649f6d 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java
@@ -110,7 +110,7 @@
         mMessage = (TextView) findViewById(R.id.message);
         mUsernameEdit = (EditText) findViewById(R.id.username_edit);
         mPasswordEdit = (EditText) findViewById(R.id.password_edit);
-        mUsernameEdit.setText(mUsername);
+        if (!TextUtils.isEmpty(mUsername)) mUsernameEdit.setText(mUsername);
         mMessage.setText(getMessage());
     }
 
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java
index bebcd72..c2ebd19 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java
@@ -16,16 +16,6 @@
 
 package com.example.android.samplesync.client;
 
-import android.accounts.Account;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Handler;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.example.android.samplesync.authenticator.AuthenticatorActivity;
-
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
@@ -41,9 +31,15 @@
 import org.apache.http.params.HttpConnectionParams;
 import org.apache.http.params.HttpParams;
 import org.apache.http.util.EntityUtils;
-import org.json.JSONObject;
 import org.json.JSONArray;
 import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.accounts.Account;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.text.TextUtils;
+import android.util.Log;
 
 import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
@@ -54,11 +50,8 @@
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
-import java.util.TimeZone;
 
 /**
  * Provides utility methods for communicating with the server.
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/editor/ContactEditorActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/editor/ContactEditorActivity.java
deleted file mode 100644
index efda0cc..0000000
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/editor/ContactEditorActivity.java
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.example.android.samplesync.editor;
-
-import com.example.android.samplesync.Constants;
-import com.example.android.samplesync.R;
-import com.example.android.samplesync.client.RawContact;
-import com.example.android.samplesync.platform.BatchOperation;
-import com.example.android.samplesync.platform.ContactManager;
-import com.example.android.samplesync.platform.ContactManager.ContactQuery;
-import com.example.android.samplesync.platform.ContactManager.EditorQuery;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.RawContacts;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.widget.EditText;
-import android.widget.TextView;
-
-/**
- * Implements a sample editor for a contact that belongs to a remote contact service.
- * The editor can be invoked for an existing SampleSyncAdapter contact, or it can
- * be used to create a brand new SampleSyncAdapter contact. We look at the Intent
- * object to figure out whether this is a "new" or "edit" operation.
- */
-public class ContactEditorActivity extends Activity {
-    private static final String TAG = "SampleSyncAdapter";
-
-    // Keep track of whether we're inserting a new contact or editing an
-    // existing contact.
-    private boolean mIsInsert;
-
-    // The name of the external account we're syncing this contact to.
-    private String mAccountName;
-
-    // For existing contacts, this is the URI to the contact data.
-    private Uri mRawContactUri;
-
-    // The raw clientId for this contact
-    private long mRawContactId;
-
-    // Make sure we only attempt to save the contact once if the
-    // user presses the "done" button multiple times...
-    private boolean mSaveInProgress = false;
-
-    // Keep track of the controls used to edit contact values, so we can get/set
-    // those values easily.
-    private EditText mNameEditText;
-    private EditText mHomePhoneEditText;
-    private EditText mMobilePhoneEditText;
-    private EditText mWorkPhoneEditText;
-    private EditText mEmailEditText;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.editor);
-
-        mNameEditText = (EditText)findViewById(R.id.editor_name);
-        mHomePhoneEditText = (EditText)findViewById(R.id.editor_phone_home);
-        mMobilePhoneEditText = (EditText)findViewById(R.id.editor_phone_mobile);
-        mWorkPhoneEditText = (EditText)findViewById(R.id.editor_phone_work);
-        mEmailEditText = (EditText)findViewById(R.id.editor_email);
-
-        // Figure out whether we're creating a new contact (ACTION_INSERT), editing
-        // an existing contact, or adding a new one to existing contact (INVITE_CONTACT).
-        Intent intent = getIntent();
-        String action = intent.getAction();
-        if (Intent.ACTION_INSERT.equals(action)) {
-            // We're inserting a new contact, so save off the external account name
-            // which should have been added to the intent we were passed.
-            mIsInsert = true;
-            String accountName = intent.getStringExtra(RawContacts.ACCOUNT_NAME);
-            if (accountName == null) {
-                Log.e(TAG, "Account name is required");
-                finish();
-            }
-            setAccountName(accountName);
-        } else if (ContactsContract.Intents.INVITE_CONTACT.equals(action)) {
-            // Adding to an existing contact.
-            mIsInsert = true;
-            // Use the first account found.
-            Account[] myAccounts = AccountManager.get(this).getAccountsByType(
-                    Constants.ACCOUNT_TYPE);
-            if (myAccounts.length == 0) {
-                Log.e(TAG, "Account not configured");
-                finish();
-            }
-            setAccountName(myAccounts[0].name);
-
-            Uri lookupUri = intent.getData();
-            if (lookupUri == null) {
-                Log.e(TAG, "Contact lookup URI is required");
-                finish();
-            }
-            startLoadContactEntity(lookupUri);
-        } else {
-            // We're editing an existing contact. Load in the data from the contact
-            // so that the user can edit it.
-            mIsInsert = false;
-            mRawContactUri = intent.getData();
-            if (mRawContactUri == null) {
-                Log.e(TAG, "Raw contact URI is required");
-                finish();
-            }
-            startLoadRawContactEntity();
-        }
-    }
-
-    @Override
-    public void onBackPressed() {
-        // This method will have been called if the user presses the "Back" button
-        // in the ActionBar.  We treat that the same way as the "Done" button in
-        // the ActionBar.
-        save();
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        // This method gets called so that we can place items in the main Options menu -
-        // for example, the ActionBar items.  We add our menus from the res/menu/edit.xml
-        // file.
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.edit, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case android.R.id.home:
-            case R.id.menu_done:
-                // The user pressed the "Home" button or our "Done" button - both
-                // in the ActionBar.  In both cases, we want to save the contact
-                // and exit.
-                save();
-                return true;
-            case R.id.menu_cancel:
-                // The user pressed the Cancel menu item in the ActionBar.
-                // Close the editor without saving any changes.
-                finish();
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Create an AsyncTask to load the contact from the Contacts data provider
-     */
-    private void startLoadRawContactEntity() {
-        Uri uri = Uri.withAppendedPath(mRawContactUri, RawContacts.Entity.CONTENT_DIRECTORY);
-        new LoadRawContactTask().execute(uri);
-    }
-
-    /**
-     * Called by the LoadRawContactTask when the contact information has been
-     * successfully loaded from the Contacts data provider.
-     */
-    public void onRawContactEntityLoaded(Cursor cursor) {
-        if (cursor.moveToFirst()) {
-            String mimetype = cursor.getString(EditorQuery.COLUMN_MIMETYPE);
-            if (StructuredName.CONTENT_ITEM_TYPE.equals(mimetype)) {
-                setAccountName(cursor.getString(EditorQuery.COLUMN_ACCOUNT_NAME));
-                mRawContactId = cursor.getLong(EditorQuery.COLUMN_RAW_CONTACT_ID);
-                mNameEditText.setText(cursor.getString(EditorQuery.COLUMN_FULL_NAME));
-            } else if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
-                final int type = cursor.getInt(EditorQuery.COLUMN_PHONE_TYPE);
-                if (type == Phone.TYPE_HOME) {
-                    mHomePhoneEditText.setText(cursor.getString(EditorQuery.COLUMN_PHONE_NUMBER));
-                } else if (type == Phone.TYPE_MOBILE) {
-                    mMobilePhoneEditText.setText(cursor.getString(EditorQuery.COLUMN_PHONE_NUMBER));
-                } else if (type == Phone.TYPE_WORK) {
-                    mWorkPhoneEditText.setText(cursor.getString(EditorQuery.COLUMN_PHONE_NUMBER));
-                }
-            } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
-                mEmailEditText.setText(cursor.getString(EditorQuery.COLUMN_DATA1));
-            }
-        }
-    }
-
-    /**
-     * Create an AsyncTask to load the contact from the Contacts data provider
-     */
-    private void startLoadContactEntity(Uri lookupUri) {
-        new LoadContactTask().execute(lookupUri);
-    }
-
-    /**
-     * Called by the LoadContactTask when the contact information has been
-     * successfully loaded from the Contacts data provider.
-     */
-    public void onContactEntityLoaded(Cursor cursor) {
-        if (cursor.moveToFirst()) {
-            mNameEditText.setText(cursor.getString(ContactQuery.COLUMN_DISPLAY_NAME));
-        }
-    }
-
-    /**
-     * Save the updated contact data. We actually take two different actions
-     * depending on whether we are creating a new contact or editing an
-     * existing contact.
-     */
-    public void save() {
-        // If we're already saving this contact, don't kick-off yet
-        // another save - the user probably just pressed the "Done"
-        // button multiple times...
-        if (mSaveInProgress) {
-            return;
-        }
-
-        mSaveInProgress = true;
-        if (mIsInsert) {
-            saveNewContact();
-        } else {
-            saveChanges();
-        }
-    }
-
-    /**
-     * Save off the external contacts provider account name. We show the account name
-     * in the header section of the edit panel, and we also need it later when we
-     * save off a brand new contact.
-     */
-    private void setAccountName(String accountName) {
-        mAccountName = accountName;
-        Log.i(TAG, "account=" + mAccountName);
-        if (accountName != null) {
-            TextView accountNameLabel = (TextView)findViewById(R.id.header_account_name);
-            if (accountNameLabel != null) {
-                accountNameLabel.setText(accountName);
-            }
-        }
-    }
-
-    /**
-     * Save a new contact using the Contacts content provider. The actual insertion
-     * is performed in an AsyncTask.
-     */
-    @SuppressWarnings("unchecked")
-    private void saveNewContact() {
-        new InsertContactTask().execute(buildRawContact());
-    }
-
-    /**
-     * Save changes to an existing contact.  The actual update is performed in
-     * an AsyncTask.
-     */
-    @SuppressWarnings("unchecked")
-    private void saveChanges() {
-        new UpdateContactTask().execute(buildRawContact());
-    }
-
-    /**
-     * Build a RawContact object from the data in the user-editable form
-     * @return a new RawContact object representing the edited user
-     */
-    private RawContact buildRawContact() {
-        return RawContact.create(mNameEditText.getText().toString(),
-                null,
-                null,
-                mMobilePhoneEditText.getText().toString(),
-                mWorkPhoneEditText.getText().toString(),
-                mHomePhoneEditText.getText().toString(),
-                mEmailEditText.getText().toString(),
-                null,
-                false,
-                mRawContactId,
-                -1);
-    }
-
-    /**
-     * Called after a contact is saved - both for edited contacts and new contacts.
-     * We set the final result of the activity to be "ok", and then close the activity
-     * by calling finish().
-     */
-    public void onContactSaved(Uri result) {
-        if (result != null) {
-            Intent intent = new Intent();
-            intent.setData(result);
-            setResult(RESULT_OK, intent);
-            finish();
-        }
-        mSaveInProgress = false;
-    }
-
-    /**
-     * Represents an asynchronous task used to load a contact from
-     * the Contacts content provider.
-     *
-     */
-    public class LoadRawContactTask extends AsyncTask<Uri, Void, Cursor> {
-
-        @Override
-        protected Cursor doInBackground(Uri... params) {
-            // Our background task is to load the contact from the Contacts provider
-            return getContentResolver().query(params[0], EditorQuery.PROJECTION, null, null, null);
-        }
-
-        @Override
-        protected void onPostExecute(Cursor cursor) {
-            if (cursor == null) return;
-            // After we've successfully loaded the contact, call back into
-            // the ContactEditorActivity so we can update the UI
-            try {
-                onRawContactEntityLoaded(cursor);
-            } finally {
-                cursor.close();
-            }
-        }
-    }
-
-    /**
-     * Represents an asynchronous task used to save a new contact
-     * into the contacts database.
-     */
-    public class InsertContactTask extends AsyncTask<RawContact, Void, Uri> {
-
-        @Override
-        protected Uri doInBackground(RawContact... params) {
-            try {
-                final RawContact rawContact = params[0];
-                final Context context = getApplicationContext();
-                final ContentResolver resolver = getContentResolver();
-                final BatchOperation batchOperation = new BatchOperation(context, resolver);
-                ContactManager.addContact(context, mAccountName, rawContact, false, batchOperation);
-                Uri rawContactUri = batchOperation.execute();
-
-                // Convert the raw contact URI to a contact URI
-                if (rawContactUri != null) {
-                    return RawContacts.getContactLookupUri(resolver, rawContactUri);
-                } else {
-                    Log.e(TAG, "Could not save new contact");
-                    return null;
-                }
-            } catch (Exception e) {
-                Log.e(TAG, "An error occurred while saving new contact", e);
-            }
-            return null;
-        }
-
-        @Override
-        protected void onPostExecute(Uri result) {
-            // Tell the UI that the contact has been successfully saved
-            onContactSaved(result);
-        }
-    }
-
-
-    /**
-     * Represents an asynchronous task used to save an updated contact
-     * into the contacts database.
-     */
-    public class UpdateContactTask extends AsyncTask<RawContact, Void, Uri> {
-
-        @Override
-        protected Uri doInBackground(RawContact... params) {
-            try {
-                final RawContact rawContact = params[0];
-                final Context context = getApplicationContext();
-                final ContentResolver resolver = getContentResolver();
-                final BatchOperation batchOperation = new BatchOperation(context, resolver);
-                ContactManager.updateContact(context, resolver, rawContact, false, false, false,
-                        false, rawContact.getRawContactId(), batchOperation);
-                batchOperation.execute();
-
-                // Convert the raw contact URI to a contact URI
-                return RawContacts.getContactLookupUri(resolver, mRawContactUri);
-            } catch (Exception e) {
-                Log.e(TAG, "Could not save changes", e);
-            }
-            return null;
-        }
-
-        @Override
-        protected void onPostExecute(Uri result) {
-            // Tell the UI that the contact has been successfully saved
-            onContactSaved(result);
-        }
-    }
-
-    /**
-     * Loads contact information by a lookup URI.
-     */
-    public class LoadContactTask extends AsyncTask<Uri, Void, Cursor> {
-
-        @Override
-        protected Cursor doInBackground(Uri... params) {
-            return getContentResolver().query(params[0], ContactQuery.PROJECTION, null, null, null);
-        }
-
-        @Override
-        protected void onPostExecute(Cursor cursor) {
-            if (cursor == null) return;
-            try {
-                onContactEntityLoaded(cursor);
-            } finally {
-                cursor.close();
-            }
-        }
-    }
-}
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
index 035c976..6b2dfb1 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java
@@ -34,6 +34,7 @@
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Groups;
 import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.Settings;
 import android.provider.ContactsContract.StatusUpdates;
@@ -54,6 +55,41 @@
 
     private static final String TAG = "ContactManager";
 
+    public static final String SAMPLE_GROUP_NAME = "Sample Group";
+
+    public static long ensureSampleGroupExists(Context context, Account account) {
+        final ContentResolver resolver = context.getContentResolver();
+
+        // Lookup the sample group
+        long groupId = 0;
+        final Cursor cursor = resolver.query(Groups.CONTENT_URI, new String[] { Groups._ID },
+                Groups.ACCOUNT_NAME + "=? AND " + Groups.ACCOUNT_TYPE + "=? AND " +
+                Groups.TITLE + "=?",
+                new String[] { account.name, account.type, SAMPLE_GROUP_NAME }, null);
+        if (cursor != null) {
+            try {
+                if (cursor.moveToFirst()) {
+                    groupId = cursor.getLong(0);
+                }
+            } finally {
+                cursor.close();
+            }
+        }
+
+        if (groupId == 0) {
+            // Sample group doesn't exist yet, so create it
+            final ContentValues contentValues = new ContentValues();
+            contentValues.put(Groups.ACCOUNT_NAME, account.name);
+            contentValues.put(Groups.ACCOUNT_TYPE, account.type);
+            contentValues.put(Groups.TITLE, SAMPLE_GROUP_NAME);
+            contentValues.put(Groups.GROUP_IS_READ_ONLY, true);
+
+            final Uri newGroupUri = resolver.insert(Groups.CONTENT_URI, contentValues);
+            groupId = ContentUris.parseId(newGroupUri);
+        }
+        return groupId;
+    }
+
     /**
      * Take a list of updated contacts and apply those changes to the
      * contacts database. Typically this list of contacts would have been
@@ -67,7 +103,7 @@
      * sync request.
      */
     public static synchronized long updateContacts(Context context, String account,
-            List<RawContact> rawContacts, long lastSyncMarker) {
+            List<RawContact> rawContacts, long groupId, long lastSyncMarker) {
 
         long currentSyncMarker = lastSyncMarker;
         final ContentResolver resolver = context.getContentResolver();
@@ -112,7 +148,7 @@
                 Log.d(TAG, "In addContact");
                 if (!rawContact.isDeleted()) {
                     newUsers.add(rawContact);
-                    addContact(context, account, rawContact, true, batchOperation);
+                    addContact(context, account, rawContact, groupId, true, batchOperation);
                 }
             }
             // A sync adapter should batch operations on multiple contacts,
@@ -235,12 +271,13 @@
      * @param context the Authenticator Activity context
      * @param accountName the account the contact belongs to
      * @param rawContact the sample SyncAdapter User object
+     * @param groupId the id of the sample group
      * @param inSync is the add part of a client-server sync?
      * @param batchOperation allow us to batch together multiple operations
      *        into a single provider call
      */
     public static void addContact(Context context, String accountName, RawContact rawContact,
-        boolean inSync, BatchOperation batchOperation) {
+            long groupId, boolean inSync, BatchOperation batchOperation) {
 
         // Put the data in the contacts provider
         final ContactOperations contactOp = ContactOperations.createNewContact(
@@ -252,6 +289,7 @@
                 .addPhone(rawContact.getCellPhone(), Phone.TYPE_MOBILE)
                 .addPhone(rawContact.getHomePhone(), Phone.TYPE_HOME)
                 .addPhone(rawContact.getOfficePhone(), Phone.TYPE_WORK)
+                .addGroupMembership(groupId)
                 .addAvatar(rawContact.getAvatarUrl());
 
         // If we have a serverId, then go ahead and create our status profile.
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java
index cb8e97b..1445e55 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java
@@ -25,6 +25,7 @@
 import android.net.Uri;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
@@ -185,6 +186,20 @@
         return this;
     }
 
+    /**
+     * Adds a group membership
+     *
+     * @param id The id of the group to assign
+     * @return instance of ContactOperations
+     */
+    public ContactOperations addGroupMembership(long groupId) {
+        mValues.clear();
+        mValues.put(GroupMembership.GROUP_ROW_ID, groupId);
+        mValues.put(GroupMembership.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
+        addInsertOp();
+        return this;
+    }
+
     public ContactOperations addAvatar(String avatarUrl) {
         if (avatarUrl != null) {
             byte[] avatarBuffer = NetworkUtilities.downloadAvatar(avatarUrl);
diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
index 0ca8dee..0f570cd 100644
--- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
+++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java
@@ -15,6 +15,15 @@
  */
 package com.example.android.samplesync.syncadapter;
 
+import com.example.android.samplesync.Constants;
+import com.example.android.samplesync.client.NetworkUtilities;
+import com.example.android.samplesync.client.RawContact;
+import com.example.android.samplesync.platform.ContactManager;
+
+import org.apache.http.ParseException;
+import org.apache.http.auth.AuthenticationException;
+import org.json.JSONException;
+
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AuthenticatorException;
@@ -27,18 +36,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.example.android.samplesync.Constants;
-import com.example.android.samplesync.client.NetworkUtilities;
-import com.example.android.samplesync.client.RawContact;
-import com.example.android.samplesync.platform.ContactManager;
-
-import org.apache.http.ParseException;
-import org.apache.http.auth.AuthenticationException;
-import org.json.JSONException;
-
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 
 /**
@@ -91,6 +89,9 @@
             final String authtoken = mAccountManager.blockingGetAuthToken(account,
                     Constants.AUTHTOKEN_TYPE, NOTIFY_AUTH_FAILURE);
 
+            // Make sure that the sample group exists
+            final long groupId = ContactManager.ensureSampleGroupExists(mContext, account);
+
             // Find the local 'dirty' contacts that we need to tell the server about...
             // Find the local users that need to be sync'd to the server...
             dirtyContacts = ContactManager.getDirtyContacts(mContext, account);
@@ -106,6 +107,7 @@
             long newSyncState = ContactManager.updateContacts(mContext,
                     account.name,
                     updatedContacts,
+                    groupId,
                     lastSyncMarker);
 
             // This is a demo of how you can update IM-style status messages
diff --git a/samples/StackWidget/AndroidManifest.xml b/samples/StackWidget/AndroidManifest.xml
index 1fec157..25517f0 100644
--- a/samples/StackWidget/AndroidManifest.xml
+++ b/samples/StackWidget/AndroidManifest.xml
@@ -22,7 +22,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.example.android.stackwidget">
-    <uses-sdk android:targetSdkVersion="11" android:minSdkVersion="11"/>
+    <uses-sdk android:targetSdkVersion="14" android:minSdkVersion="11"/>
     <application android:label="StackWidget">
         <receiver android:name="StackWidgetProvider">
             <intent-filter>
diff --git a/samples/StackWidget/res/layout/widget_layout.xml b/samples/StackWidget/res/layout/widget_layout.xml
index 11f9d36..983c6fb 100644
--- a/samples/StackWidget/res/layout/widget_layout.xml
+++ b/samples/StackWidget/res/layout/widget_layout.xml
@@ -15,7 +15,8 @@
 -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:layout_margin="@dimen/widget_margin">
     <StackView xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/stack_view"
         android:layout_width="match_parent"
diff --git a/samples/SampleSyncAdapter/res/values/styles.xml b/samples/StackWidget/res/values-v14/dimens.xml
similarity index 64%
copy from samples/SampleSyncAdapter/res/values/styles.xml
copy to samples/StackWidget/res/values-v14/dimens.xml
index 074613e..2626bc3 100644
--- a/samples/SampleSyncAdapter/res/values/styles.xml
+++ b/samples/StackWidget/res/values-v14/dimens.xml
@@ -13,15 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
 <resources>
-    <!--
-        These styles will only be used in Honeycomb and later because
-        Android doesn't support third-party contact editing in pre-
-        Honeycomb versions.
-    -->
-    <color name="EditPanelBackgroundColor">#ffffff</color>
-    <color name="EditPanelBorderColor">#cccccc</color>
-    <style name="ContactEditTheme" parent="android:Theme.Holo.Light">
-    </style>
+    <dimen name="widget_margin">0dp</dimen>
 </resources>
diff --git a/samples/SampleSyncAdapter/res/values/styles.xml b/samples/StackWidget/res/values/dimens.xml
similarity index 64%
copy from samples/SampleSyncAdapter/res/values/styles.xml
copy to samples/StackWidget/res/values/dimens.xml
index 074613e..aa8a9e2 100644
--- a/samples/SampleSyncAdapter/res/values/styles.xml
+++ b/samples/StackWidget/res/values/dimens.xml
@@ -13,15 +13,6 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
 <resources>
-    <!--
-        These styles will only be used in Honeycomb and later because
-        Android doesn't support third-party contact editing in pre-
-        Honeycomb versions.
-    -->
-    <color name="EditPanelBackgroundColor">#ffffff</color>
-    <color name="EditPanelBorderColor">#cccccc</color>
-    <style name="ContactEditTheme" parent="android:Theme.Holo.Light">
-    </style>
+    <dimen name="widget_margin">8dp</dimen>
 </resources>
diff --git a/samples/StackWidget/res/xml/stackwidgetinfo.xml b/samples/StackWidget/res/xml/stackwidgetinfo.xml
index 6f59605..2a587e1 100644
--- a/samples/StackWidget/res/xml/stackwidgetinfo.xml
+++ b/samples/StackWidget/res/xml/stackwidgetinfo.xml
@@ -15,11 +15,13 @@
 -->
 <appwidget-provider
   xmlns:android="http://schemas.android.com/apk/res/android"
-  android:minWidth="150dip"
-  android:minHeight="150dip"
+  android:minWidth="110dip"
+  android:minHeight="110dip"
   android:updatePeriodMillis="3600000"
   android:previewImage="@drawable/preview"
   android:initialLayout="@layout/widget_layout"
-  android:autoAdvanceViewId="@id/stack_view"
-  android:resizeMode="horizontal|vertical">
+  android:autoAdvanceViewId="@id/stack_view">
 </appwidget-provider>
+<!--to enable resizing:
+ android:resizeMode="horizontal|vertical" -->
+ 
\ No newline at end of file
diff --git a/samples/VoicemailProviderDemo/AndroidManifest.xml b/samples/VoicemailProviderDemo/AndroidManifest.xml
index 558dbf7..f70c248 100644
--- a/samples/VoicemailProviderDemo/AndroidManifest.xml
+++ b/samples/VoicemailProviderDemo/AndroidManifest.xml
@@ -23,8 +23,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     android:versionCode="1" android:versionName="1.0" package="com.example.android.voicemail">
 
-    <uses-sdk android:minSdkVersion="13"
-              android:targetSdkVersion="13" />
+    <uses-sdk android:minSdkVersion="14"
+              android:targetSdkVersion="14" />
 
     <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/AddVoicemailActivity.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/AddVoicemailActivity.java
index 121840a..2adb0c4 100644
--- a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/AddVoicemailActivity.java
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/AddVoicemailActivity.java
@@ -206,13 +206,10 @@
             Uri newVoicemailUri = mVoicemailProviderHelper.insert(voicemail);
             logger.i("Inserted new voicemail URI: " + newVoicemailUri);
             if (inputAudioStream != null) {
-                OutputStream outputStream = null;
                 try {
-                    outputStream = mVoicemailProviderHelper.setVoicemailContent(
-                            newVoicemailUri, getContentResolver().getType(recordingUri));
-                    copyStreamData(inputAudioStream, outputStream);
+                    mVoicemailProviderHelper.setVoicemailContent(newVoicemailUri, inputAudioStream,
+                            getContentResolver().getType(recordingUri));
                 } finally {
-                    CloseUtils.closeQuietly(outputStream);
                     CloseUtils.closeQuietly(inputAudioStream);
                 }
             }
@@ -228,13 +225,5 @@
             }
         }
 
-        private void copyStreamData(InputStream in, OutputStream out) throws IOException {
-            // Copy 8K chunk at a time.
-            byte[] data = new byte[8 * 1024];
-            int numBytes;
-            while ((numBytes = in.read(data)) > 0) {
-                out.write(data, 0, numBytes);
-            }
-        }
     }
 }
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelper.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelper.java
index 9cb6a3b..918aa4a 100644
--- a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelper.java
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelper.java
@@ -21,7 +21,7 @@
 import android.net.Uri;
 
 import java.io.IOException;
-import java.io.OutputStream;
+import java.io.InputStream;
 import java.util.List;
 
 /**
@@ -99,14 +99,25 @@
     public int update(Uri uri, Voicemail voicemail);
 
     /**
-     * Get the OutputStream to write the voicemail content with the given mime type.
+     * Sets the voicemail content from the supplied input stream.
      * <p>
-     * <b>Remember to close the OutputStream after you're done writing.</b>
+     * The inputStream is owned by the caller and must be closed by it as usual after the call has
+     * returned.
      *
      * @throws IOException if there is a problem creating the file or no voicemail is found matching
      *             the given Uri
      */
-    public OutputStream setVoicemailContent(Uri voicemailUri, String mimeType) throws IOException;
+    public void setVoicemailContent(Uri voicemailUri, InputStream inputStream, String mimeType)
+            throws IOException;
+
+    /**
+     * Sets the voicemail content from the supplied byte array.
+     *
+     * @throws IOException if there is a problem creating the file or no voicemail is found matching
+     *             the given Uri
+     */
+    public void setVoicemailContent(Uri voicemailUri, byte[] inputBytes, String mimeType)
+            throws IOException;
 
     /**
      * Fetch all the voicemails accessible to this voicemail content provider.
diff --git a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelpers.java b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelpers.java
index 1840462..27c7f69 100644
--- a/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelpers.java
+++ b/samples/VoicemailProviderDemo/src/com/example/android/voicemail/common/core/VoicemailProviderHelpers.java
@@ -30,6 +30,7 @@
 import android.provider.VoicemailContract.Voicemails;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
@@ -114,16 +115,45 @@
     }
 
     @Override
-    public OutputStream setVoicemailContent(Uri voicemailUri, String mimeType) throws IOException {
+    public void setVoicemailContent(Uri voicemailUri, InputStream inputStream, String mimeType)
+            throws IOException {
+        setVoicemailContent(voicemailUri, null, inputStream, mimeType);
+    }
+
+    @Override
+    public void setVoicemailContent(Uri voicemailUri, byte[] inputBytes, String mimeType)
+            throws IOException {
+        setVoicemailContent(voicemailUri, inputBytes, null, mimeType);
+    }
+
+    private void setVoicemailContent(Uri voicemailUri, byte[] inputBytes, InputStream inputStream,
+            String mimeType) throws IOException {
+        if (inputBytes != null && inputStream != null) {
+            throw new IllegalArgumentException("Both inputBytes & inputStream non-null. Don't" +
+                    " know which one to use.");
+        }
+
+        logger.d(String.format("Writing new voicemail content: %s", voicemailUri));
+        OutputStream outputStream = null;
+        try {
+            outputStream = mContentResolver.openOutputStream(voicemailUri);
+            if (inputBytes != null) {
+                outputStream.write(inputBytes);
+            } else if (inputStream != null) {
+                copyStreamData(inputStream, outputStream);
+            }
+        } finally {
+            CloseUtils.closeQuietly(outputStream);
+        }
+        // Update mime_type & has_content after we are done with file update.
         ContentValues values = new ContentValues();
         values.put(Voicemails.MIME_TYPE, mimeType);
+        values.put(Voicemails.HAS_CONTENT, true);
         int updatedCount = mContentResolver.update(voicemailUri, values, null, null);
         if (updatedCount != 1) {
             throw new IOException("Updating voicemail should have updated 1 row, was: "
                     + updatedCount);
         }
-        logger.d(String.format("Writing new voicemail content: %s", voicemailUri));
-        return mContentResolver.openOutputStream(voicemailUri);
     }
 
     @Override
@@ -288,4 +318,13 @@
         }
         return contentValues;
     }
+
+    private void copyStreamData(InputStream in, OutputStream out) throws IOException {
+        byte[] data = new byte[8 * 1024];
+        int numBytes;
+        while ((numBytes = in.read(data)) > 0) {
+            out.write(data, 0, numBytes);
+        }
+
+    }
 }
diff --git a/samples/WeatherListWidget/AndroidManifest.xml b/samples/WeatherListWidget/AndroidManifest.xml
index cfb2372..7b1638f 100644
--- a/samples/WeatherListWidget/AndroidManifest.xml
+++ b/samples/WeatherListWidget/AndroidManifest.xml
@@ -21,7 +21,9 @@
      to come from a domain that you own or have control over. -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.example.android.weatherlistwidget">
-    <uses-sdk android:minSdkVersion="11" />
+
+    <uses-sdk android:minSdkVersion="11"
+              android:targetSdkVersion="14"/>
     <application android:label="Weather Widget Sample">
         <!-- The widget provider -->
         <receiver android:name="WeatherWidgetProvider">
@@ -42,4 +44,4 @@
         <provider android:name="WeatherDataProvider"
               android:authorities="com.example.android.weatherlistwidget.provider" />
     </application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/samples/WeatherListWidget/res/drawable-hdpi/body.png b/samples/WeatherListWidget/res/drawable-hdpi/body.png
index 0a2c1d1..17d303f 100644
--- a/samples/WeatherListWidget/res/drawable-hdpi/body.png
+++ b/samples/WeatherListWidget/res/drawable-hdpi/body.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-hdpi/footer.png b/samples/WeatherListWidget/res/drawable-hdpi/footer.png
index 73cc95c..43962f7 100644
--- a/samples/WeatherListWidget/res/drawable-hdpi/footer.png
+++ b/samples/WeatherListWidget/res/drawable-hdpi/footer.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-hdpi/header.9.png b/samples/WeatherListWidget/res/drawable-hdpi/header.9.png
new file mode 100644
index 0000000..5f34768
--- /dev/null
+++ b/samples/WeatherListWidget/res/drawable-hdpi/header.9.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-hdpi/header.png b/samples/WeatherListWidget/res/drawable-hdpi/header.png
deleted file mode 100644
index e659aee..0000000
--- a/samples/WeatherListWidget/res/drawable-hdpi/header.png
+++ /dev/null
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-hdpi/item_bg_dark.png b/samples/WeatherListWidget/res/drawable-hdpi/item_bg_dark.png
index 5097ab7..f5886bd 100644
--- a/samples/WeatherListWidget/res/drawable-hdpi/item_bg_dark.png
+++ b/samples/WeatherListWidget/res/drawable-hdpi/item_bg_dark.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-hdpi/item_bg_light.png b/samples/WeatherListWidget/res/drawable-hdpi/item_bg_light.png
index 019f36c..e8b5aaf 100644
--- a/samples/WeatherListWidget/res/drawable-hdpi/item_bg_light.png
+++ b/samples/WeatherListWidget/res/drawable-hdpi/item_bg_light.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-hdpi/refresh.png b/samples/WeatherListWidget/res/drawable-hdpi/refresh.png
index 2847773..eaec9cb 100644
--- a/samples/WeatherListWidget/res/drawable-hdpi/refresh.png
+++ b/samples/WeatherListWidget/res/drawable-hdpi/refresh.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-hdpi/refresh_pressed.png b/samples/WeatherListWidget/res/drawable-hdpi/refresh_pressed.png
index 820cc36..34438b7 100644
--- a/samples/WeatherListWidget/res/drawable-hdpi/refresh_pressed.png
+++ b/samples/WeatherListWidget/res/drawable-hdpi/refresh_pressed.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-ldpi/body.png b/samples/WeatherListWidget/res/drawable-ldpi/body.png
deleted file mode 100644
index 3ce4276..0000000
--- a/samples/WeatherListWidget/res/drawable-ldpi/body.png
+++ /dev/null
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-ldpi/footer.png b/samples/WeatherListWidget/res/drawable-ldpi/footer.png
deleted file mode 100644
index ab89bf3..0000000
--- a/samples/WeatherListWidget/res/drawable-ldpi/footer.png
+++ /dev/null
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-ldpi/header.png b/samples/WeatherListWidget/res/drawable-ldpi/header.png
deleted file mode 100644
index ff29577..0000000
--- a/samples/WeatherListWidget/res/drawable-ldpi/header.png
+++ /dev/null
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-ldpi/item_bg_dark.png b/samples/WeatherListWidget/res/drawable-ldpi/item_bg_dark.png
deleted file mode 100644
index c945b5f..0000000
--- a/samples/WeatherListWidget/res/drawable-ldpi/item_bg_dark.png
+++ /dev/null
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-ldpi/item_bg_light.png b/samples/WeatherListWidget/res/drawable-ldpi/item_bg_light.png
deleted file mode 100644
index a14b9a6..0000000
--- a/samples/WeatherListWidget/res/drawable-ldpi/item_bg_light.png
+++ /dev/null
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-ldpi/refresh.png b/samples/WeatherListWidget/res/drawable-ldpi/refresh.png
deleted file mode 100644
index d08343c..0000000
--- a/samples/WeatherListWidget/res/drawable-ldpi/refresh.png
+++ /dev/null
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-ldpi/refresh_pressed.png b/samples/WeatherListWidget/res/drawable-ldpi/refresh_pressed.png
deleted file mode 100644
index 3da3ae6..0000000
--- a/samples/WeatherListWidget/res/drawable-ldpi/refresh_pressed.png
+++ /dev/null
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-mdpi/body.png b/samples/WeatherListWidget/res/drawable-mdpi/body.png
index 5331a9a..a08d03b 100644
--- a/samples/WeatherListWidget/res/drawable-mdpi/body.png
+++ b/samples/WeatherListWidget/res/drawable-mdpi/body.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-mdpi/footer.png b/samples/WeatherListWidget/res/drawable-mdpi/footer.png
index ca8b7ec..d3960a7 100644
--- a/samples/WeatherListWidget/res/drawable-mdpi/footer.png
+++ b/samples/WeatherListWidget/res/drawable-mdpi/footer.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-mdpi/header.9.png b/samples/WeatherListWidget/res/drawable-mdpi/header.9.png
new file mode 100644
index 0000000..2372225
--- /dev/null
+++ b/samples/WeatherListWidget/res/drawable-mdpi/header.9.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-mdpi/header.png b/samples/WeatherListWidget/res/drawable-mdpi/header.png
deleted file mode 100644
index 5452abf..0000000
--- a/samples/WeatherListWidget/res/drawable-mdpi/header.png
+++ /dev/null
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-mdpi/item_bg_dark.png b/samples/WeatherListWidget/res/drawable-mdpi/item_bg_dark.png
index 5ae5480..a3ac9d7 100644
--- a/samples/WeatherListWidget/res/drawable-mdpi/item_bg_dark.png
+++ b/samples/WeatherListWidget/res/drawable-mdpi/item_bg_dark.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-mdpi/item_bg_light.png b/samples/WeatherListWidget/res/drawable-mdpi/item_bg_light.png
index 5696944..ec6f5aa 100644
--- a/samples/WeatherListWidget/res/drawable-mdpi/item_bg_light.png
+++ b/samples/WeatherListWidget/res/drawable-mdpi/item_bg_light.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-mdpi/refresh.png b/samples/WeatherListWidget/res/drawable-mdpi/refresh.png
index 569b360..006bcc5 100644
--- a/samples/WeatherListWidget/res/drawable-mdpi/refresh.png
+++ b/samples/WeatherListWidget/res/drawable-mdpi/refresh.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-mdpi/refresh_pressed.png b/samples/WeatherListWidget/res/drawable-mdpi/refresh_pressed.png
index 5f10662..d8ca9b5 100644
--- a/samples/WeatherListWidget/res/drawable-mdpi/refresh_pressed.png
+++ b/samples/WeatherListWidget/res/drawable-mdpi/refresh_pressed.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/layout/widget_layout.xml b/samples/WeatherListWidget/res/layout/widget_layout.xml
index 4b09efc..4c58fa7 100644
--- a/samples/WeatherListWidget/res/layout/widget_layout.xml
+++ b/samples/WeatherListWidget/res/layout/widget_layout.xml
@@ -14,9 +14,15 @@
      limitations under the License.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="294dp"
+    android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:layout_marginTop="@dimen/widget_margin_top"
+    android:layout_marginBottom="@dimen/widget_margin_bottom"
+    android:layout_marginLeft="@dimen/widget_margin_left"
+    android:layout_marginRight="@dimen/widget_margin_right">
+    <!-- We define separate margins to allow for flexibility in twiddling the margins
+         depending on device form factor and target SDK version. -->
     <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
@@ -24,12 +30,14 @@
             android:id="@+id/header"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:scaleType="fitXY"
             android:src="@drawable/header" />
         <ImageButton
             android:id="@+id/refresh"
             android:layout_width="56dp"
             android:layout_height="39dp"
-            android:layout_marginLeft="222dp"
+            android:layout_gravity="right|top"
+            android:layout_marginRight="15dp"
             android:layout_marginTop="20dp"
             android:background="@drawable/refresh_button" />
     </FrameLayout>
@@ -57,5 +65,6 @@
         android:id="@+id/footer"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:scaleType="fitXY"
         android:src="@drawable/footer" />
 </LinearLayout>
diff --git a/samples/SampleSyncAdapter/res/values/styles.xml b/samples/WeatherListWidget/res/values-v14/dimens.xml
similarity index 64%
copy from samples/SampleSyncAdapter/res/values/styles.xml
copy to samples/WeatherListWidget/res/values-v14/dimens.xml
index 074613e..8b5494e 100644
--- a/samples/SampleSyncAdapter/res/values/styles.xml
+++ b/samples/WeatherListWidget/res/values-v14/dimens.xml
@@ -13,15 +13,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
 <resources>
-    <!--
-        These styles will only be used in Honeycomb and later because
-        Android doesn't support third-party contact editing in pre-
-        Honeycomb versions.
-    -->
-    <color name="EditPanelBackgroundColor">#ffffff</color>
-    <color name="EditPanelBorderColor">#cccccc</color>
-    <style name="ContactEditTheme" parent="android:Theme.Holo.Light">
-    </style>
+    <dimen name="widget_margin_top">0dp</dimen>
+    <dimen name="widget_margin_bottom">0dp</dimen>
+    <dimen name="widget_margin_left">0dp</dimen>
+    <dimen name="widget_margin_right">0dp</dimen>
 </resources>
diff --git a/samples/SampleSyncAdapter/res/values/styles.xml b/samples/WeatherListWidget/res/values/dimens.xml
similarity index 64%
copy from samples/SampleSyncAdapter/res/values/styles.xml
copy to samples/WeatherListWidget/res/values/dimens.xml
index 074613e..00257a9 100644
--- a/samples/SampleSyncAdapter/res/values/styles.xml
+++ b/samples/WeatherListWidget/res/values/dimens.xml
@@ -13,15 +13,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
 <resources>
-    <!--
-        These styles will only be used in Honeycomb and later because
-        Android doesn't support third-party contact editing in pre-
-        Honeycomb versions.
-    -->
-    <color name="EditPanelBackgroundColor">#ffffff</color>
-    <color name="EditPanelBorderColor">#cccccc</color>
-    <style name="ContactEditTheme" parent="android:Theme.Holo.Light">
-    </style>
-</resources>
+    <dimen name="widget_margin_top">8dp</dimen>
+    <dimen name="widget_margin_bottom">8dp</dimen>
+    <dimen name="widget_margin_left">8dp</dimen>
+    <dimen name="widget_margin_right">8dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/samples/WeatherListWidget/res/xml/widgetinfo.xml b/samples/WeatherListWidget/res/xml/widgetinfo.xml
index af64106..e6e9cf3 100644
--- a/samples/WeatherListWidget/res/xml/widgetinfo.xml
+++ b/samples/WeatherListWidget/res/xml/widgetinfo.xml
@@ -15,10 +15,12 @@
 -->
 <appwidget-provider
   xmlns:android="http://schemas.android.com/apk/res/android"
-  android:minWidth="222dip"
-  android:minHeight="222dip"
+  android:minWidth="250dp"
+  android:minHeight="180dp"
   android:updatePeriodMillis="1800000"
   android:initialLayout="@layout/widget_layout"
   android:resizeMode="vertical"
+  android:minResizeWidth="250dp"
+  android:minResizeHeight="110dp"
   android:previewImage="@drawable/preview">
 </appwidget-provider>
diff --git a/samples/WeatherListWidget/src/com/example/android/weatherlistwidget/WeatherWidgetService.java b/samples/WeatherListWidget/src/com/example/android/weatherlistwidget/WeatherWidgetService.java
index e0bc682..1d3c349 100644
--- a/samples/WeatherListWidget/src/com/example/android/weatherlistwidget/WeatherWidgetService.java
+++ b/samples/WeatherListWidget/src/com/example/android/weatherlistwidget/WeatherWidgetService.java
@@ -123,4 +123,4 @@
         mCursor = mContext.getContentResolver().query(WeatherDataProvider.CONTENT_URI, null, null,
                 null, null);
     }
-}
\ No newline at end of file
+}
diff --git a/samples/WiFiDirectDemo/Android.mk b/samples/WiFiDirectDemo/Android.mk
new file mode 100644
index 0000000..f77bb85
--- /dev/null
+++ b/samples/WiFiDirectDemo/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := samples
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := WiFiDirectDemo
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/samples/WiFiDirectDemo/AndroidManifest.xml b/samples/WiFiDirectDemo/AndroidManifest.xml
new file mode 100644
index 0000000..993716f
--- /dev/null
+++ b/samples/WiFiDirectDemo/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.wifidirect"
+    android:versionCode="1" android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="14" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <!-- Market filtering --> 
+    <uses-feature android:name="android.hardware.wifi.direct" android:required="true"/>
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@android:style/Theme.Holo">
+        <activity
+            android:name=".WiFiDirectActivity"
+            android:label="@string/app_name" android:launchMode="singleTask">
+            <intent-filter>
+                <action
+                    android:name="android.intent.action.MAIN" />
+                <category
+                    android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <!-- Used for transferring files  after a successful connection -->
+        <service android:enabled="true" android:name=".FileTransferService" />
+
+    </application>
+</manifest>
diff --git a/samples/WiFiDirectDemo/_index.html b/samples/WiFiDirectDemo/_index.html
new file mode 100644
index 0000000..07fb190
--- /dev/null
+++ b/samples/WiFiDirectDemo/_index.html
@@ -0,0 +1,49 @@
+<p>This is a demo application highlighting how to make peer to peer network connections with
+the Wi-Fi Direct APIs.  The application allows you to transfer jpeg images from the gallery after a succesful connection.</p>
+
+<p>The source code for this demo app shows how to accomplish three key things
+with Wi-Fi Direct APIs: Discovering peers, connecting using Wi-Fi Direct APIs, and finding group details post connection, so that a 
+TCP socket can be opened to transfer files.</p>
+
+<p>The application includes:<p>
+<ul> <li><a
+    href="src/com/example/android/wifidirect/WiFiDirectActivity.html"><code>WiFiDirectActivity</code></a>
+  &mdash; the main <code>Activity</code> that contains two fragments to handle app's UI and peer lifecycle. It also registers a broadcast receiver for Wi-Fi Direct related events.</li> <li><a
+    href="src/com/example/android/wifidirect/WiFiDirectBroadcastReceiver.html"><code>
+      WiFiDirectBroadcastReceiver</code></a> &mdash; a <code>BroadcastReceiver</code>
+  that listens for Wi-Fi Direct related events and passes them to
+  <code>WiFiDirectActivity</code> and it's fragments for neccesary action.</li> <li><a
+    href="src/com/example/android/wifidirect/DeviceListFragment.html"><code>DeviceListFragment</code></a>
+  &mdash; a <code>ListFragment</code> that displays available peers and their status. </li>
+<li><a href="src/com/example/android/wifidirect/DeviceDetailFragment.html"><code>DeviceDetailFragment</code></a>
+  &mdash; a <code>Fragment</code> that displays the details of the selected device and also drives the connection, disonnection and data transfer functionality of the demo. </li>
+<li><a href="src/com/example/android/wifidirect/FileTransferService.html"><code>FileTransferService</code></a>
+  &mdash; an <code>IntentService</code> that services file transfer requests from the application by using TCP sockets. </li> </ul>
+<p>If you are developing an application that uses the Wi-Fi Direct APIs, remember that the
+feature is supported only on Android 4.0 (API level 14) and higher versions of
+the platform. To ensure that your application can only
+be installed on devices that are capable of supporting Wi-Fi Direct mode, remember to add the
+following to the application's manifest before publishing to Android Market:</p>
+<ul> <li><code>&lt;uses-sdk android:minSdkVersion="14" /&gt;</code>, which
+  indicates to Android Market and the platform that your application requires
+  Android 4.0 or higher. For more information, see <a
+    href="../../../guide/appendix/api-levels.html">API Levels</a> and the
+  documentation for the <a
+    href="../../../guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
+  element.</li> </ul> <p>To control how Android Market filters your application
+from devices that do not support Wi-Fi Direct mode, remember to add the following to the
+application's manifest <ul> <li><code>&lt;uses-feature
+    android:name="android.hardware.wifi.direct" /&gt;</code>, which tells Android
+  Market that your application uses the Wi-Fi Direct API. The declaration should include
+  an <code>android:required</code> attribute that indicates whether you want
+  Android Market to filter the application from devices that do not offer Wi-Fi Direct support. Other <code>&lt;uses-feature&gt;</code> declarations may also be
+  needed, depending on your implementation. For more information, see the
+  documentation for the <a
+    href="../../../guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
+  element.</li> </ul>
+<p>For more information about using the Wi-Fi Direct API, see the <a
+  href="../../../reference/android/net/wifi/p2p/package-summary.html"><code>android.net.wifi.p2p	</a></code>
+documentation. </p>
+
+<img alt="" src="../images/WifiDirect.png" />
+
diff --git a/samples/WiFiDirectDemo/assets/sample_file.txt b/samples/WiFiDirectDemo/assets/sample_file.txt
new file mode 100644
index 0000000..504dbf5
--- /dev/null
+++ b/samples/WiFiDirectDemo/assets/sample_file.txt
@@ -0,0 +1,3 @@
+This is a sample text file for wifi_direct demo. 
+
+Once the devices are connected, the server i.e. groupOwner will listen for incoming connections and write this file. 
\ No newline at end of file
diff --git a/samples/WiFiDirectDemo/res/drawable-hdpi/ic_action_discover.png b/samples/WiFiDirectDemo/res/drawable-hdpi/ic_action_discover.png
new file mode 100644
index 0000000..98241d7
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-hdpi/ic_action_discover.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-hdpi/ic_action_on_off.png b/samples/WiFiDirectDemo/res/drawable-hdpi/ic_action_on_off.png
new file mode 100644
index 0000000..5eabf08
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-hdpi/ic_action_on_off.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-hdpi/ic_launcher.png b/samples/WiFiDirectDemo/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..f2a2f25
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-hdpi/icon.png b/samples/WiFiDirectDemo/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-ldpi/ic_action_discover.png b/samples/WiFiDirectDemo/res/drawable-ldpi/ic_action_discover.png
new file mode 100644
index 0000000..12849ed
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-ldpi/ic_action_discover.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-ldpi/ic_action_on_off.png b/samples/WiFiDirectDemo/res/drawable-ldpi/ic_action_on_off.png
new file mode 100644
index 0000000..e84700a
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-ldpi/ic_action_on_off.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-ldpi/ic_launcher.png b/samples/WiFiDirectDemo/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..002dae2
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/samples/WeatherListWidget/res/drawable-ldpi/icon.png b/samples/WiFiDirectDemo/res/drawable-ldpi/icon.png
similarity index 100%
copy from samples/WeatherListWidget/res/drawable-ldpi/icon.png
copy to samples/WiFiDirectDemo/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-mdpi/ic_action_discover.png b/samples/WiFiDirectDemo/res/drawable-mdpi/ic_action_discover.png
new file mode 100644
index 0000000..bd71a10
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-mdpi/ic_action_discover.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-mdpi/ic_action_on_off.png b/samples/WiFiDirectDemo/res/drawable-mdpi/ic_action_on_off.png
new file mode 100644
index 0000000..8e49066
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-mdpi/ic_action_on_off.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-mdpi/ic_launcher.png b/samples/WiFiDirectDemo/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c3792d0
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-mdpi/icon.png b/samples/WiFiDirectDemo/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-xhdpi/ic_action_discover.png b/samples/WiFiDirectDemo/res/drawable-xhdpi/ic_action_discover.png
new file mode 100644
index 0000000..543e2a0
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-xhdpi/ic_action_discover.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-xhdpi/ic_action_on_off.png b/samples/WiFiDirectDemo/res/drawable-xhdpi/ic_action_on_off.png
new file mode 100644
index 0000000..3d30ac9
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-xhdpi/ic_action_on_off.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable-xhdpi/ic_launcher.png b/samples/WiFiDirectDemo/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..c6d8a02
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable/details_view.xml b/samples/WiFiDirectDemo/res/drawable/details_view.xml
new file mode 100644
index 0000000..06fb95a
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable/details_view.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    
+    <solid android:color="@color/layout_border_color"/>
+    <stroke
+        android:width="4dp"
+        android:color="@android:color/background_dark" />
+    <padding
+        android:left="10dp"
+        android:top="2dp"
+        android:right="10dp"
+        android:bottom="2dp" />
+</shape>
diff --git a/samples/WiFiDirectDemo/res/drawable/machine.png b/samples/WiFiDirectDemo/res/drawable/machine.png
new file mode 100644
index 0000000..d61609a
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable/machine.png
Binary files differ
diff --git a/samples/WiFiDirectDemo/res/drawable/section_header.xml b/samples/WiFiDirectDemo/res/drawable/section_header.xml
new file mode 100644
index 0000000..22344dc
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/drawable/section_header.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <stroke
+        android:width="2dp"
+        android:color="@color/layout_border_color" />
+
+    <padding
+        android:left="10dp"
+        android:top="5dp"
+        android:right="10dp"
+        android:bottom="2dp" />
+    <corners
+        android:radius="2dp" />
+</shape>
diff --git a/samples/WiFiDirectDemo/res/layout-land/main.xml b/samples/WiFiDirectDemo/res/layout-land/main.xml
new file mode 100644
index 0000000..55b0d09
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/layout-land/main.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:id="@+id/linearLayout1"
+        android:layout_height="match_parent"
+        android:orientation="horizontal">
+        <fragment
+            class="com.example.android.wifidirect.DeviceListFragment"
+            android:id="@+id/frag_list"
+            android:layout_width="@dimen/phone_list_height"
+            android:layout_height="match_parent">
+            <!-- Preview: layout=@layout/row_devices -->
+        </fragment>
+        <fragment
+            class="com.example.android.wifidirect.DeviceDetailFragment"
+            android:id="@+id/frag_detail"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <!-- Preview: layout=@layout/device_detail -->
+        </fragment>
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/WiFiDirectDemo/res/layout-large/main.xml b/samples/WiFiDirectDemo/res/layout-large/main.xml
new file mode 100644
index 0000000..b278d64
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/layout-large/main.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    <LinearLayout android:layout_width="match_parent" android:id="@+id/linearLayout1"
+        android:layout_height="fill_parent" android:orientation="horizontal">
+        <fragment class="com.example.android.wifidirect.DeviceListFragment"
+            android:id="@+id/frag_list" android:layout_width="@dimen/tablet_list_width"
+            android:layout_height="match_parent">
+            <!-- Preview: layout=@layout/row_devices -->
+        </fragment>
+        <fragment class="com.example.android.wifidirect.DeviceDetailFragment"
+            android:id="@+id/frag_detail" android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <!-- Preview: layout=@layout/device_detail -->
+        </fragment>
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/WiFiDirectDemo/res/layout/device_detail.xml b/samples/WiFiDirectDemo/res/layout/device_detail.xml
new file mode 100644
index 0000000..40509b1
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/layout/device_detail.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="fill_parent"
+    android:background="@drawable/details_view"
+    android:visibility="gone">
+    <LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <LinearLayout
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+            <Button
+                android:id="@+id/btn_connect"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/connect_peer_button" />
+            <Button
+                android:id="@+id/btn_disconnect"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/disconnect_peer_button" />
+            <Button
+                android:id="@+id/btn_start_client"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/get_file_button"
+                android:visibility="gone" />
+        </LinearLayout>
+        <TextView
+            android:id="@+id/device_address"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+        <TextView
+            android:id="@+id/device_info"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+        <TextView
+            android:id="@+id/group_owner"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+        <TextView
+            android:id="@+id/group_ip"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:id="@+id/status_bar"
+        android:orientation="vertical"
+        android:layout_gravity="bottom"
+        android:layout_height="37dp"
+        android:layout_marginBottom="3dp"
+        android:background="@android:color/background_dark">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:layout_margin="5dp"
+            android:textColor="@android:color/white"
+            android:id="@+id/status_text">
+        </TextView>
+    </LinearLayout>
+</FrameLayout>
diff --git a/samples/WiFiDirectDemo/res/layout/device_list.xml b/samples/WiFiDirectDemo/res/layout/device_list.xml
new file mode 100644
index 0000000..2d91566
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/layout/device_list.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingTop="3dp">
+
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:text="@string/label_me" />
+    <View
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:gravity="center_vertical"
+        android:background="@android:color/holo_blue_light" />
+
+    <!-- Self information -->
+    <LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="fill_parent"
+        android:layout_height="?android:attr/listPreferredItemHeight"
+        android:background="?android:attr/activatedBackgroundIndicator"
+        android:padding="3dip">
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_marginRight="2dp"
+            android:src="@drawable/machine" />
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="fill_parent">
+            <TextView
+                android:id="@+id/my_name"
+                android:layout_width="fill_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:gravity="center_vertical" />
+            <TextView
+                android:id="@+id/my_status"
+                android:layout_width="fill_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:singleLine="true"
+                android:ellipsize="marquee" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:text="@string/label_peers" />
+
+    <View
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:gravity="center_vertical"
+        android:background="@android:color/holo_blue_light" />
+
+    <!-- Available peers -->
+    <ListView
+        android:id="@id/android:list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:drawSelectorOnTop="false" />
+
+    <TextView
+        android:id="@id/android:empty"
+        android:layout_width="match_parent"
+        android:layout_gravity="center"
+        android:layout_height="match_parent"
+        android:text="@string/empty_message" />
+</LinearLayout>
diff --git a/samples/WiFiDirectDemo/res/layout/main.xml b/samples/WiFiDirectDemo/res/layout/main.xml
new file mode 100644
index 0000000..70151d5
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/layout/main.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:id="@+id/linearLayout1"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+        <fragment
+            class="com.example.android.wifidirect.DeviceListFragment"
+            android:id="@+id/frag_list"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/phone_list_height">
+            <!-- Preview: layout=@layout/row_devices -->
+        </fragment>
+        <fragment
+            class="com.example.android.wifidirect.DeviceDetailFragment"
+            android:id="@+id/frag_detail"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <!-- Preview: layout=@layout/device_detail -->
+        </fragment>
+    </LinearLayout>
+</LinearLayout>
diff --git a/samples/WiFiDirectDemo/res/layout/row_devices.xml b/samples/WiFiDirectDemo/res/layout/row_devices.xml
new file mode 100644
index 0000000..f5b68fa
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/layout/row_devices.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:background="?android:attr/activatedBackgroundIndicator"
+    android:padding="6dip">
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent"
+        android:layout_marginRight="2dip"
+        android:src="@drawable/machine" />
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="0dip"
+        android:layout_weight="1"
+        android:layout_height="fill_parent">
+        <TextView
+            android:id="@+id/device_name"
+            android:layout_width="fill_parent"
+            android:layout_height="0dip"
+            android:layout_weight="1"
+            android:gravity="center_vertical" />
+        <TextView
+            android:layout_width="fill_parent"
+            android:layout_height="0dip"
+            android:layout_weight="1"
+            android:id="@+id/device_details"
+            android:singleLine="true"
+            android:ellipsize="marquee" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/WiFiDirectDemo/res/menu/action_items.xml b/samples/WiFiDirectDemo/res/menu/action_items.xml
new file mode 100644
index 0000000..d2d3c7c
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/menu/action_items.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/atn_direct_enable"
+        android:icon="@drawable/ic_action_on_off"
+        android:title="@string/enable_p2p_button"
+        android:showAsAction="ifRoom|withText" />
+
+    <item
+        android:id="@+id/atn_direct_discover"
+        android:icon="@drawable/ic_action_discover"
+        android:title="@string/discover_peers_button"
+        android:showAsAction="ifRoom|withText" />
+</menu>
diff --git a/samples/WiFiDirectDemo/res/values/colors.xml b/samples/WiFiDirectDemo/res/values/colors.xml
new file mode 100644
index 0000000..6dae474
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/values/colors.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="status_bar_color">#FF000000</color>
+    <color name="layout_border_color">#FF111111</color>
+</resources>
diff --git a/samples/HoneycombGallery/res/layout/action_bar_custom.xml b/samples/WiFiDirectDemo/res/values/dimens.xml
similarity index 63%
copy from samples/HoneycombGallery/res/layout/action_bar_custom.xml
copy to samples/WiFiDirectDemo/res/values/dimens.xml
index 5f111d9..9ff9f12 100644
--- a/samples/HoneycombGallery/res/layout/action_bar_custom.xml
+++ b/samples/WiFiDirectDemo/res/values/dimens.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   Copyright (C) 2011 The Android Open Source Project
 
@@ -13,12 +14,8 @@
   See the License for the specific language governing permissions and
   limitations under the License.
  -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <TextView
-      android:layout_width="match_parent"
-      android:layout_height="match_parent">Hello Action Bar</TextView>
-</LinearLayout>
+<resources>
+    <dimen name="tablet_list_width">300dp</dimen>
+    <dimen name="phone_list_height">200dp</dimen>
+    
+</resources>
\ No newline at end of file
diff --git a/samples/WiFiDirectDemo/res/values/strings.xml b/samples/WiFiDirectDemo/res/values/strings.xml
new file mode 100644
index 0000000..96042b6
--- /dev/null
+++ b/samples/WiFiDirectDemo/res/values/strings.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">WiFi Direct</string>
+    <string name="enable_p2p_button">P2P On/Off</string>
+    <string name="discover_peers_button">Discover</string>
+    <string name="connect_peer_button">Connect</string>
+    <string name="disconnect_peer_button">Disconnect</string>
+    <string name="get_file_button">Launch Gallery</string>
+    <string name="empty"></string>
+    <string name="yes">yes</string>
+    <string name="no">no</string>
+    <string name="client_text">This device will act as a client. Click on Gallery button to pick a local(stored) file</string>
+    <string name="empty_message">No devices found. Turn on P2P and perform discovery from the Action Bar</string>
+    <string name="p2p_off_warning">Enable P2P from action bar button above or system settings</string>
+    <string name="group_owner_text">"Am I the Group Owner? "</string>
+    <string name="label_me">ME</string>
+    <string name="label_peers">PEERS</string>
+</resources>
diff --git a/samples/WiFiDirectDemo/src/com/example/android/wifidirect/DeviceDetailFragment.java b/samples/WiFiDirectDemo/src/com/example/android/wifidirect/DeviceDetailFragment.java
new file mode 100644
index 0000000..f74afae
--- /dev/null
+++ b/samples/WiFiDirectDemo/src/com/example/android/wifidirect/DeviceDetailFragment.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.wifidirect;
+
+import android.app.Fragment;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.net.wifi.WpsInfo;
+import android.net.wifi.p2p.WifiP2pConfig;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pInfo;
+import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.example.android.wifidirect.DeviceListFragment.DeviceActionListener;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * A fragment that manages a particular peer and allows interaction with device
+ * i.e. setting up network connection and transferring data.
+ */
+public class DeviceDetailFragment extends Fragment implements ConnectionInfoListener {
+
+    protected static final int CHOOSE_FILE_RESULT_CODE = 20;
+    private View mContentView = null;
+    private WifiP2pDevice device;
+    private WifiP2pInfo info;
+    ProgressDialog progressDialog = null;
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        mContentView = inflater.inflate(R.layout.device_detail, null);
+        mContentView.findViewById(R.id.btn_connect).setOnClickListener(new View.OnClickListener() {
+
+            @Override
+            public void onClick(View v) {
+                WifiP2pConfig config = new WifiP2pConfig();
+                config.deviceAddress = device.deviceAddress;
+                config.wps.setup = WpsInfo.PBC;
+                if (progressDialog != null && progressDialog.isShowing()) {
+                    progressDialog.dismiss();
+                }
+                progressDialog = ProgressDialog.show(getActivity(), "Press back to cancel",
+                        "Connecting to :" + device.deviceAddress, true, true
+//                        new DialogInterface.OnCancelListener() {
+//
+//                            @Override
+//                            public void onCancel(DialogInterface dialog) {
+//                                ((DeviceActionListener) getActivity()).cancelDisconnect();
+//                            }
+//                        }
+                        );
+                ((DeviceActionListener) getActivity()).connect(config);
+
+            }
+        });
+
+        mContentView.findViewById(R.id.btn_disconnect).setOnClickListener(
+                new View.OnClickListener() {
+
+                    @Override
+                    public void onClick(View v) {
+                        ((DeviceActionListener) getActivity()).disconnect();
+                    }
+                });
+
+        mContentView.findViewById(R.id.btn_start_client).setOnClickListener(
+                new View.OnClickListener() {
+
+                    @Override
+                    public void onClick(View v) {
+                        // Allow user to pick an image from Gallery or other
+                        // registered apps
+                        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+                        intent.setType("image/*");
+                        startActivityForResult(intent, CHOOSE_FILE_RESULT_CODE);
+                    }
+                });
+
+        return mContentView;
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+        // User has picked an image. Transfer it to group owner i.e peer using
+        // FileTransferService.
+        Uri uri = data.getData();
+        TextView statusText = (TextView) mContentView.findViewById(R.id.status_text);
+        statusText.setText("Sending: " + uri);
+        Log.d(WiFiDirectActivity.TAG, "Intent----------- " + uri);
+        Intent serviceIntent = new Intent(getActivity(), FileTransferService.class);
+        serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
+        serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, uri.toString());
+        serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS,
+                info.groupOwnerAddress.getHostAddress());
+        serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8988);
+        getActivity().startService(serviceIntent);
+    }
+
+    @Override
+    public void onConnectionInfoAvailable(final WifiP2pInfo info) {
+        if (progressDialog != null && progressDialog.isShowing()) {
+            progressDialog.dismiss();
+        }
+        this.info = info;
+        this.getView().setVisibility(View.VISIBLE);
+
+        // The owner IP is now known.
+        TextView view = (TextView) mContentView.findViewById(R.id.group_owner);
+        view.setText(getResources().getString(R.string.group_owner_text)
+                + ((info.isGroupOwner == true) ? getResources().getString(R.string.yes)
+                        : getResources().getString(R.string.no)));
+
+        // InetAddress from WifiP2pInfo struct.
+        view = (TextView) mContentView.findViewById(R.id.device_info);
+        view.setText("Group Owner IP - " + info.groupOwnerAddress.getHostAddress());
+
+        // After the group negotiation, we assign the group owner as the file
+        // server. The file server is single threaded, single connection server
+        // socket.
+        if (info.groupFormed && info.isGroupOwner) {
+            new FileServerAsyncTask(getActivity(), mContentView.findViewById(R.id.status_text))
+                    .execute();
+        } else if (info.groupFormed) {
+            // The other device acts as the client. In this case, we enable the
+            // get file button.
+            mContentView.findViewById(R.id.btn_start_client).setVisibility(View.VISIBLE);
+            ((TextView) mContentView.findViewById(R.id.status_text)).setText(getResources()
+                    .getString(R.string.client_text));
+        }
+
+        // hide the connect button
+        mContentView.findViewById(R.id.btn_connect).setVisibility(View.GONE);
+    }
+
+    /**
+     * Updates the UI with device data
+     * 
+     * @param device the device to be displayed
+     */
+    public void showDetails(WifiP2pDevice device) {
+        this.device = device;
+        this.getView().setVisibility(View.VISIBLE);
+        TextView view = (TextView) mContentView.findViewById(R.id.device_address);
+        view.setText(device.deviceAddress);
+        view = (TextView) mContentView.findViewById(R.id.device_info);
+        view.setText(device.toString());
+
+    }
+
+    /**
+     * Clears the UI fields after a disconnect or direct mode disable operation.
+     */
+    public void resetViews() {
+        mContentView.findViewById(R.id.btn_connect).setVisibility(View.VISIBLE);
+        TextView view = (TextView) mContentView.findViewById(R.id.device_address);
+        view.setText(R.string.empty);
+        view = (TextView) mContentView.findViewById(R.id.device_info);
+        view.setText(R.string.empty);
+        view = (TextView) mContentView.findViewById(R.id.group_owner);
+        view.setText(R.string.empty);
+        view = (TextView) mContentView.findViewById(R.id.status_text);
+        view.setText(R.string.empty);
+        mContentView.findViewById(R.id.btn_start_client).setVisibility(View.GONE);
+        this.getView().setVisibility(View.GONE);
+    }
+
+    /**
+     * A simple server socket that accepts connection and writes some data on
+     * the stream.
+     */
+    public static class FileServerAsyncTask extends AsyncTask<Void, Void, String> {
+
+        private Context context;
+        private TextView statusText;
+
+        /**
+         * @param context
+         * @param statusText
+         */
+        public FileServerAsyncTask(Context context, View statusText) {
+            this.context = context;
+            this.statusText = (TextView) statusText;
+        }
+
+        @Override
+        protected String doInBackground(Void... params) {
+            try {
+                ServerSocket serverSocket = new ServerSocket(8988);
+                Log.d(WiFiDirectActivity.TAG, "Server: Socket opened");
+                Socket client = serverSocket.accept();
+                Log.d(WiFiDirectActivity.TAG, "Server: connection done");
+                final File f = new File(Environment.getExternalStorageDirectory() + "/"
+                        + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
+                        + ".jpg");
+
+                File dirs = new File(f.getParent());
+                if (!dirs.exists())
+                    dirs.mkdirs();
+                f.createNewFile();
+
+                Log.d(WiFiDirectActivity.TAG, "server: copying files " + f.toString());
+                InputStream inputstream = client.getInputStream();
+                copyFile(inputstream, new FileOutputStream(f));
+                serverSocket.close();
+                return f.getAbsolutePath();
+            } catch (IOException e) {
+                Log.e(WiFiDirectActivity.TAG, e.getMessage());
+                return null;
+            }
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
+         */
+        @Override
+        protected void onPostExecute(String result) {
+            if (result != null) {
+                statusText.setText("File copied - " + result);
+                Intent intent = new Intent();
+                intent.setAction(android.content.Intent.ACTION_VIEW);
+                intent.setDataAndType(Uri.parse("file://" + result), "image/*");
+                context.startActivity(intent);
+            }
+
+        }
+
+        /*
+         * (non-Javadoc)
+         * @see android.os.AsyncTask#onPreExecute()
+         */
+        @Override
+        protected void onPreExecute() {
+            statusText.setText("Opening a server socket");
+        }
+
+    }
+
+    public static boolean copyFile(InputStream inputStream, OutputStream out) {
+        byte buf[] = new byte[1024];
+        int len;
+        try {
+            while ((len = inputStream.read(buf)) != -1) {
+                out.write(buf, 0, len);
+
+            }
+            out.close();
+            inputStream.close();
+        } catch (IOException e) {
+            Log.d(WiFiDirectActivity.TAG, e.toString());
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/samples/WiFiDirectDemo/src/com/example/android/wifidirect/DeviceListFragment.java b/samples/WiFiDirectDemo/src/com/example/android/wifidirect/DeviceListFragment.java
new file mode 100644
index 0000000..bfdbd6b
--- /dev/null
+++ b/samples/WiFiDirectDemo/src/com/example/android/wifidirect/DeviceListFragment.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.wifidirect;
+
+import android.app.ListFragment;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.wifi.p2p.WifiP2pConfig;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pDeviceList;
+import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A ListFragment that displays available peers on discovery and requests the
+ * parent activity to handle user interaction events
+ */
+public class DeviceListFragment extends ListFragment implements PeerListListener {
+
+    private List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
+    ProgressDialog progressDialog = null;
+    View mContentView = null;
+    private WifiP2pDevice device;
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        this.setListAdapter(new WiFiPeerListAdapter(getActivity(), R.layout.row_devices, peers));
+
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        mContentView = inflater.inflate(R.layout.device_list, null);
+        return mContentView;
+    }
+
+    /**
+     * @return this device
+     */
+    public WifiP2pDevice getDevice() {
+        return device;
+    }
+
+    private static String getDeviceStatus(int deviceStatus) {
+        Log.d(WiFiDirectActivity.TAG, "Peer status :" + deviceStatus);
+        switch (deviceStatus) {
+            case WifiP2pDevice.AVAILABLE:
+                return "Available";
+            case WifiP2pDevice.INVITED:
+                return "Invited";
+            case WifiP2pDevice.CONNECTED:
+                return "Connected";
+            case WifiP2pDevice.FAILED:
+                return "Failed";
+            case WifiP2pDevice.UNAVAILABLE:
+                return "Unavailable";
+            default:
+                return "Unknown";
+
+        }
+    }
+
+    /**
+     * Initiate a connection with the peer.
+     */
+    @Override
+    public void onListItemClick(ListView l, View v, int position, long id) {
+        WifiP2pDevice device = (WifiP2pDevice) getListAdapter().getItem(position);
+        ((DeviceActionListener) getActivity()).showDetails(device);
+    }
+
+    /**
+     * Array adapter for ListFragment that maintains WifiP2pDevice list.
+     */
+    private class WiFiPeerListAdapter extends ArrayAdapter<WifiP2pDevice> {
+
+        private List<WifiP2pDevice> items;
+
+        /**
+         * @param context
+         * @param textViewResourceId
+         * @param objects
+         */
+        public WiFiPeerListAdapter(Context context, int textViewResourceId,
+                List<WifiP2pDevice> objects) {
+            super(context, textViewResourceId, objects);
+            items = objects;
+
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            View v = convertView;
+            if (v == null) {
+                LayoutInflater vi = (LayoutInflater) getActivity().getSystemService(
+                        Context.LAYOUT_INFLATER_SERVICE);
+                v = vi.inflate(R.layout.row_devices, null);
+            }
+            WifiP2pDevice device = items.get(position);
+            if (device != null) {
+                TextView top = (TextView) v.findViewById(R.id.device_name);
+                TextView bottom = (TextView) v.findViewById(R.id.device_details);
+                if (top != null) {
+                    top.setText(device.deviceName);
+                }
+                if (bottom != null) {
+                    bottom.setText(getDeviceStatus(device.status));
+                }
+            }
+
+            return v;
+
+        }
+    }
+
+    /**
+     * Update UI for this device.
+     * 
+     * @param device WifiP2pDevice object
+     */
+    public void updateThisDevice(WifiP2pDevice device) {
+        this.device = device;
+        TextView view = (TextView) mContentView.findViewById(R.id.my_name);
+        view.setText(device.deviceName);
+        view = (TextView) mContentView.findViewById(R.id.my_status);
+        view.setText(getDeviceStatus(device.status));
+    }
+
+    @Override
+    public void onPeersAvailable(WifiP2pDeviceList peerList) {
+        if (progressDialog != null && progressDialog.isShowing()) {
+            progressDialog.dismiss();
+        }
+        peers.clear();
+        peers.addAll(peerList.getDeviceList());
+        ((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
+        if (peers.size() == 0) {
+            Log.d(WiFiDirectActivity.TAG, "No devices found");
+            return;
+        }
+
+    }
+
+    public void clearPeers() {
+        peers.clear();
+        ((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
+    }
+
+    /**
+     * 
+     */
+    public void onInitiateDiscovery() {
+        if (progressDialog != null && progressDialog.isShowing()) {
+            progressDialog.dismiss();
+        }
+        progressDialog = ProgressDialog.show(getActivity(), "Press back to cancel", "finding peers", true,
+                true, new DialogInterface.OnCancelListener() {
+
+                    @Override
+                    public void onCancel(DialogInterface dialog) {
+                        
+                    }
+                });
+    }
+
+    /**
+     * An interface-callback for the activity to listen to fragment interaction
+     * events.
+     */
+    public interface DeviceActionListener {
+
+        void showDetails(WifiP2pDevice device);
+
+        void cancelDisconnect();
+
+        void connect(WifiP2pConfig config);
+
+        void disconnect();
+    }
+
+}
diff --git a/samples/WiFiDirectDemo/src/com/example/android/wifidirect/FileTransferService.java b/samples/WiFiDirectDemo/src/com/example/android/wifidirect/FileTransferService.java
new file mode 100644
index 0000000..cfd3160
--- /dev/null
+++ b/samples/WiFiDirectDemo/src/com/example/android/wifidirect/FileTransferService.java
@@ -0,0 +1,86 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package com.example.android.wifidirect;
+
+import android.app.IntentService;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.util.Log;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+/**
+ * A service that process each file transfer request i.e Intent by opening a
+ * socket connection with the WiFi Direct Group Owner and writing the file
+ */
+public class FileTransferService extends IntentService {
+
+    private static final int SOCKET_TIMEOUT = 5000;
+    public static final String ACTION_SEND_FILE = "com.example.android.wifidirect.SEND_FILE";
+    public static final String EXTRAS_FILE_PATH = "file_url";
+    public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
+    public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";
+
+    public FileTransferService(String name) {
+        super(name);
+    }
+
+    public FileTransferService() {
+        super("FileTransferService");
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see android.app.IntentService#onHandleIntent(android.content.Intent)
+     */
+    @Override
+    protected void onHandleIntent(Intent intent) {
+
+        Context context = getApplicationContext();
+        if (intent.getAction().equals(ACTION_SEND_FILE)) {
+            String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
+            String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
+            Socket socket = new Socket();
+            int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);
+
+            try {
+                Log.d(WiFiDirectActivity.TAG, "Opening client socket - ");
+                socket.bind(null);
+                socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);
+
+                Log.d(WiFiDirectActivity.TAG, "Client socket - " + socket.isConnected());
+                OutputStream stream = socket.getOutputStream();
+                ContentResolver cr = context.getContentResolver();
+                InputStream is = null;
+                try {
+                    is = cr.openInputStream(Uri.parse(fileUri));
+                } catch (FileNotFoundException e) {
+                    Log.d(WiFiDirectActivity.TAG, e.toString());
+                }
+                DeviceDetailFragment.copyFile(is, stream);
+                Log.d(WiFiDirectActivity.TAG, "Client: Data written");
+            } catch (IOException e) {
+                Log.e(WiFiDirectActivity.TAG, e.getMessage());
+            } finally {
+                if (socket != null) {
+                    if (socket.isConnected()) {
+                        try {
+                            socket.close();
+                        } catch (IOException e) {
+                            // Give up
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            }
+
+        }
+    }
+}
diff --git a/samples/WiFiDirectDemo/src/com/example/android/wifidirect/WiFiDirectActivity.java b/samples/WiFiDirectDemo/src/com/example/android/wifidirect/WiFiDirectActivity.java
new file mode 100644
index 0000000..2e51c3d
--- /dev/null
+++ b/samples/WiFiDirectDemo/src/com/example/android/wifidirect/WiFiDirectActivity.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.wifidirect;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.p2p.WifiP2pConfig;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.p2p.WifiP2pManager.ActionListener;
+import android.net.wifi.p2p.WifiP2pManager.Channel;
+import android.net.wifi.p2p.WifiP2pManager.ChannelListener;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Toast;
+
+import com.example.android.wifidirect.DeviceListFragment.DeviceActionListener;
+
+/**
+ * An activity that uses WiFi Direct APIs to discover and connect with available
+ * devices. WiFi Direct APIs are asynchronous and rely on callback mechanism
+ * using interfaces to notify the application of operation success or failure.
+ * The application should also register a BroadcastReceiver for notification of
+ * WiFi state related events.
+ */
+public class WiFiDirectActivity extends Activity implements ChannelListener, DeviceActionListener {
+
+    public static final String TAG = "wifidirectdemo";
+    private WifiP2pManager manager;
+    private boolean isWifiP2pEnabled = false;
+    private boolean retryChannel = false;
+
+    private final IntentFilter intentFilter = new IntentFilter();
+    private Channel channel;
+    private BroadcastReceiver receiver = null;
+
+    /**
+     * @param isWifiP2pEnabled the isWifiP2pEnabled to set
+     */
+    public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
+        this.isWifiP2pEnabled = isWifiP2pEnabled;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        // add necessary intent values to be matched.
+
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
+
+        manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
+        channel = manager.initialize(this, getMainLooper(), null);
+    }
+
+    /** register the BroadcastReceiver with the intent values to be matched */
+    @Override
+    public void onResume() {
+        super.onResume();
+        receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
+        registerReceiver(receiver, intentFilter);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        unregisterReceiver(receiver);
+    }
+
+    /**
+     * Remove all peers and clear all fields. This is called on
+     * BroadcastReceiver receiving a state change event.
+     */
+    public void resetData() {
+        DeviceListFragment fragmentList = (DeviceListFragment) getFragmentManager()
+                .findFragmentById(R.id.frag_list);
+        DeviceDetailFragment fragmentDetails = (DeviceDetailFragment) getFragmentManager()
+                .findFragmentById(R.id.frag_detail);
+        if (fragmentList != null) {
+            fragmentList.clearPeers();
+        }
+        if (fragmentDetails != null) {
+            fragmentDetails.resetViews();
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.action_items, menu);
+        return true;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.atn_direct_enable:
+                if (manager != null && channel != null) {
+
+                    // Since this is the system wireless settings activity, it's
+                    // not going to send us a result. We will be notified by
+                    // WiFiDeviceBroadcastReceiver instead.
+
+                    startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
+                } else {
+                    Log.e(TAG, "channel or manager is null");
+                }
+                return true;
+
+            case R.id.atn_direct_discover:
+                if (!isWifiP2pEnabled) {
+                    Toast.makeText(WiFiDirectActivity.this, R.string.p2p_off_warning,
+                            Toast.LENGTH_SHORT).show();
+                    return true;
+                }
+                final DeviceListFragment fragment = (DeviceListFragment) getFragmentManager()
+                        .findFragmentById(R.id.frag_list);
+                fragment.onInitiateDiscovery();
+                manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
+
+                    @Override
+                    public void onSuccess() {
+                        Toast.makeText(WiFiDirectActivity.this, "Discovery Initiated",
+                                Toast.LENGTH_SHORT).show();
+                    }
+
+                    @Override
+                    public void onFailure(int reasonCode) {
+                        Toast.makeText(WiFiDirectActivity.this, "Discovery Failed : " + reasonCode,
+                                Toast.LENGTH_SHORT).show();
+                    }
+                });
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
+    @Override
+    public void showDetails(WifiP2pDevice device) {
+        DeviceDetailFragment fragment = (DeviceDetailFragment) getFragmentManager()
+                .findFragmentById(R.id.frag_detail);
+        fragment.showDetails(device);
+
+    }
+
+    @Override
+    public void connect(WifiP2pConfig config) {
+        manager.connect(channel, config, new ActionListener() {
+
+            @Override
+            public void onSuccess() {
+                // WiFiDirectBroadcastReceiver will notify us. Ignore for now.
+            }
+
+            @Override
+            public void onFailure(int reason) {
+                Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.",
+                        Toast.LENGTH_SHORT).show();
+            }
+        });
+    }
+
+    @Override
+    public void disconnect() {
+        final DeviceDetailFragment fragment = (DeviceDetailFragment) getFragmentManager()
+                .findFragmentById(R.id.frag_detail);
+        fragment.resetViews();
+        manager.removeGroup(channel, new ActionListener() {
+
+            @Override
+            public void onFailure(int reasonCode) {
+                Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
+
+            }
+
+            @Override
+            public void onSuccess() {
+                fragment.getView().setVisibility(View.GONE);
+            }
+
+        });
+    }
+
+    @Override
+    public void onChannelDisconnected() {
+        // we will try once more
+        if (manager != null && !retryChannel) {
+            Toast.makeText(this, "Channel lost. Trying again", Toast.LENGTH_LONG).show();
+            resetData();
+            retryChannel = true;
+            manager.initialize(this, getMainLooper(), this);
+        } else {
+            Toast.makeText(this,
+                    "Severe! Channel is probably lost premanently. Try Disable/Re-Enable P2P.",
+                    Toast.LENGTH_LONG).show();
+        }
+    }
+
+    @Override
+    public void cancelDisconnect() {
+
+        /*
+         * A cancel abort request by user. Disconnect i.e. removeGroup if
+         * already connected. Else, request WifiP2pManager to abort the ongoing
+         * request
+         */
+        if (manager != null) {
+            final DeviceListFragment fragment = (DeviceListFragment) getFragmentManager()
+                    .findFragmentById(R.id.frag_list);
+            if (fragment.getDevice() == null
+                    || fragment.getDevice().status == WifiP2pDevice.CONNECTED) {
+                disconnect();
+            } else if (fragment.getDevice().status == WifiP2pDevice.AVAILABLE
+                    || fragment.getDevice().status == WifiP2pDevice.INVITED) {
+
+                manager.cancelConnect(channel, new ActionListener() {
+
+                    @Override
+                    public void onSuccess() {
+                        Toast.makeText(WiFiDirectActivity.this, "Aborting connection",
+                                Toast.LENGTH_SHORT).show();
+                    }
+
+                    @Override
+                    public void onFailure(int reasonCode) {
+                        Toast.makeText(WiFiDirectActivity.this,
+                                "Connect abort request failed. Reason Code: " + reasonCode,
+                                Toast.LENGTH_SHORT).show();
+                    }
+                });
+            }
+        }
+
+    }
+}
diff --git a/samples/WiFiDirectDemo/src/com/example/android/wifidirect/WiFiDirectBroadcastReceiver.java b/samples/WiFiDirectDemo/src/com/example/android/wifidirect/WiFiDirectBroadcastReceiver.java
new file mode 100644
index 0000000..8bec5b4
--- /dev/null
+++ b/samples/WiFiDirectDemo/src/com/example/android/wifidirect/WiFiDirectBroadcastReceiver.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.wifidirect;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkInfo;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.p2p.WifiP2pManager.Channel;
+import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
+import android.util.Log;
+
+/**
+ * A BroadcastReceiver that notifies of important wifi p2p events.
+ */
+public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
+
+    private WifiP2pManager manager;
+    private Channel channel;
+    private WiFiDirectActivity activity;
+
+    /**
+     * @param manager WifiP2pManager system service
+     * @param channel Wifi p2p channel
+     * @param activity activity associated with the receiver
+     */
+    public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
+            WiFiDirectActivity activity) {
+        super();
+        this.manager = manager;
+        this.channel = channel;
+        this.activity = activity;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see android.content.BroadcastReceiver#onReceive(android.content.Context,
+     * android.content.Intent)
+     */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
+
+            // UI update to indicate wifi p2p status.
+            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
+            if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
+                // Wifi Direct mode is enabled
+                activity.setIsWifiP2pEnabled(true);
+            } else {
+                activity.setIsWifiP2pEnabled(false);
+                activity.resetData();
+
+            }
+            Log.d(WiFiDirectActivity.TAG, "P2P state changed - " + state);
+        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
+
+            // request available peers from the wifi p2p manager. This is an
+            // asynchronous call and the calling activity is notified with a
+            // callback on PeerListListener.onPeersAvailable()
+            if (manager != null) {
+                manager.requestPeers(channel, (PeerListListener) activity.getFragmentManager()
+                        .findFragmentById(R.id.frag_list));
+            }
+            Log.d(WiFiDirectActivity.TAG, "P2P peers changed");
+        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
+
+            if (manager == null) {
+                return;
+            }
+
+            NetworkInfo networkInfo = (NetworkInfo) intent
+                    .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
+
+            if (networkInfo.isConnected()) {
+
+                // we are connected with the other device, request connection
+                // info to find group owner IP
+
+                DeviceDetailFragment fragment = (DeviceDetailFragment) activity
+                        .getFragmentManager().findFragmentById(R.id.frag_detail);
+                manager.requestConnectionInfo(channel, fragment);
+            } else {
+                // It's a disconnect
+                activity.resetData();
+            }
+        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
+            DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager()
+                    .findFragmentById(R.id.frag_list);
+            fragment.updateThisDevice((WifiP2pDevice) intent.getParcelableExtra(
+                    WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
+
+        }
+    }
+}
diff --git a/samples/source.properties b/samples/source.properties
index 795c25a..7cb1d33 100644
--- a/samples/source.properties
+++ b/samples/source.properties
@@ -1,4 +1,4 @@
 Pkg.UserSrc=false
 Pkg.Revision=1
-AndroidVersion.ApiLevel=13
-#AndroidVersion.CodeName=Honeycomb
+AndroidVersion.ApiLevel=14
+#AndroidVersion.CodeName=
diff --git a/sdk/compatibility_source.properties b/sdk/compatibility_source.properties
deleted file mode 100644
index f23e52a..0000000
--- a/sdk/compatibility_source.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-Pkg.UserSrc=false
-Pkg.Revision=3
diff --git a/sdk/doc_source.properties b/sdk/doc_source.properties
index 5f493e4..acf5d3b 100644
--- a/sdk/doc_source.properties
+++ b/sdk/doc_source.properties
@@ -1,5 +1,5 @@
 Pkg.UserSrc=false
 Pkg.Revision=1
-AndroidVersion.ApiLevel=13
+AndroidVersion.ApiLevel=14
 #AndroidVersion.CodeName=
 
diff --git a/sdk/images_armeabi-v7a_source.properties b/sdk/images_armeabi-v7a_source.properties
new file mode 100644
index 0000000..aa7d1aa
--- /dev/null
+++ b/sdk/images_armeabi-v7a_source.properties
@@ -0,0 +1,6 @@
+Pkg.Desc=Android SDK Platform 4.0
+Pkg.UserSrc=false
+Pkg.Revision=1
+AndroidVersion.ApiLevel=14
+#AndroidVersion.CodeName=
+SystemImage.Abi=armeabi-v7a
diff --git a/sdk/images_armeabi_source.properties b/sdk/images_armeabi_source.properties
new file mode 100644
index 0000000..192ecde
--- /dev/null
+++ b/sdk/images_armeabi_source.properties
@@ -0,0 +1,6 @@
+Pkg.Desc=Android SDK Platform 4.0
+Pkg.UserSrc=false
+Pkg.Revision=1
+AndroidVersion.ApiLevel=14
+#AndroidVersion.CodeName=
+SystemImage.Abi=armeabi
diff --git a/sdk/images_x86_source.properties b/sdk/images_x86_source.properties
new file mode 100644
index 0000000..caccb2d
--- /dev/null
+++ b/sdk/images_x86_source.properties
@@ -0,0 +1,6 @@
+Pkg.Desc=Android SDK Platform 4.0
+Pkg.UserSrc=false
+Pkg.Revision=1
+AndroidVersion.ApiLevel=14
+#AndroidVersion.CodeName=
+SystemImage.Abi=x86
diff --git a/sdk/llvm-rs-cc.txt b/sdk/llvm-rs-cc.txt
deleted file mode 100644
index ddfbc97..0000000
--- a/sdk/llvm-rs-cc.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-# map versions of the llvm-rs-cc compiler with the min API level.
-# <compiler version>:<api leve>
-# the compiler version number maps to the filename llvm-rs-cc-<version>[.exe]
-# except for version 1 which is simply llvm-rs-cc[.exe]
-1:11
diff --git a/sdk/platform_source.properties b/sdk/platform_source.properties
index 7b6a869..5e3ef13 100644
--- a/sdk/platform_source.properties
+++ b/sdk/platform_source.properties
@@ -1,6 +1,8 @@
-Pkg.Desc=Android SDK Platform 3.2
+Pkg.Desc=Android SDK Platform 4.0
 Pkg.UserSrc=false
-Platform.Version=3.2
+Platform.Version=4.0
 Pkg.Revision=1
-AndroidVersion.ApiLevel=13
+AndroidVersion.ApiLevel=14
 #AndroidVersion.CodeName=
+Layoutlib.Api=7
+Layoutlib.Revision=1
diff --git a/sdk/source_source.properties b/sdk/source_source.properties
new file mode 100644
index 0000000..7cb1d33
--- /dev/null
+++ b/sdk/source_source.properties
@@ -0,0 +1,4 @@
+Pkg.UserSrc=false
+Pkg.Revision=1
+AndroidVersion.ApiLevel=14
+#AndroidVersion.CodeName=
diff --git a/sdk/compatibility_README.txt b/sdk/support_README.txt
similarity index 81%
rename from sdk/compatibility_README.txt
rename to sdk/support_README.txt
index 7752b3b..2d3ba25 100644
--- a/sdk/compatibility_README.txt
+++ b/sdk/support_README.txt
@@ -1,8 +1,9 @@
-Compatibility Libraries for Android.
+Support Libraries for Android.
 
 This SDK component contains static libraries providing access to newer APIs
-on older platforms. To use those libraries, simply copy them as static libraries
-into your project.
+on older platforms and various helper classes.
+
+To use those libraries, simply copy them as static libraries into your project.
 
 Each library is called v<api>, indicating the minimum API level that they require.
 
@@ -21,7 +22,7 @@
 
 *** V13 ***
 
-Provides the same features as v4, plus:
+v13/android-support-v13.jar provides the same features as v4, plus:
 - FragmentPagerAdapter: Implementation of PagerAdapter that represents each page as a Fragment.
 
 v13/src/ is the source code for the compatibility library, not including the v4 source
diff --git a/sdk/support_source.properties b/sdk/support_source.properties
new file mode 100644
index 0000000..16d5cd8
--- /dev/null
+++ b/sdk/support_source.properties
@@ -0,0 +1,6 @@
+Pkg.UserSrc=false
+Pkg.Revision=4
+Extra.Vendor=android
+Extra.Path=support
+Extra.OldPaths=compatibility
+
diff --git a/sdk_overlay/frameworks/base/core/res/res/values/config.xml b/sdk_overlay/frameworks/base/core/res/res/values/config.xml
index 3296ed1..22cc16e 100644
--- a/sdk_overlay/frameworks/base/core/res/res/values/config.xml
+++ b/sdk_overlay/frameworks/base/core/res/res/values/config.xml
@@ -23,6 +23,5 @@
     <!-- Component name of the service providing geocoder API support. -->
     <string name="config_geocodeProvider">com.google.android.location.GeocodeProvider</string>
 
-    <!-- This device is not "voice capable"; it's data-only. -->
-    <bool name="config_voice_capable">false</bool>
+    <bool name="config_voice_capable">true</bool>
 </resources>
diff --git a/tools/emulator/opengl/Android.mk b/tools/emulator/opengl/Android.mk
index 8147395..2c1cb64 100644
--- a/tools/emulator/opengl/Android.mk
+++ b/tools/emulator/opengl/Android.mk
@@ -9,11 +9,6 @@
 #
 ifeq (true,$(BUILD_EMULATOR_OPENGL))
 
-# By default, NEVER build the gralloc.goldfish support library because
-# the code has not been ported to Honeycomb / IceCreamSandwich yet and
-# will fail to build properly.
-BUILD_EMULATOR_OPENGL_DRIVER ?= true
-
 # Top-level for all modules
 EMUGL_PATH := $(call my-dir)
 
@@ -71,13 +66,8 @@
 include $(EMUGL_PATH)/system/GLESv1/Android.mk
 include $(EMUGL_PATH)/system/GLESv2/Android.mk
 
-ifeq (false,$(BUILD_EMULATOR_OPENGL_DRIVER))
-  include $(EMUGL_PATH)/tests/ut_rendercontrol_enc/Android.mk
-  include $(EMUGL_PATH)/tests/gles_android_wrapper/Android.mk
-else
-  include $(EMUGL_PATH)/system/gralloc/Android.mk
-  include $(EMUGL_PATH)/system/egl/Android.mk
-endif
+include $(EMUGL_PATH)/system/gralloc/Android.mk
+include $(EMUGL_PATH)/system/egl/Android.mk
 
 # Host static libraries
 include $(EMUGL_PATH)/host/libs/GLESv1_dec/Android.mk
@@ -95,12 +85,7 @@
 # Host executables
 include $(EMUGL_PATH)/host/renderer/Android.mk
 
-# Host unit-test for the renderer. this one uses its own small
-# EGL host wrapper.
-include $(EMUGL_PATH)/tests/event_injector/Android.mk
-include $(EMUGL_PATH)/tests/EGL_host_wrapper/Android.mk
-include $(EMUGL_PATH)/tests/emulator_test_renderer/Android.mk
-include $(EMUGL_PATH)/tests/ut_renderer/Android.mk
+# Host unit-test for the renderer.
 
 include $(EMUGL_PATH)/tests/translator_tests/MacCommon/Android.mk
 include $(EMUGL_PATH)/tests/translator_tests/GLES_CM/Android.mk
diff --git a/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h b/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h
index 41d8023..445ec17 100644
--- a/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h
+++ b/tools/emulator/opengl/host/include/libOpenglRender/IOStream.h
@@ -34,6 +34,7 @@
     virtual int commitBuffer(size_t size) = 0;
     virtual const unsigned char *readFully( void *buf, size_t len) = 0;
     virtual const unsigned char *read( void *buf, size_t *inout_len) = 0;
+    virtual int writeFully(const void* buf, size_t len) = 0;
 
     virtual ~IOStream() {
 
@@ -82,6 +83,7 @@
         return readFully(buf, len);
     }
 
+
 private:
     unsigned char *m_buf;
     size_t m_bufsize;
diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/RenderServer.cpp b/tools/emulator/opengl/host/libs/libOpenglRender/RenderServer.cpp
index fb5948b..78f305c 100644
--- a/tools/emulator/opengl/host/libs/libOpenglRender/RenderServer.cpp
+++ b/tools/emulator/opengl/host/libs/libOpenglRender/RenderServer.cpp
@@ -15,7 +15,9 @@
 */
 #include "RenderServer.h"
 #include "TcpStream.h"
-#ifndef _WIN32
+#ifdef _WIN32
+#include "Win32PipeStream.h"
+#else
 #include "UnixStream.h"
 #endif
 #include "RenderThread.h"
@@ -43,9 +45,9 @@
         server->m_listenSock = new TcpStream();
     } else {
 #ifdef _WIN32
-    server->m_listenSock = new TcpStream();
+        server->m_listenSock = new Win32PipeStream();
 #else
-    server->m_listenSock = new UnixStream();
+        server->m_listenSock = new UnixStream();
 #endif
     }
 
diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp b/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp
index 7381b7d..8a5f464 100644
--- a/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp
+++ b/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp
@@ -21,7 +21,9 @@
 #include "TimeUtils.h"
 
 #include "TcpStream.h"
-#ifndef _WIN32
+#ifdef _WIN32
+#include "Win32PipeStream.h"
+#else
 #include "UnixStream.h"
 #endif
 
@@ -289,12 +291,10 @@
 
     if (gRendererStreamMode == STREAM_MODE_TCP) {
         stream = new TcpStream(p_stream_buffer_size);
-#ifdef _WIN32
     } else {
-        /* XXX: Need Win32 named pipe stream here */
-        stream = new TcpStream(p_stream_buffer_size);
-#else
-    } else if (gRendererStreamMode == STREAM_MODE_UNIX) {
+#ifdef _WIN32
+        stream = new Win32PipeStream(p_stream_buffer_size);
+#else /* !_WIN32 */
         stream = new UnixStream(p_stream_buffer_size);
 #endif
     }
diff --git a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
index 9e95604..4265301 100644
--- a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
+++ b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
@@ -21,6 +21,15 @@
 #include <errno.h>
 #include <sys/types.h>
 
+/* Define this to 1 to enable support for the 'isLarge' variable flag
+ * that instructs the encoder to send large data buffers by a direct
+ * write through the pipe (i.e. without copying it into a temporary
+ * buffer. This has definite performance benefits when using a QEMU Pipe.
+ *
+ * Set to 0 otherwise.
+ */
+#define WITH_LARGE_SUPPORT  1
+
 EntryPoint * ApiGen::findEntryByName(const std::string & name)
 {
     EntryPoint * entry = NULL;
@@ -338,6 +347,104 @@
     return 0;
 }
 
+// Format the byte length expression for a given variable into a user-provided buffer
+// If the variable type is not a pointer, this is simply its size as a decimal constant
+// If the variable is a pointer, this will be an expression provided by the .attrib file
+// through the 'len' attribute.
+//
+// Returns 1 if the variable is a pointer, 0 otherwise
+//
+static int getVarEncodingSizeExpression(Var&  var, EntryPoint* e, char* buff, size_t bufflen)
+{
+    int ret = 0;
+    if (!var.isPointer()) {
+        snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes());
+    } else {
+        ret = 1;
+        const char* lenExpr = var.lenExpression().c_str();
+        const char* varname = var.name().c_str();
+        if (e != NULL && lenExpr[0] == '\0') {
+            fprintf(stderr, "%s: data len is undefined for '%s'\n",
+                    e->name().c_str(), varname);
+        }
+        if (var.nullAllowed()) {
+            snprintf(buff, bufflen, "((%s != NULL) ? %s : 0)", varname, lenExpr);
+        } else {
+            snprintf(buff, bufflen, "%s", lenExpr);
+        }
+    }
+    return ret;
+}
+
+static int writeVarEncodingSize(Var& var, FILE* fp)
+{
+    int ret = 0;
+    if (!var.isPointer()) {
+        fprintf(fp, "%u", (unsigned int) var.type()->bytes());
+    } else {
+        ret = 1;
+        fprintf(fp, "__size_%s", var.name().c_str());
+    }
+    return ret;
+}
+
+
+
+static void writeVarEncodingExpression(Var& var, FILE* fp)
+{
+    const char* varname = var.name().c_str();
+
+    if (var.isPointer()) {
+        // encode a pointer header
+        fprintf(fp, "\t*(unsigned int *)(ptr) = __size_%s; ptr += 4;\n", varname);
+
+        Var::PointerDir dir = var.pointerDir();
+        if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
+            if (var.nullAllowed()) {
+                fprintf(fp, "\tif (%s != NULL) ", varname);
+            } else {
+                fprintf(fp, "\t");
+            }
+
+            if (var.packExpression().size() != 0) {
+                fprintf(fp, "%s;", var.packExpression().c_str());
+            } else {
+                fprintf(fp, "memcpy(ptr, %s, __size_%s);",
+                        varname, varname);
+            }
+
+            fprintf(fp, "ptr += __size_%s;\n", varname);
+        }
+    } else {
+        // encode a non pointer variable
+        if (!var.isVoid()) {
+            fprintf(fp, "\t*(%s *) (ptr) = %s; ptr += %u;\n",
+                    var.type()->name().c_str(), varname,
+                    (uint) var.type()->bytes());
+        }
+    }
+}
+
+#if WITH_LARGE_SUPPORT
+static void writeVarLargeEncodingExpression(Var& var, FILE* fp)
+{
+    const char* varname = var.name().c_str();
+
+    fprintf(fp, "\tstream->writeFully(&__size_%s,4);\n", varname);
+    if (var.nullAllowed()) {
+        fprintf(fp, "\tif (%s != NULL) ", varname);
+    } else {
+        fprintf(fp, "\t");
+    }
+    if (var.writeExpression() != "") {
+        fprintf(fp, "%s", var.writeExpression().c_str());
+    } else {
+        fprintf(fp, "stream->writeFully(%s, __size_%s)", varname, varname);
+    }
+    fprintf(fp, ";\n");
+}
+#endif /* WITH_LARGE_SUPPORT */
+
 int ApiGen::genEncoderImpl(const std::string &filename)
 {
     FILE *fp = fopen(filename.c_str(), "wt");
@@ -368,46 +475,139 @@
         fprintf(fp, "{\n");
 
 //      fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str());
-        fprintf(fp, "\n\t%s *ctx = (%s *)self;\n\n",
+        fprintf(fp, "\n\t%s *ctx = (%s *)self;\n",
                 classname.c_str(),
                 classname.c_str());
-
-        // size calculation ;
-        fprintf(fp, "\t size_t packetSize = ");
-
+        fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n\n");
         VarsArray & evars = e->vars();
+        size_t  maxvars = evars.size();
+        size_t  j;
+
+        char    buff[256];
+
+        // Define the __size_XXX variables that contain the size of data
+        // associated with pointers.
+        for (j = 0; j < maxvars; j++) {
+            Var& var = evars[j];
+
+            if (!var.isPointer())
+                continue;
+
+            const char* varname = var.name().c_str();
+            fprintf(fp, "\tconst unsigned int __size_%s = ", varname);
+
+            getVarEncodingSizeExpression(var, e, buff, sizeof(buff));
+            fprintf(fp, "%s;\n", buff);
+        }
+
+#if WITH_LARGE_SUPPORT
+        // We need to take care of 'isLarge' variable in a special way
+        // Anything before an isLarge variable can be packed into a single
+        // buffer, which is then commited. Each isLarge variable is a pointer
+        // to data that can be written to directly through the pipe, which
+        // will be instant when using a QEMU pipe
+
+        size_t  nvars   = 0;
+        size_t  npointers = 0;
+
+        // First, compute the total size, 8 bytes for the opcode + payload size
+        fprintf(fp, "\t unsigned char *ptr;\n");
+        fprintf(fp, "\t const size_t packetSize = 8");
+
+        for (j = 0; j < maxvars; j++) {
+            fprintf(fp, " + ");
+            npointers += writeVarEncodingSize(evars[j], fp);
+        }
+        if (npointers > 0) {
+            fprintf(fp, " + %u*4", npointers);
+        }
+        fprintf(fp, ";\n");
+
+        // We need to divide the packet into fragments. Each fragment contains
+        // either copied arguments to a temporary buffer, or direct writes for
+        // large variables.
+        //
+        // The first fragment must also contain the opcode+payload_size
+        //
+        nvars = 0;
+        while (nvars < maxvars || maxvars == 0) {
+
+            // Skip over non-large fields
+            for (j = nvars; j < maxvars; j++) {
+                if (evars[j].isLarge())
+                    break;
+            }
+
+            // Write a fragment if needed.
+            if (nvars == 0 || j > nvars) {
+                const char* plus = "";
+
+                if (nvars == 0 && j == maxvars) {
+                    // Simple shortcut for the common case where we don't have large variables;
+                    fprintf(fp, "\tptr = stream->alloc(packetSize);\n");
+
+                } else {
+                    // allocate buffer from the stream until the first large variable
+                    fprintf(fp, "\tptr = stream->alloc(");
+                    plus = "";
+
+                    if (nvars == 0) {
+                        fprintf(fp,"8"); plus = " + ";
+                    }
+                    if (j > nvars) {
+                        npointers = 0;
+                        for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
+                            fprintf(fp, "%s", plus); plus = " + ";
+                            npointers += writeVarEncodingSize(evars[j], fp);
+                        }
+                        if (npointers > 0) {
+                            fprintf(fp, "%s%u*4", plus, npointers); plus = " + ";
+                        }
+                    }
+                    fprintf(fp,");\n");
+                }
+
+                // encode packet header if needed.
+                if (nvars == 0) {
+                    fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n", e->name().c_str());
+                    fprintf(fp, "\t*(unsigned int *)(ptr) = (unsigned int) packetSize; ptr += 4;\n");
+                }
+
+                if (maxvars == 0)
+                    break;
+
+                // encode non-large fields in this fragment
+                for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
+                    writeVarEncodingExpression(evars[j],fp);
+                }
+
+                // Ensure the fragment is commited if it is followed by a large variable
+                if (j < maxvars) {
+                    fprintf(fp, "\tstream->flush();\n");
+                }
+            }
+
+            // If we have one or more large variables, write them directly.
+            // As size + data
+            for ( ; j < maxvars && evars[j].isLarge(); j++) {
+                writeVarLargeEncodingExpression(evars[j], fp);
+            }
+
+            nvars = j;
+        }
+
+#else /* !WITH_LARGE_SUPPORT */
         size_t nvars = evars.size();
         size_t npointers = 0;
+        fprintf(fp, "\t const size_t packetSize = 8");
         for (size_t j = 0; j < nvars; j++) {
-            fprintf(fp, "%s ", j == 0 ? "" : " +");
-            if (evars[j].isPointer()) {
-                npointers++;
-
-                if (evars[j].lenExpression() == "") {
-                    fprintf(stderr, "%s: data len is undefined for '%s'\n",
-                            e->name().c_str(), evars[j].name().c_str());
-                }
-
-                if (evars[j].nullAllowed()) {
-                    fprintf(fp, "(%s != NULL ? %s : 0)",
-                            evars[j].name().c_str(),
-                            evars[j].lenExpression().c_str());
-                } else {
-                    if (evars[j].pointerDir() == Var::POINTER_IN ||
-                        evars[j].pointerDir() == Var::POINTER_INOUT) {
-                        fprintf(fp, "%s", evars[j].lenExpression().c_str());
-                    } else {
-                        fprintf(fp, "0");
-                    }
-                }
-            } else {
-                fprintf(fp, "%u", (unsigned int) evars[j].type()->bytes());
-            }
+            npointers += getVarEncodingSizeExpression(evars[j],e,buff,sizeof(buff));
+            fprintf(fp, " + %s", buff);
         }
-        fprintf(fp, " %s 8 + %u * 4;\n", nvars != 0 ? "+" : "", (unsigned int) npointers);
+        fprintf(fp, " + %u * 4;\n", (unsigned int) npointers);
 
         // allocate buffer from the stream;
-        fprintf(fp, "\t unsigned char *ptr = ctx->m_stream->alloc(packetSize);\n\n");
+        fprintf(fp, "\t unsigned char *ptr = stream->alloc(packetSize);\n\n");
 
         // encode into the stream;
         fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n",  e->name().c_str());
@@ -415,62 +615,23 @@
 
         // out variables
         for (size_t j = 0; j < nvars; j++) {
-            if (evars[j].isPointer()) {
-                // encode a pointer header
-                if (evars[j].nullAllowed()) {
-                    fprintf(fp, "\t*(unsigned int *)(ptr) = (%s != NULL) ? %s : 0; ptr += 4; \n",
-                            evars[j].name().c_str(), evars[j].lenExpression().c_str());
-                } else {
-                    fprintf(fp, "\t*(unsigned int *)(ptr) = %s; ptr += 4; \n",
-                            evars[j].lenExpression().c_str());
-                }
-
-                Var::PointerDir dir = evars[j].pointerDir();
-                if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
-                    if (evars[j].nullAllowed()) {
-                        fprintf(fp, "\tif (%s != NULL) ", evars[j].name().c_str());
-                    } else {
-                        fprintf(fp, "\t");
-                    }
-
-                    if (evars[j].packExpression().size() != 0) {
-                        fprintf(fp, "%s;", evars[j].packExpression().c_str());
-                    } else {
-                        fprintf(fp, "memcpy(ptr, %s, %s);",
-                                evars[j].name().c_str(),
-                                evars[j].lenExpression().c_str());
-                    }
-
-                    if (evars[j].nullAllowed()) {
-                        fprintf(fp, "ptr += %s == NULL ? 0 : %s; \n", evars[j].name().c_str(), evars[j].lenExpression().c_str());
-                    } else {
-                        fprintf(fp, "ptr += %s;\n", evars[j].lenExpression().c_str());
-                    }
-                }
-            } else {
-                // encode a non pointer variable
-                if (!evars[j].isVoid()) {
-                    fprintf(fp, "\t*(%s *) (ptr) = %s; ptr += %u;\n",
-                            evars[j].type()->name().c_str(), evars[j].name().c_str(),
-                            (uint) evars[j].type()->bytes());
-                }
-            }
+            writeVarEncodingExpression(evars[j], fp);
         }
+#endif /* !WITH_LARGE_SUPPORT */
+
         // in variables;
         for (size_t j = 0; j < nvars; j++) {
             if (evars[j].isPointer()) {
                 Var::PointerDir dir = evars[j].pointerDir();
                 if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
+                    const char* varname = evars[j].name().c_str();
                     if (evars[j].nullAllowed()) {
-                        fprintf(fp, "\tif (%s != NULL) ctx->m_stream->readback(%s, %s);\n",
-                                evars[j].name().c_str(),
-                                evars[j].name().c_str(),
-                                evars[j].lenExpression().c_str());
+                        fprintf(fp, "\tif (%s != NULL) ",varname);
                     } else {
-                        fprintf(fp, "\tctx->m_stream->readback(%s, %s);\n",
-                                evars[j].name().c_str(),
-                                evars[j].lenExpression().c_str());
+                        fprintf(fp, "\t");
                     }
+                    fprintf(fp, "stream->readback(%s, __size_%s);\n",
+                            varname, varname);
                 }
             }
         }
@@ -482,7 +643,7 @@
             fprintf(fp, "\t return NULL;\n");
         } else if (e->retval().type()->name() != "void") {
             fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str());
-            fprintf(fp, "\tctx->m_stream->readback(&retval, %u);\n",(uint) e->retval().type()->bytes());
+            fprintf(fp, "\tstream->readback(&retval, %u);\n",(uint) e->retval().type()->bytes());
             fprintf(fp, "\treturn retval;\n");
         }
         fprintf(fp, "}\n\n");
diff --git a/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp b/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
index 413b56a..43b904b 100644
--- a/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
+++ b/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
@@ -119,7 +119,7 @@
         fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str());
     }
 
-    m_retval.init(std::string(""), theType, std::string(""), Var::POINTER_OUT, std::string(""));
+    m_retval.init(std::string(""), theType, std::string(""), Var::POINTER_OUT, std::string(""), std::string(""));
 
     // function name
     m_name = getNextToken(linestr, pos, &last, ",)");
@@ -146,7 +146,7 @@
                 varname = oss.str();
             }
 
-            m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, ""));
+            m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, "", ""));
         }
         pos = last + 1;
     }
@@ -286,22 +286,36 @@
                     (unsigned int)lc, varname.c_str(), name().c_str());
             return -2;
         }
-        pos = last;
-        std::string flag = getNextToken(line, pos, &last, WHITESPACE);
-        if (flag.size() == 0) {
-            fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
-            return -3;
-        }
-
-        if (flag == "nullAllowed") {
-            if (v->isPointer()) {
-                v->setNullAllowed(true);
-            } else {
-                fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
-                        (unsigned int) lc, v->name().c_str());
+        int count = 0;
+        for (;;) {
+            pos = last;
+            std::string flag = getNextToken(line, pos, &last, WHITESPACE);
+            if (flag.size() == 0) {
+                if (count == 0) {
+                    fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
+                    return -3;
+                }
+                break;
             }
-        } else {
-            fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str());
+            count++;
+
+            if (flag == "nullAllowed") {
+                if (v->isPointer()) {
+                    v->setNullAllowed(true);
+                } else {
+                    fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
+                            (unsigned int) lc, v->name().c_str());
+                }
+            } else if (flag == "isLarge") {
+                if (v->isPointer()) {
+                    v->setIsLarge(true);
+                } else {
+                    fprintf(stderr, "WARNING: %u: setting isLarge flag for a non-pointer variable %s\n",
+                            (unsigned int) lc, v->name().c_str());
+                }
+            } else {
+                fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str());
+            }
         }
     } else if (token == "custom_pack") {
         pos = last;
@@ -320,6 +334,23 @@
         // set the size expression into var
         pos = last;
         v->setPackExpression(line.substr(pos));
+    } else if (token == "custom_write") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+        if (varname.size() == 0) {
+            fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_write' attribute\n", (unsigned int)lc);
+            return -1;
+        }
+        Var * v = var(varname);
+        if (v == NULL) {
+            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+                    (unsigned int)lc, varname.c_str(), name().c_str());
+            return -2;
+        }
+        // set the size expression into var
+        pos = last;
+        v->setWriteExpression(line.substr(pos));
     } else if (token == "flag") {
         pos = last;
         std::string flag = getNextToken(line, pos, &last, WHITESPACE);
diff --git a/tools/emulator/opengl/host/tools/emugen/README b/tools/emulator/opengl/host/tools/emugen/README
index 4d2c28d..5df11a3 100644
--- a/tools/emulator/opengl/host/tools/emugen/README
+++ b/tools/emulator/opengl/host/tools/emugen/README
@@ -313,7 +313,10 @@
 
  var_flag 
  	 description : set variable flags
- 	 format: var_flag <varname> < nullAllowed | ... >
+ 	 format: var_flag <varname> < nullAllowed | isLarge | ... >
+
+        nullAllowed -> for pointer variables, indicates that NULL is a valid value
+        isLarge     -> for pointer variables, indicates that the data should be sent without an intermediate copy
 
  flag
 	description: set entry point flag; 
diff --git a/tools/emulator/opengl/host/tools/emugen/Var.h b/tools/emulator/opengl/host/tools/emugen/Var.h
index c9735c7..322c66a 100644
--- a/tools/emulator/opengl/host/tools/emugen/Var.h
+++ b/tools/emulator/opengl/host/tools/emugen/Var.h
@@ -30,7 +30,9 @@
         m_lenExpression(""),
         m_pointerDir(POINTER_IN),
         m_nullAllowed(false),
+        m_isLarge(false),
         m_packExpression(""),
+        m_writeExpression(""),
         m_paramCheckExpression("")
 
     {
@@ -40,26 +42,33 @@
         const VarType * vartype,
         const std::string & lenExpression,
         PointerDir dir,
-        const std::string &packExpression) :
+        const std::string &packExpression,
+        const std::string &writeExpression) :
         m_name(name),
         m_type(const_cast<VarType *>(vartype)),
         m_lenExpression(lenExpression),
         m_pointerDir(dir),
         m_nullAllowed(false),
+        m_isLarge(false),
         m_packExpression(packExpression),
-		m_paramCheckExpression("")	
+        m_writeExpression(writeExpression),
+	m_paramCheckExpression("")
     {
     }
 
     void init(const std::string name, const VarType * vartype,
               std::string lenExpression,
-              PointerDir dir, std::string packExpression) {
+              PointerDir dir,
+              std::string packExpression,
+              std::string writeExpression) {
         m_name = name;
         m_type = vartype;
         m_lenExpression = lenExpression;
         m_packExpression = packExpression;
+        m_writeExpression = writeExpression;
         m_pointerDir = dir;
         m_nullAllowed = false;
+        m_isLarge = false;
 
     }
 
@@ -69,14 +78,18 @@
     bool isVoid() const { return ((m_type->bytes() == 0) && (!m_type->isPointer())); }
     const std::string & lenExpression() const { return m_lenExpression; }
     const std::string & packExpression() const { return(m_packExpression); }
+    const std::string & writeExpression() const { return(m_writeExpression); }
     const std::string & paramCheckExpression() const { return m_paramCheckExpression; }
     void setLenExpression(const std::string & lenExpression) { m_lenExpression = lenExpression; }
     void setPackExpression(const std::string & packExpression) { m_packExpression = packExpression; }
+    void setWriteExpression(const std::string & writeExpression) { m_writeExpression = writeExpression; }
     void setParamCheckExpression(const std::string & paramCheckExpression) { m_paramCheckExpression = paramCheckExpression; }
     void setPointerDir(PointerDir dir) { m_pointerDir = dir; }
     PointerDir pointerDir() { return m_pointerDir; }
     void setNullAllowed(bool state) { m_nullAllowed = state; }
+    void setIsLarge(bool state) { m_isLarge = state; }
     bool nullAllowed() const { return m_nullAllowed; }
+    bool isLarge() const { return m_isLarge; }
     void printType(FILE *fp) { fprintf(fp, "%s", m_type->name().c_str()); }
     void printTypeName(FILE *fp) { printType(fp); fprintf(fp, " %s", m_name.c_str()); }
 
@@ -87,7 +100,9 @@
     std::string m_lenExpression; // an expression to calcualte a pointer data size
     PointerDir m_pointerDir;
     bool m_nullAllowed;
+    bool m_isLarge;
     std::string m_packExpression; // an expression to pack data into the stream
+    std::string m_writeExpression; // an expression to write data into the stream
     std::string m_paramCheckExpression; //an expression to check parameter value
 
 };
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/Android.mk b/tools/emulator/opengl/shared/OpenglCodecCommon/Android.mk
index fb9c2c9..2f7da79 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/Android.mk
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/Android.mk
@@ -11,10 +11,6 @@
         TcpStream.cpp \
         TimeUtils.cpp
 
-ifneq ($(HOST_OS),windows)
-    commonSources += UnixStream.cpp
-endif
-
 ### CodecCommon  guest ##############################################
 $(call emugl-begin-static-library,libOpenglCodecCommon)
 
@@ -31,6 +27,12 @@
 
 LOCAL_SRC_FILES := $(commonSources)
 
+ifeq ($(HOST_OS),windows)
+    LOCAL_SRC_FILES += Win32PipeStream.cpp
+else
+    LOCAL_SRC_FILES += UnixStream.cpp
+endif
+
 $(call emugl-export,STATIC_LIBRARIES,libcutils)
 $(call emugl-export,C_INCLUDES,$(LOCAL_PATH))
 $(call emugl-end-module)
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp
index 244cfbb..ddc56d0 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.cpp
@@ -85,13 +85,18 @@
 
 int SocketStream::commitBuffer(size_t size)
 {
+    return writeFully(m_buf, size);
+}
+
+int SocketStream::writeFully(const void* buffer, size_t size)
+{
     if (!valid()) return -1;
 
     size_t res = size;
     int retval = 0;
 
     while (res > 0) {
-        ssize_t stat = ::send(m_sock, (const char *)(m_buf) + (size - res), res, 0);
+        ssize_t stat = ::send(m_sock, (const char *)buffer + (size - res), res, 0);
         if (stat < 0) {
             if (errno != EINTR) {
                 retval =  stat;
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h
index c54dea7..3a501b4 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/SocketStream.h
@@ -37,6 +37,7 @@
 
     bool valid() { return m_sock >= 0; }
     virtual int recv(void *buf, size_t len);
+    virtual int writeFully(const void *buf, size_t len);
 
 protected:
     int            m_sock;
@@ -44,7 +45,6 @@
     unsigned char *m_buf;
 
     SocketStream(int sock, size_t bufSize);
-    int writeFully(const void *buf, size_t len);
 };
 
 #endif /* __SOCKET_STREAM_H */
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp b/tools/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp
new file mode 100644
index 0000000..e1a0b9b
--- /dev/null
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp
@@ -0,0 +1,239 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "Win32PipeStream.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <windows.h>
+
+#ifndef _WIN32
+#error ONLY BUILD THIS SOURCE FILE FOR WINDOWS!
+#endif
+
+/* The official documentation states that the name of a given named
+ * pipe cannot be more than 256 characters long.
+ */
+#define NAMED_PIPE_MAX 256
+
+Win32PipeStream::Win32PipeStream(size_t bufSize) :
+    SocketStream(bufSize),
+    m_pipe(INVALID_HANDLE_VALUE)
+{
+}
+
+Win32PipeStream::Win32PipeStream(HANDLE pipe, size_t bufSize) :
+    SocketStream(-1, bufSize),
+    m_pipe(pipe)
+{
+}
+
+Win32PipeStream::~Win32PipeStream()
+{
+    if (m_pipe != INVALID_HANDLE_VALUE) {
+        CloseHandle(m_pipe);
+        m_pipe = INVALID_HANDLE_VALUE;
+    }
+}
+
+/* Initialize the pipe name corresponding to a given port
+ */
+static void
+make_pipe_name(char *path, size_t  pathlen, int port_number)
+{
+    snprintf(path, pathlen, "\\\\.\\pipe\\qemu-gles-%d", port_number);
+}
+
+
+/* Technical note: Named pipes work differently from BSD Sockets.
+ * One does not create/bind a pipe, and collect a new handle each
+ * time a client connects with accept().
+ *
+ * Instead, the server creates a new pipe instance each time it wants
+ * to get a new client connection, then calls ConnectNamedPipe() to
+ * wait for a connection.
+ *
+ * So listen() is a no-op, and accept() really creates the pipe handle.
+ *
+ * Also, connect() must create a pipe handle with CreateFile() and
+ * wait for a server instance with WaitNamedPipe()
+ */
+int Win32PipeStream::listen(unsigned short port)
+{
+    // just save the port number for accept()
+    m_port = port;
+    return 0;
+}
+
+SocketStream * Win32PipeStream::accept()
+{
+    char path[NAMED_PIPE_MAX+1];
+    SocketStream*  clientStream;
+    HANDLE pipe;
+
+    make_pipe_name(path, sizeof(path), m_port);
+
+    pipe = ::CreateNamedPipe(
+                path,                // pipe name
+                PIPE_ACCESS_DUPLEX,  // read-write access
+                PIPE_TYPE_BYTE |     // byte-oriented writes
+                PIPE_READMODE_BYTE | // byte-oriented reads
+                PIPE_WAIT,           // blocking operations
+                PIPE_UNLIMITED_INSTANCES, // no limit on clients
+                4096,                // input buffer size
+                4096,                // output buffer size
+                0,                   // client time-out
+                NULL);               // default security attributes
+
+    if (pipe == INVALID_HANDLE_VALUE) {
+        ERR("%s: CreateNamedPipe failed %d\n", __FUNCTION__, (int)GetLastError());
+        return NULL;
+    }
+
+    // Stupid Win32 API design: If a client is already connected, then
+    // ConnectNamedPipe will return 0, and GetLastError() will return
+    // ERROR_PIPE_CONNECTED. This is not an error! It just means that the
+    // function didn't have to wait.
+    //
+    if (::ConnectNamedPipe(pipe, NULL) == 0 && GetLastError() != ERROR_PIPE_CONNECTED) {
+        ERR("%s: ConnectNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError());
+        CloseHandle(pipe);
+        return NULL;
+    }
+
+    clientStream = new Win32PipeStream(pipe, m_bufsize);
+    return clientStream;
+}
+
+int Win32PipeStream::connect(unsigned short port)
+{
+    char   path[NAMED_PIPE_MAX+1];
+    HANDLE pipe;
+    int    tries = 10;
+
+    make_pipe_name(path, sizeof(path), port);
+
+    /* We're going to loop in order to wait for the pipe server to
+     * be setup properly.
+     */
+    for (; tries > 0; tries--) {
+        pipe = ::CreateFile(
+                    path,                          // pipe name
+                    GENERIC_READ | GENERIC_WRITE,  // read & write
+                    0,                             // no sharing
+                    NULL,                          // default security attrs
+                    OPEN_EXISTING,                 // open existing pipe
+                    0,                             // default attributes
+                    NULL);                         // no template file
+
+        /* If we have a valid pipe handle, break from the loop */
+        if (pipe != INVALID_HANDLE_VALUE) {
+            break;
+        }
+
+        /* We can get here if the pipe is busy, i.e. if the server hasn't
+         * create a new pipe instance to service our request. In which case
+         * GetLastError() will return ERROR_PIPE_BUSY.
+         *
+         * If so, then use WaitNamedPipe() to wait for a decent time
+         * to try again.
+         */
+        if (GetLastError() != ERROR_PIPE_BUSY) {
+            /* Not ERROR_PIPE_BUSY */
+            ERR("%s: CreateFile failed: %d\n", __FUNCTION__, (int)GetLastError());
+            errno = EINVAL;
+            return -1;
+        }
+
+        /* Wait for 5 seconds */
+        if ( !WaitNamedPipe(path, 5000) ) {
+            ERR("%s: WaitNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError());
+            errno = EINVAL;
+            return -1;
+        }
+    }
+
+    m_pipe = pipe;
+    return 0;
+}
+
+/* Special buffer methods, since we can't use socket functions here */
+
+int Win32PipeStream::commitBuffer(size_t size)
+{
+    if (m_pipe == INVALID_HANDLE_VALUE)
+        return -1;
+
+    size_t res = size;
+    int retval = 0;
+
+    while (res > 0) {
+        DWORD  written;
+        if (! ::WriteFile(m_pipe, (const char *)m_buf + (size - res), res, &written, NULL)) {
+            retval =  -1;
+            ERR("%s: failed: %d\n", __FUNCTION__, (int)GetLastError());
+            break;
+        }
+        res -= written;
+    }
+    return retval;
+}
+
+const unsigned char *Win32PipeStream::readFully(void *buf, size_t len)
+{
+    const unsigned char* ret = NULL;
+
+    if (m_pipe == INVALID_HANDLE_VALUE)
+        return NULL;
+
+    if (!buf) {
+        return NULL;  // do not allow NULL buf in that implementation
+    }
+
+    size_t res = len;
+    while (res > 0) {
+        DWORD  readcount = 0;
+        if (! ::ReadFile(m_pipe, (char *)buf + (len - res), res, &readcount, NULL) || readcount == 0) {
+            errno = (int)GetLastError();
+            return NULL;
+        }
+        res -= readcount;
+    }
+    return (const unsigned char *)buf;
+}
+
+const unsigned char *Win32PipeStream::read( void *buf, size_t *inout_len)
+{
+    size_t len = *inout_len;
+    DWORD  readcount;
+
+    if (m_pipe == INVALID_HANDLE_VALUE)
+        return NULL;
+
+    if (!buf) {
+        return NULL;  // do not allow NULL buf in that implementation
+    }
+
+    if (!::ReadFile(m_pipe, (char *)buf, len, &readcount, NULL)) {
+        errno = (int)GetLastError();
+        return NULL;
+    }
+
+    *inout_len = (size_t)readcount;
+    return (const unsigned char *)buf;
+}
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.h b/tools/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.h
new file mode 100644
index 0000000..4114545
--- /dev/null
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.h
@@ -0,0 +1,41 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __WIN32_PIPE_STREAM_H
+#define __WIN32_PIPE_STREAM_H
+
+#include "SocketStream.h"
+#include <windows.h>
+
+class Win32PipeStream : public SocketStream {
+public:
+    explicit Win32PipeStream(size_t bufsize = 10000);
+    virtual ~Win32PipeStream();
+    virtual int listen(unsigned short port);
+    virtual SocketStream *accept();
+    virtual int connect(unsigned short port);
+
+    virtual int commitBuffer(size_t size);
+    virtual const unsigned char *readFully(void *buf, size_t len);
+    virtual const unsigned char *read(void *buf, size_t *inout_len);
+
+private:
+    Win32PipeStream(HANDLE pipe, size_t bufSize);
+    HANDLE  m_pipe;
+    int     m_port;
+};
+
+
+#endif
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
index b0702a7..ae70598 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.cpp
@@ -16,6 +16,7 @@
 #include "glUtils.h"
 #include <string.h>
 #include "ErrorLog.h"
+#include <IOStream.h>
 
 size_t glSizeof(GLenum type)
 {
@@ -344,6 +345,25 @@
     }
 }
 
+void glUtilsWritePackPointerData(void* _stream, unsigned char *src,
+                                 int size, GLenum type, unsigned int stride,
+                                 unsigned int datalen)
+{
+    IOStream* stream = reinterpret_cast<IOStream*>(_stream);
+
+    unsigned int  vsize = size * glSizeof(type);
+    if (stride == 0) stride = vsize;
+
+    if (stride == vsize) {
+        stream->writeFully(src, datalen);
+    } else {
+        for (unsigned int i = 0; i < datalen; i += vsize) {
+            stream->writeFully(src, (size_t)vsize);
+            src += stride;
+        }
+    }
+}
+
 int glUtilsPixelBitSize(GLenum format, GLenum type)
 {
     int components = 0;
diff --git a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h
index c66c568..f8857f1 100644
--- a/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h
+++ b/tools/emulator/opengl/shared/OpenglCodecCommon/glUtils.h
@@ -51,6 +51,9 @@
     void   glUtilsPackPointerData(unsigned char *dst, unsigned char *str,
                            int size, GLenum type, unsigned int stride,
                            unsigned int datalen);
+    void glUtilsWritePackPointerData(void* stream, unsigned char *src,
+                                    int size, GLenum type, unsigned int stride,
+                                    unsigned int datalen);
     int glUtilsPixelBitSize(GLenum format, GLenum type);
     void   glUtilsPackStrings(char *ptr, char **strings, GLint *length, GLsizei count);
     int glUtilsCalcShaderSourceLen(char **strings, GLint *length, GLsizei count);
diff --git a/tools/emulator/opengl/system/GLESv1_enc/GLEncoder.cpp b/tools/emulator/opengl/system/GLESv1_enc/GLEncoder.cpp
index 6d12fe3..43391f0 100644
--- a/tools/emulator/opengl/system/GLESv1_enc/GLEncoder.cpp
+++ b/tools/emulator/opengl/system/GLESv1_enc/GLEncoder.cpp
@@ -544,7 +544,7 @@
     m_glBufferData_enc = set_glBufferData(s_glBufferData);
     m_glBufferSubData_enc = set_glBufferSubData(s_glBufferSubData);
     m_glDeleteBuffers_enc = set_glDeleteBuffers(s_glDeleteBuffers);
-    
+
     m_glEnableClientState_enc = set_glEnableClientState(s_glEnableClientState);
     m_glDisableClientState_enc = set_glDisableClientState(s_glDisableClientState);
     m_glIsEnabled_enc = set_glIsEnabled(s_glIsEnabled);
@@ -558,7 +558,7 @@
 
 GLEncoder::~GLEncoder()
 {
-    delete m_compressedTextureFormats;
+    delete [] m_compressedTextureFormats;
 }
 
 size_t GLEncoder::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack)
diff --git a/tools/emulator/opengl/system/GLESv1_enc/gl.attrib b/tools/emulator/opengl/system/GLESv1_enc/gl.attrib
index fed0f7a..9b84f89 100644
--- a/tools/emulator/opengl/system/GLESv1_enc/gl.attrib
+++ b/tools/emulator/opengl/system/GLESv1_enc/gl.attrib
@@ -240,7 +240,7 @@
 glTexImage2D
 	dir pixels in
 	len pixels pixelDataSize(self, width, height, format, type, 0)
-	var_flag pixels nullAllowed
+	var_flag pixels nullAllowed isLarge
 
 #void glTexParameteriv(GLenum target, GLenum pname, GLint *params)
 glTexParameteriv
@@ -253,6 +253,7 @@
 #void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
 glTexSubImage2D
 	len pixels pixelDataSize(self, width, height, format, type, 0)
+        var_flag pixels isLarge
 
 #void glVertexPointer(GLint size, GLenum type, GLsizei stride, GLvoid *pointer)
 # we treat the pointer as an offset to a VBO
diff --git a/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib b/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib
index 538c453..7fe9a66 100644
--- a/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib
+++ b/tools/emulator/opengl/system/GLESv2_enc/gl2.attrib
@@ -9,20 +9,22 @@
 #void glBufferData(GLenum target, GLsizeiptr size, GLvoid *data, GLenum usage)
 glBufferData
 	len data size
-	var_flag data nullAllowed
+	var_flag data nullAllowed isLarge
 
 #void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data)
 glBufferSubData
 	len data size
+        var_flag data isLarge
 
 #void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLvoid *data)
 glCompressedTexImage2D
 	len data imageSize
-    var_flag data nullAllowed
+    var_flag data nullAllowed isLarge
 
 #void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLvoid *data)
 glCompressedTexSubImage2D
 	len data imageSize
+        var_flag data isLarge
 
 #void glDeleteBuffers(GLsizei n, GLuint *buffers)
 glDeleteBuffers
@@ -243,7 +245,7 @@
 glTexImage2D
 	dir pixels in
 	len pixels pixelDataSize(self, width, height, format, type, 0)
-	var_flag pixels nullAllowed
+	var_flag pixels nullAllowed isLarge
 
 #void glTexParameterfv(GLenum target, GLenum pname, GLfloat *params)
 glTexParameterfv
@@ -255,6 +257,7 @@
 #void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
 glTexSubImage2D
 	len pixels pixelDataSize(self, width, height, format, type, 0)
+        var_flag pixels isLarge
 	
 #void glUniform1fv(GLint location, GLsizei count, GLfloat *v)
 glUniform1fv
@@ -333,20 +336,23 @@
 
 #void glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLvoid *pixels)
 glTexImage3DOES
-	len pixels pixelDataSize3D(self, width, height, depth, format, type, 0)	
-	var_flag pixels nullAllowed
+	len pixels pixelDataSize3D(self, width, height, depth, format, type, 0)
+	var_flag pixels nullAllowed isLarge
 
 #void glTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *pixels)
 glTexSubImage3DOES
 	len pixels pixelDataSize3D(self, width, height, depth, format, type, 0)	
+        var_flag pixels isLarge
 
 #void glCompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLvoid *data)
 glCompressedTexImage3DOES
 	len data imageSize
+        var_flag data isLarge
 
 #void glCompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLvoid *data)
 glCompressedTexSubImage3DOES
 	len data imageSize
+        var_flag data isLarge
 
 #void glDeleteVertexArraysOES(GLsizei n, GLuint *arrays)
 glDeleteVertexArraysOES
diff --git a/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h b/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h
index db36286..57ee399 100644
--- a/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h
+++ b/tools/emulator/opengl/system/OpenglSystemCommon/QemuPipeStream.h
@@ -39,8 +39,7 @@
     bool valid() { return m_sock >= 0; }
     int recv(void *buf, size_t len);
 
-private:
-    int writeFully(const void *buf, size_t len);
+    virtual int writeFully(const void *buf, size_t len);
 
 private:
     int m_sock;
diff --git a/tools/emulator/opengl/system/egl/ClientAPIExts.cpp b/tools/emulator/opengl/system/egl/ClientAPIExts.cpp
index 888c231..5e81afe 100644
--- a/tools/emulator/opengl/system/egl/ClientAPIExts.cpp
+++ b/tools/emulator/opengl/system/egl/ClientAPIExts.cpp
@@ -129,7 +129,7 @@
 #define API_ENTRY_RET(rtype,fname,params,args) \
     API_ENTRY(fname,params,args)
 
-static struct _client_ext_funcs {
+static const struct _client_ext_funcs {
     const char *fname;
     void* proc;
 } s_client_ext_funcs[] = {
diff --git a/tools/emulator/opengl/system/egl/ClientAPIExts.in b/tools/emulator/opengl/system/egl/ClientAPIExts.in
index c3162eb..5850701 100644
--- a/tools/emulator/opengl/system/egl/ClientAPIExts.in
+++ b/tools/emulator/opengl/system/egl/ClientAPIExts.in
@@ -2,7 +2,7 @@
 // Each extension function should have one of the following
 // macro definitions:
 //    API_ENTRY(funcname, paramlist, arglist)
-//  -or- (in case funciton has return value)
+//  -or- (if the function has a return value)
 //    API_ENTRY_RET(return_type,funcname, paramlist, arglist)
 //
 API_ENTRY(glEGLImageTargetTexture2DOES,
diff --git a/tools/emulator/opengl/system/egl/eglDisplay.cpp b/tools/emulator/opengl/system/egl/eglDisplay.cpp
index 78025b1..7beeb8e 100644
--- a/tools/emulator/opengl/system/egl/eglDisplay.cpp
+++ b/tools/emulator/opengl/system/egl/eglDisplay.cpp
@@ -19,17 +19,17 @@
 
 static const int systemEGLVersionMajor = 1;
 static const int systemEGLVersionMinor = 4;
-static const char *systemEGLVendor = "Google Android emulator";
+static const char systemEGLVendor[] = "Google Android emulator";
 
 // list of extensions supported by this EGL implementation
 //  NOTE that each extension name should be suffixed with space
-static const char *systemStaticEGLExtensions =
+static const char systemStaticEGLExtensions[] =
             "EGL_ANDROID_image_native_buffer ";
 
 // list of extensions supported by this EGL implementation only if supported
 // on the host implementation.
 //  NOTE that each extension name should be suffixed with space
-static const char *systemDynamicEGLExtensions =
+static const char systemDynamicEGLExtensions[] =
             "EGL_KHR_image_base "
             "EGL_KHR_gl_texture_2d_image ";
 
@@ -70,6 +70,11 @@
     pthread_mutex_init(&m_lock, NULL);
 }
 
+eglDisplay::~eglDisplay()
+{
+    pthread_mutex_destroy(&m_lock);
+}
+
 bool eglDisplay::initialize(EGLClient_eglInterface *eglIface)
 {
     pthread_mutex_lock(&m_lock);
diff --git a/tools/emulator/opengl/system/egl/eglDisplay.h b/tools/emulator/opengl/system/egl/eglDisplay.h
index 934c699..9d979d9 100644
--- a/tools/emulator/opengl/system/egl/eglDisplay.h
+++ b/tools/emulator/opengl/system/egl/eglDisplay.h
@@ -33,6 +33,7 @@
 {
 public:
     eglDisplay();
+    ~eglDisplay();
 
     bool initialize(EGLClient_eglInterface *eglIface);
     void terminate();
diff --git a/tools/emulator/opengl/system/egl/egl_ftable.h b/tools/emulator/opengl/system/egl/egl_ftable.h
index ee40585..2c9d19a 100644
--- a/tools/emulator/opengl/system/egl/egl_ftable.h
+++ b/tools/emulator/opengl/system/egl/egl_ftable.h
@@ -13,7 +13,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-static struct _egl_funcs_by_name {
+static const struct _egl_funcs_by_name {
     const char *name;
     void *proc;
 } egl_funcs_by_name[] = {
@@ -63,4 +63,4 @@
     {"eglSetSwapRectangleANDROID", (void *)eglSetSwapRectangleANDROID}
 };
 
-static int egl_num_funcs = sizeof(egl_funcs_by_name) / sizeof(struct _egl_funcs_by_name);
+static const int egl_num_funcs = sizeof(egl_funcs_by_name) / sizeof(struct _egl_funcs_by_name);
diff --git a/tools/emulator/opengl/system/gralloc/gralloc.cpp b/tools/emulator/opengl/system/gralloc/gralloc.cpp
index 9c3df97..b27eaa3 100644
--- a/tools/emulator/opengl/system/gralloc/gralloc.cpp
+++ b/tools/emulator/opengl/system/gralloc/gralloc.cpp
@@ -31,6 +31,21 @@
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
+/* Set to 1 or 2 to enable debug traces */
+#define DEBUG  0
+
+#if DEBUG >= 1
+#  define D(...)   LOGD(__VA_ARGS__)
+#else
+#  define D(...)   ((void)0)
+#endif
+
+#if DEBUG >= 2
+#  define DD(...)  LOGD(__VA_ARGS__)
+#else
+#  define DD(...)  ((void)0)
+#endif
+
 #define DBG_FUNC DBG("%s\n", __FUNCTION__)
 //
 // our private gralloc module structure
@@ -115,7 +130,7 @@
                          int w, int h, int format, int usage,
                          buffer_handle_t* pHandle, int* pStride)
 {
-    LOGD("gralloc_alloc w=%d h=%d usage=0x%x\n", w, h, usage);
+    D("gralloc_alloc w=%d h=%d usage=0x%x\n", w, h, usage);
 
     gralloc_device_t *grdev = (gralloc_device_t *)dev;
     if (!grdev || !pHandle || !pStride)
@@ -182,7 +197,7 @@
         *pStride = bpr / bpp;
     }
 
-    LOGD("gralloc_alloc ashmem_size=%d, tid %d\n", ashmem_size, gettid());
+    D("gralloc_alloc ashmem_size=%d, tid %d\n", ashmem_size, gettid());
 
     //
     // Allocate space in ashmem if needed
@@ -194,7 +209,7 @@
 
         fd = ashmem_create_region("gralloc-buffer", ashmem_size);
         if (fd < 0) {
-            LOGE("gralloc_alloc failed to create ashmem region err=%d\n", errno);
+            LOGE("gralloc_alloc failed to create ashmem region: %s\n", strerror(errno));
             return -errno;
         }
     }
@@ -224,7 +239,7 @@
         DEFINE_HOST_CONNECTION;
         if (hostCon && rcEnc) {
             cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, glFormat);
-            LOGD("Created host ColorBuffer 0x%x\n", cb->hostHandle);
+            D("Created host ColorBuffer 0x%x\n", cb->hostHandle);
         }
 
         if (!cb->hostHandle) {
@@ -264,7 +279,7 @@
 
     if (cb->hostHandle != 0) {
         DEFINE_AND_VALIDATE_HOST_CONNECTION;
-
+        D("Destroying host ColorBuffer 0x%x\n", cb->hostHandle);
         rcEnc->rcDestroyColorBuffer(rcEnc, cb->hostHandle);
     }
 
@@ -370,7 +385,7 @@
     DEFINE_AND_VALIDATE_HOST_CONNECTION;
 
     // send request to host
-    // XXX - should be implemented
+    // TODO: XXX - should be implemented
     //rcEnc->rc_XXX
 
     return 0;
@@ -399,9 +414,7 @@
 {
     fb_device_t *fbdev = (fb_device_t *)dev;
 
-    if (fbdev) {
-        delete fbdev;
-    }
+    delete fbdev;
 
     return 0;
 }
@@ -418,11 +431,12 @@
         return sFallback->registerBuffer(sFallback, handle);
     }
 
+    D("gralloc_register_buffer(%p) called", handle);
 
     private_module_t *gr = (private_module_t *)module;
     cb_handle_t *cb = (cb_handle_t *)handle;
     if (!gr || !cb_handle_t::validate(cb)) {
-        ERR("gralloc_register_buffer: invalid buffer");
+        ERR("gralloc_register_buffer(%p): invalid buffer", cb);
         return -EINVAL;
     }
 
@@ -434,7 +448,7 @@
         void *vaddr;
         int err = map_buffer(cb, &vaddr);
         if (err) {
-            ERR("gralloc_register_buffer: map failed");
+            ERR("gralloc_register_buffer(%p): map failed: %s", cb, strerror(-err));
             return -err;
         }
         cb->mappedPid = getpid();
@@ -453,7 +467,7 @@
     private_module_t *gr = (private_module_t *)module;
     cb_handle_t *cb = (cb_handle_t *)handle;
     if (!gr || !cb_handle_t::validate(cb)) {
-        ERR("gralloc_unregister_buffer: invalid buffer");
+        ERR("gralloc_unregister_buffer(%p): invalid buffer", cb);
         return -EINVAL;
     }
 
@@ -465,13 +479,15 @@
         void *vaddr;
         int err = munmap((void *)cb->ashmemBase, cb->ashmemSize);
         if (err) {
-            ERR("gralloc_unregister_buffer: unmap failed");
+            ERR("gralloc_unregister_buffer(%p): unmap failed", cb);
             return -EINVAL;
         }
         cb->ashmemBase = NULL;
         cb->mappedPid = 0;
     }
 
+    D("gralloc_unregister_buffer(%p) done\n", cb);
+
     return 0;
 }
 
@@ -640,7 +656,7 @@
 {
     int status = -EINVAL;
 
-    LOGD("gralloc_device_open %s\n", name);
+    D("gralloc_device_open %s\n", name);
 
     pthread_once( &sFallbackOnce, fallback_init );
     if (sFallback != NULL) {
@@ -689,16 +705,21 @@
         //
         // Query the host for Framebuffer attributes
         //
-        LOGD("gralloc: query Frabuffer attribs\n");
+        D("gralloc: query Frabuffer attribs\n");
         EGLint width = rcEnc->rcGetFBParam(rcEnc, FB_WIDTH);
-        LOGD("gralloc: width=%d\n", width);
+        D("gralloc: width=%d\n", width);
         EGLint height = rcEnc->rcGetFBParam(rcEnc, FB_HEIGHT);
-        LOGD("gralloc: height=%d\n", height);
+        D("gralloc: height=%d\n", height);
         EGLint xdpi = rcEnc->rcGetFBParam(rcEnc, FB_XDPI);
+        D("gralloc: xdpi=%d\n", xdpi);
         EGLint ydpi = rcEnc->rcGetFBParam(rcEnc, FB_YDPI);
+        D("gralloc: ydpi=%d\n", ydpi);
         EGLint fps = rcEnc->rcGetFBParam(rcEnc, FB_FPS);
+        D("gralloc: fps=%d\n", fps);
         EGLint min_si = rcEnc->rcGetFBParam(rcEnc, FB_MIN_SWAP_INTERVAL);
+        D("gralloc: min_swap=%d\n", min_si);
         EGLint max_si = rcEnc->rcGetFBParam(rcEnc, FB_MAX_SWAP_INTERVAL);
+        D("gralloc: max_swap=%d\n", max_si);
 
         //
         // Allocate memory for the framebuffer device
diff --git a/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib b/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib
index c51ae0e..8b9972f 100644
--- a/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib
+++ b/tools/emulator/opengl/system/renderControl_enc/renderControl.attrib
@@ -26,10 +26,10 @@
 
 rcChooseConfig
     dir attribs in
-	len attribs attribs_size
-	dir configs out
+    len attribs attribs_size
+    dir configs out
     var_flag configs nullAllowed
-	len configs configs_size*sizeof(uint32_t)
+    len configs configs_size*sizeof(uint32_t)
 
 rcReadColorBuffer
     dir pixels out
@@ -38,3 +38,4 @@
 rcUpdateColorBuffer
     dir pixels in
     len pixels (((glUtilsPixelBitSize(format, type) * width) >> 3) * height)
+    var_flag pixels isLarge
diff --git a/tools/emulator/skins/WVGA800/hardware.ini b/tools/emulator/skins/WVGA800/hardware.ini
index 19e3b35..96dee4f 100644
--- a/tools/emulator/skins/WVGA800/hardware.ini
+++ b/tools/emulator/skins/WVGA800/hardware.ini
@@ -1,4 +1,4 @@
 # skin-specific hardware values
 hw.lcd.density=240
 vm.heapSize=24
-hw.ramSize=256
\ No newline at end of file
+hw.ramSize=512
\ No newline at end of file
diff --git a/tools/emulator/skins/WVGA854/hardware.ini b/tools/emulator/skins/WVGA854/hardware.ini
index 9434288..6ac3d82 100644
--- a/tools/emulator/skins/WVGA854/hardware.ini
+++ b/tools/emulator/skins/WVGA854/hardware.ini
@@ -1,4 +1,4 @@
 # skin-specific hardware values
 hw.lcd.density=240
 vm.heapSize=24
-hw.ramSize=256
+hw.ramSize=512
diff --git a/tools/emulator/skins/WXGA/arrow_down.png b/tools/emulator/skins/WXGA720/arrow_down.png
similarity index 100%
rename from tools/emulator/skins/WXGA/arrow_down.png
rename to tools/emulator/skins/WXGA720/arrow_down.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/arrow_left.png b/tools/emulator/skins/WXGA720/arrow_left.png
similarity index 100%
rename from tools/emulator/skins/WXGA/arrow_left.png
rename to tools/emulator/skins/WXGA720/arrow_left.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/arrow_right.png b/tools/emulator/skins/WXGA720/arrow_right.png
similarity index 100%
rename from tools/emulator/skins/WXGA/arrow_right.png
rename to tools/emulator/skins/WXGA720/arrow_right.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/arrow_up.png b/tools/emulator/skins/WXGA720/arrow_up.png
similarity index 100%
rename from tools/emulator/skins/WXGA/arrow_up.png
rename to tools/emulator/skins/WXGA720/arrow_up.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA720/background_land.png b/tools/emulator/skins/WXGA720/background_land.png
new file mode 100755
index 0000000..2aba27e
--- /dev/null
+++ b/tools/emulator/skins/WXGA720/background_land.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA720/background_port.png b/tools/emulator/skins/WXGA720/background_port.png
new file mode 100755
index 0000000..9561ca8
--- /dev/null
+++ b/tools/emulator/skins/WXGA720/background_port.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/button.png b/tools/emulator/skins/WXGA720/button.png
similarity index 100%
rename from tools/emulator/skins/WXGA/button.png
rename to tools/emulator/skins/WXGA720/button.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/controls.png b/tools/emulator/skins/WXGA720/controls.png
similarity index 100%
rename from tools/emulator/skins/WXGA/controls.png
rename to tools/emulator/skins/WXGA720/controls.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA720/hardware.ini b/tools/emulator/skins/WXGA720/hardware.ini
new file mode 100755
index 0000000..3be263c
--- /dev/null
+++ b/tools/emulator/skins/WXGA720/hardware.ini
@@ -0,0 +1,8 @@
+# skin-specific hardware values
+hw.lcd.density=320
+vm.heapSize=48
+hw.ramSize=1024
+hw.keyboard.lid=no
+hw.mainKeys=no
+
+
diff --git a/tools/emulator/skins/WXGA/key.png b/tools/emulator/skins/WXGA720/key.png
similarity index 100%
rename from tools/emulator/skins/WXGA/key.png
rename to tools/emulator/skins/WXGA720/key.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/keyboard.png b/tools/emulator/skins/WXGA720/keyboard.png
similarity index 100%
rename from tools/emulator/skins/WXGA/keyboard.png
rename to tools/emulator/skins/WXGA720/keyboard.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA720/layout b/tools/emulator/skins/WXGA720/layout
new file mode 100755
index 0000000..8332bdc
--- /dev/null
+++ b/tools/emulator/skins/WXGA720/layout
@@ -0,0 +1,88 @@
+parts {
+    portrait {
+        background {
+            image   background_port.png
+        }
+    }
+    landscape {
+        background {
+            image   background_land.png
+        }
+    }
+
+    device {
+        display {
+            width   1280
+            height  720
+            x       0
+            y       0
+        }
+    }
+    
+}
+
+layouts {
+
+    landscape {
+        width     1333
+        height    775
+        color     0xe0e0e0
+        event     EV_SW:0:1
+
+        part1 {
+            name    portrait
+            x       1400
+            y       0
+        }
+
+        part2 {
+            name    landscape
+            x       0
+            y       0
+        }
+
+        part3 {
+            name      device
+            x         26
+            y         29
+        }
+    }
+
+    portrait {
+        width     773
+        height    1334
+        color     0xe0e0e0
+        event     EV_SW:0:0
+
+        dpad-rotation 3
+        
+        part1 {
+            name    portrait
+            x       0
+            y       0
+        }
+
+        part2 {
+            name    landscape
+            x       1400
+            y       0
+        }
+
+        part3 {
+            name    device
+            x       27
+            y       1307
+            rotation  3
+        }
+    }
+
+}
+
+keyboard {
+    charmap qwerty2
+}
+
+network {
+    speed  full
+    delay  none
+}
diff --git a/tools/emulator/skins/WXGA/select.png b/tools/emulator/skins/WXGA720/select.png
similarity index 100%
rename from tools/emulator/skins/WXGA/select.png
rename to tools/emulator/skins/WXGA720/select.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/spacebar.png b/tools/emulator/skins/WXGA720/spacebar.png
similarity index 100%
rename from tools/emulator/skins/WXGA/spacebar.png
rename to tools/emulator/skins/WXGA720/spacebar.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/arrow_down.png b/tools/emulator/skins/WXGA800/arrow_down.png
similarity index 100%
copy from tools/emulator/skins/WXGA/arrow_down.png
copy to tools/emulator/skins/WXGA800/arrow_down.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/arrow_left.png b/tools/emulator/skins/WXGA800/arrow_left.png
similarity index 100%
copy from tools/emulator/skins/WXGA/arrow_left.png
copy to tools/emulator/skins/WXGA800/arrow_left.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/arrow_right.png b/tools/emulator/skins/WXGA800/arrow_right.png
similarity index 100%
copy from tools/emulator/skins/WXGA/arrow_right.png
copy to tools/emulator/skins/WXGA800/arrow_right.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/arrow_up.png b/tools/emulator/skins/WXGA800/arrow_up.png
similarity index 100%
copy from tools/emulator/skins/WXGA/arrow_up.png
copy to tools/emulator/skins/WXGA800/arrow_up.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/background_land.png b/tools/emulator/skins/WXGA800/background_land.png
similarity index 100%
rename from tools/emulator/skins/WXGA/background_land.png
rename to tools/emulator/skins/WXGA800/background_land.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/background_port.png b/tools/emulator/skins/WXGA800/background_port.png
similarity index 100%
rename from tools/emulator/skins/WXGA/background_port.png
rename to tools/emulator/skins/WXGA800/background_port.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/button.png b/tools/emulator/skins/WXGA800/button.png
similarity index 100%
copy from tools/emulator/skins/WXGA/button.png
copy to tools/emulator/skins/WXGA800/button.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/controls.png b/tools/emulator/skins/WXGA800/controls.png
similarity index 100%
copy from tools/emulator/skins/WXGA/controls.png
copy to tools/emulator/skins/WXGA800/controls.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/hardware.ini b/tools/emulator/skins/WXGA800/hardware.ini
similarity index 84%
rename from tools/emulator/skins/WXGA/hardware.ini
rename to tools/emulator/skins/WXGA800/hardware.ini
index c777f9e..81eac11 100755
--- a/tools/emulator/skins/WXGA/hardware.ini
+++ b/tools/emulator/skins/WXGA800/hardware.ini
@@ -1,6 +1,6 @@
 # skin-specific hardware values
 hw.lcd.density=160
 vm.heapSize=48
-hw.ramSize=512
+hw.ramSize=1024
 hw.keyboard.lid=no
 
diff --git a/tools/emulator/skins/WXGA/key.png b/tools/emulator/skins/WXGA800/key.png
similarity index 100%
copy from tools/emulator/skins/WXGA/key.png
copy to tools/emulator/skins/WXGA800/key.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/keyboard.png b/tools/emulator/skins/WXGA800/keyboard.png
similarity index 100%
copy from tools/emulator/skins/WXGA/keyboard.png
copy to tools/emulator/skins/WXGA800/keyboard.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/layout b/tools/emulator/skins/WXGA800/layout
similarity index 100%
rename from tools/emulator/skins/WXGA/layout
rename to tools/emulator/skins/WXGA800/layout
diff --git a/tools/emulator/skins/WXGA/select.png b/tools/emulator/skins/WXGA800/select.png
similarity index 100%
copy from tools/emulator/skins/WXGA/select.png
copy to tools/emulator/skins/WXGA800/select.png
Binary files differ
diff --git a/tools/emulator/skins/WXGA/spacebar.png b/tools/emulator/skins/WXGA800/spacebar.png
similarity index 100%
copy from tools/emulator/skins/WXGA/spacebar.png
copy to tools/emulator/skins/WXGA800/spacebar.png
Binary files differ
diff --git a/tools/emulator/system/camera/Android.mk b/tools/emulator/system/camera/Android.mk
old mode 100644
new mode 100755
index e6d106d..2e5c19c
--- a/tools/emulator/system/camera/Android.mk
+++ b/tools/emulator/system/camera/Android.mk
@@ -28,16 +28,30 @@
     libcamera_client \
     libui \
 
+# JPEG conversion libraries and includes.
+LOCAL_SHARED_LIBRARIES += \
+	libjpeg \
+	libskia \
+	libandroid_runtime \
+
+LOCAL_C_INCLUDES += external/jpeg \
+					external/skia/include/core/ \
+					frameworks/base/core/jni/android/graphics
+
 LOCAL_SRC_FILES := \
-    emulated_camera_hal.cpp \
-    emulated_camera_factory.cpp \
-    emulated_camera.cpp \
-    emulated_camera_device.cpp \
-    emulated_fake_camera.cpp \
-    emulated_fake_camera_device.cpp \
-    converters.cpp \
-    preview_window.cpp \
-    callback_notifier.cpp
+	EmulatedCameraHal.cpp \
+    EmulatedCameraFactory.cpp \
+    EmulatedCamera.cpp \
+	EmulatedCameraDevice.cpp \
+	EmulatedQemuCamera.cpp \
+	EmulatedQemuCameraDevice.cpp \
+	EmulatedFakeCamera.cpp \
+	EmulatedFakeCameraDevice.cpp \
+	Converters.cpp \
+	PreviewWindow.cpp \
+	CallbackNotifier.cpp \
+	QemuClient.cpp \
+	JpegCompressor.cpp
 
 ifeq ($(TARGET_PRODUCT),vbox_x86)
 LOCAL_MODULE := camera.vbox_x86
diff --git a/tools/emulator/system/camera/CallbackNotifier.cpp b/tools/emulator/system/camera/CallbackNotifier.cpp
new file mode 100755
index 0000000..a877b40
--- /dev/null
+++ b/tools/emulator/system/camera/CallbackNotifier.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Contains implementation of a class CallbackNotifier that manages callbacks set
+ * via set_callbacks, enable_msg_type, and disable_msg_type camera HAL API.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera_CallbackNotifier"
+#include <cutils/log.h>
+#include <media/stagefright/MetadataBufferType.h>
+#include "EmulatedCameraDevice.h"
+#include "CallbackNotifier.h"
+#include "JpegCompressor.h"
+
+namespace android {
+
+/* String representation of camera messages. */
+static const char* lCameraMessages[] =
+{
+    "CAMERA_MSG_ERROR",
+    "CAMERA_MSG_SHUTTER",
+    "CAMERA_MSG_FOCUS",
+    "CAMERA_MSG_ZOOM",
+    "CAMERA_MSG_PREVIEW_FRAME",
+    "CAMERA_MSG_VIDEO_FRAME",
+    "CAMERA_MSG_POSTVIEW_FRAME",
+    "CAMERA_MSG_RAW_IMAGE",
+    "CAMERA_MSG_COMPRESSED_IMAGE",
+    "CAMERA_MSG_RAW_IMAGE_NOTIFY",
+    "CAMERA_MSG_PREVIEW_METADATA"
+};
+static const int lCameraMessagesNum = sizeof(lCameraMessages) / sizeof(char*);
+
+/* Builds an array of strings for the given set of messages.
+ * Param:
+ *  msg - Messages to get strings for,
+ *  strings - Array where to save strings
+ *  max - Maximum number of entries in the array.
+ * Return:
+ *  Number of strings saved into the 'strings' array.
+ */
+static int GetMessageStrings(uint32_t msg, const char** strings, int max)
+{
+    int index = 0;
+    int out = 0;
+    while (msg != 0 && out < max && index < lCameraMessagesNum) {
+        while ((msg & 0x1) == 0 && index < lCameraMessagesNum) {
+            msg >>= 1;
+            index++;
+        }
+        if ((msg & 0x1) != 0 && index < lCameraMessagesNum) {
+            strings[out] = lCameraMessages[index];
+            out++;
+            msg >>= 1;
+            index++;
+        }
+    }
+
+    return out;
+}
+
+/* Logs messages, enabled by the mask. */
+static void PrintMessages(uint32_t msg)
+{
+    const char* strs[lCameraMessagesNum];
+    const int translated = GetMessageStrings(msg, strs, lCameraMessagesNum);
+    for (int n = 0; n < translated; n++) {
+        LOGV("    %s", strs[n]);
+    }
+}
+
+CallbackNotifier::CallbackNotifier()
+    : mNotifyCB(NULL),
+      mDataCB(NULL),
+      mDataCBTimestamp(NULL),
+      mGetMemoryCB(NULL),
+      mCBOpaque(NULL),
+      mLastFrameTimestamp(0),
+      mFrameRefreshFreq(0),
+      mMessageEnabler(0),
+      mJpegQuality(90),
+      mVideoRecEnabled(false),
+      mTakingPicture(false)
+{
+}
+
+CallbackNotifier::~CallbackNotifier()
+{
+}
+
+/****************************************************************************
+ * Camera API
+ ***************************************************************************/
+
+void CallbackNotifier::setCallbacks(camera_notify_callback notify_cb,
+                                    camera_data_callback data_cb,
+                                    camera_data_timestamp_callback data_cb_timestamp,
+                                    camera_request_memory get_memory,
+                                    void* user)
+{
+    LOGV("%s: %p, %p, %p, %p (%p)",
+         __FUNCTION__, notify_cb, data_cb, data_cb_timestamp, get_memory, user);
+
+    Mutex::Autolock locker(&mObjectLock);
+    mNotifyCB = notify_cb;
+    mDataCB = data_cb;
+    mDataCBTimestamp = data_cb_timestamp;
+    mGetMemoryCB = get_memory;
+    mCBOpaque = user;
+}
+
+void CallbackNotifier::enableMessage(uint msg_type)
+{
+    LOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type);
+    PrintMessages(msg_type);
+
+    Mutex::Autolock locker(&mObjectLock);
+    mMessageEnabler |= msg_type;
+    LOGV("**** Currently enabled messages:");
+    PrintMessages(mMessageEnabler);
+}
+
+void CallbackNotifier::disableMessage(uint msg_type)
+{
+    LOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type);
+    PrintMessages(msg_type);
+
+    Mutex::Autolock locker(&mObjectLock);
+    mMessageEnabler &= ~msg_type;
+    LOGV("**** Currently enabled messages:");
+    PrintMessages(mMessageEnabler);
+}
+
+status_t CallbackNotifier::enableVideoRecording(int fps)
+{
+    LOGV("%s: FPS = %d", __FUNCTION__, fps);
+
+    Mutex::Autolock locker(&mObjectLock);
+    mVideoRecEnabled = true;
+    mLastFrameTimestamp = 0;
+    mFrameRefreshFreq = 1000000000LL / fps;
+
+    return NO_ERROR;
+}
+
+void CallbackNotifier::disableVideoRecording()
+{
+    LOGV("%s:", __FUNCTION__);
+
+    Mutex::Autolock locker(&mObjectLock);
+    mVideoRecEnabled = false;
+    mLastFrameTimestamp = 0;
+    mFrameRefreshFreq = 0;
+}
+
+void CallbackNotifier::releaseRecordingFrame(const void* opaque)
+{
+    /* We don't really have anything to release here, since we report video
+     * frames by copying them directly to the camera memory. */
+}
+
+status_t CallbackNotifier::storeMetaDataInBuffers(bool enable)
+{
+    /* Return INVALID_OPERATION means HAL does not support metadata. So HAL will
+     * return actual frame data with CAMERA_MSG_VIDEO_FRRAME. Return
+     * INVALID_OPERATION to mean metadata is not supported. */
+    return INVALID_OPERATION;
+}
+
+/****************************************************************************
+ * Public API
+ ***************************************************************************/
+
+void CallbackNotifier::cleanupCBNotifier()
+{
+    Mutex::Autolock locker(&mObjectLock);
+    mMessageEnabler = 0;
+    mNotifyCB = NULL;
+    mDataCB = NULL;
+    mDataCBTimestamp = NULL;
+    mGetMemoryCB = NULL;
+    mCBOpaque = NULL;
+    mLastFrameTimestamp = 0;
+    mFrameRefreshFreq = 0;
+    mJpegQuality = 90;
+    mVideoRecEnabled = false;
+    mTakingPicture = false;
+}
+
+void CallbackNotifier::onNextFrameAvailable(const void* frame,
+                                            nsecs_t timestamp,
+                                            EmulatedCameraDevice* camera_dev)
+{
+    if (isMessageEnabled(CAMERA_MSG_VIDEO_FRAME) && isVideoRecordingEnabled() &&
+            isNewVideoFrameTime(timestamp)) {
+        camera_memory_t* cam_buff =
+            mGetMemoryCB(-1, camera_dev->getFrameBufferSize(), 1, NULL);
+        if (NULL != cam_buff && NULL != cam_buff->data) {
+            memcpy(cam_buff->data, frame, camera_dev->getFrameBufferSize());
+            mDataCBTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME,
+                               cam_buff, 0, mCBOpaque);
+        } else {
+            LOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
+        }
+    }
+
+    if (mTakingPicture) {
+        /* This happens just once. */
+        mTakingPicture = false;
+        /* The sequence of callbacks during picture taking is:
+         *  - CAMERA_MSG_SHUTTER
+         *  - CAMERA_MSG_RAW_IMAGE_NOTIFY
+         *  - CAMERA_MSG_COMPRESSED_IMAGE
+         */
+        if (isMessageEnabled(CAMERA_MSG_SHUTTER)) {
+            mNotifyCB(CAMERA_MSG_SHUTTER, 0, 0, mCBOpaque);
+        }
+        if (isMessageEnabled(CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
+            mNotifyCB(CAMERA_MSG_RAW_IMAGE_NOTIFY, 0, 0, mCBOpaque);
+        }
+        if (isMessageEnabled(CAMERA_MSG_COMPRESSED_IMAGE)) {
+            /* Compress the frame to JPEG. Note that when taking pictures, we
+             * have requested camera device to provide us with NV21 frames. */
+            NV21JpegCompressor compressor;
+            status_t res =
+                compressor.compressRawImage(frame, camera_dev->getFrameWidth(),
+                                            camera_dev->getFrameHeight(),
+                                            mJpegQuality);
+            if (res == NO_ERROR) {
+                camera_memory_t* jpeg_buff =
+                    mGetMemoryCB(-1, compressor.getCompressedSize(), 1, NULL);
+                if (NULL != jpeg_buff && NULL != jpeg_buff->data) {
+                    compressor.getCompressedImage(jpeg_buff->data);
+                    mDataCB(CAMERA_MSG_COMPRESSED_IMAGE, jpeg_buff, 0, NULL, mCBOpaque);
+                    jpeg_buff->release(jpeg_buff);
+                } else {
+                    LOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
+                }
+            } else {
+                LOGE("%s: Compression failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
+            }
+        }
+    }
+}
+
+void CallbackNotifier::onCameraDeviceError(int err)
+{
+    if (isMessageEnabled(CAMERA_MSG_ERROR) && mNotifyCB != NULL) {
+        mNotifyCB(CAMERA_MSG_ERROR, err, 0, mCBOpaque);
+    }
+}
+
+/****************************************************************************
+ * Private API
+ ***************************************************************************/
+
+bool CallbackNotifier::isNewVideoFrameTime(nsecs_t timestamp)
+{
+    Mutex::Autolock locker(&mObjectLock);
+    if ((timestamp - mLastFrameTimestamp) >= mFrameRefreshFreq) {
+        mLastFrameTimestamp = timestamp;
+        return true;
+    }
+    return false;
+}
+
+}; /* namespace android */
diff --git a/tools/emulator/system/camera/callback_notifier.h b/tools/emulator/system/camera/CallbackNotifier.h
old mode 100644
new mode 100755
similarity index 68%
rename from tools/emulator/system/camera/callback_notifier.h
rename to tools/emulator/system/camera/CallbackNotifier.h
index eb6598d..63301d2
--- a/tools/emulator/system/camera/callback_notifier.h
+++ b/tools/emulator/system/camera/CallbackNotifier.h
@@ -31,6 +31,9 @@
  *
  * Objects of this class are contained in EmulatedCamera objects, and handle
  * relevant camera API callbacks.
+ * Locking considerations. Apparently, it's not allowed to call callbacks
+ * registered in this class, while holding a lock: recursion is quite possible,
+ * which will cause a deadlock.
  */
 class CallbackNotifier {
 public:
@@ -49,7 +52,7 @@
      * This method is called by the containing emulated camera object when it is
      * handing the camera_device_ops_t::set_callbacks callback.
      */
-    void SetCallbacks(camera_notify_callback notify_cb,
+    void setCallbacks(camera_notify_callback notify_cb,
                       camera_data_callback data_cb,
                       camera_data_timestamp_callback data_cb_timestamp,
                       camera_request_memory get_memory,
@@ -59,21 +62,13 @@
      * This method is called by the containing emulated camera object when it is
      * handing the camera_device_ops_t::enable_msg_type callback.
      */
-    void EnableMessage(uint msg_type);
+    void enableMessage(uint msg_type);
 
     /* Actual handler for camera_device_ops_t::disable_msg_type callback.
      * This method is called by the containing emulated camera object when it is
      * handing the camera_device_ops_t::disable_msg_type callback.
      */
-    void DisableMessage(uint msg_type);
-
-    /* Actual handler for camera_device_ops_t::msg_type_enabled callback.
-     * This method is called by the containing emulated camera object when it is
-     * handing the camera_device_ops_t::msg_type_enabled callback.
-     * Return:
-     *  0 if message is disabled, or non-zero value, if message is enabled.
-     */
-    int IsMessageEnabled(uint msg_type);
+    void disableMessage(uint msg_type);
 
     /* Actual handler for camera_device_ops_t::store_meta_data_in_buffers
      * callback. This method is called by the containing emulated camera object
@@ -82,39 +77,60 @@
      * Return:
      *  NO_ERROR on success, or an appropriate error status.
      */
-    status_t StoreMetaDataInBuffers(bool enable);
+    status_t storeMetaDataInBuffers(bool enable);
 
     /* Enables video recording.
      * This method is called by the containing emulated camera object when it is
      * handing the camera_device_ops_t::start_recording callback.
      * Param:
      *  fps - Video frame frequency. This parameter determins when a frame
-     *      received via OnNextFrameAvailable call will be pushed through the
+     *      received via onNextFrameAvailable call will be pushed through the
      *      callback.
      * Return:
      *  NO_ERROR on success, or an appropriate error status.
      */
-    status_t EnableVideoRecording(int fps);
+    status_t enableVideoRecording(int fps);
 
     /* Disables video recording.
      * This method is called by the containing emulated camera object when it is
      * handing the camera_device_ops_t::stop_recording callback.
      */
-    void DisableVideoRecording();
-
-    /* Checks id video recording is enabled.
-     * This method is called by the containing emulated camera object when it is
-     * handing the camera_device_ops_t::recording_enabled callback.
-     * Return:
-     *  true if video recording is enabled, or false if it is disabled.
-     */
-    bool IsVideoRecordingEnabled();
+    void disableVideoRecording();
 
     /* Releases video frame, sent to the framework.
      * This method is called by the containing emulated camera object when it is
      * handing the camera_device_ops_t::release_recording_frame callback.
      */
-    void ReleaseRecordingFrame(const void* opaque);
+    void releaseRecordingFrame(const void* opaque);
+
+    /* Actual handler for camera_device_ops_t::msg_type_enabled callback.
+     * This method is called by the containing emulated camera object when it is
+     * handing the camera_device_ops_t::msg_type_enabled callback.
+     * Note: this method doesn't grab a lock while checking message status, since
+     * upon exit the status would be undefined anyway. So, grab a lock before
+     * calling this method if you care about persisting a defined message status.
+     * Return:
+     *  0 if message is disabled, or non-zero value, if message is enabled.
+     */
+    inline int isMessageEnabled(uint msg_type)
+    {
+        return mMessageEnabler & msg_type;
+    }
+
+    /* Checks id video recording is enabled.
+     * This method is called by the containing emulated camera object when it is
+     * handing the camera_device_ops_t::recording_enabled callback.
+     * Note: this method doesn't grab a lock while checking video recordin status,
+     * since upon exit the status would be undefined anyway. So, grab a lock
+     * before calling this method if you care about persisting of a defined video
+     * recording status.
+     * Return:
+     *  true if video recording is enabled, or false if it is disabled.
+     */
+    inline bool isVideoRecordingEnabled()
+    {
+        return mVideoRecEnabled;
+    }
 
     /****************************************************************************
      * Public API
@@ -122,7 +138,7 @@
 
 public:
     /* Resets the callback notifier. */
-    void Cleanup();
+    void cleanupCBNotifier();
 
     /* Next frame is available in the camera device.
      * This is a notification callback that is invoked by the camera device when
@@ -139,18 +155,41 @@
      * timestamp - Frame's timestamp.
      * camera_dev - Camera device instance that delivered the frame.
      */
-    void OnNextFrameAvailable(const void* frame,
+    void onNextFrameAvailable(const void* frame,
                               nsecs_t timestamp,
                               EmulatedCameraDevice* camera_dev);
 
+    /* Entry point for notifications that occur in camera device.
+     * Param:
+     *  err - CAMERA_ERROR_XXX error code.
+     */
+    void onCameraDeviceError(int err);
+
+    /* Sets, or resets taking picture state.
+     * This state control whether or not to notify the framework about compressed
+     * image, shutter, and other picture related events.
+     */
+    void setTakingPicture(bool taking)
+    {
+        mTakingPicture = taking;
+    }
+
+    /* Sets JPEG quality used to compress frame during picture taking. */
+    void setJpegQuality(int jpeg_quality)
+    {
+        mJpegQuality = jpeg_quality;
+    }
+
     /****************************************************************************
      * Private API
      ***************************************************************************/
 
 protected:
     /* Checks if it's time to push new video frame.
-     * Note that this method must be called while object is locked. */
-    bool IsTimeForNewVideoFrame();
+     * Note that this method must be called while object is locked.
+     * Param:
+     *  timestamp - Timestamp for the new frame. */
+    bool isNewVideoFrameTime(nsecs_t timestamp);
 
     /****************************************************************************
      * Data members
@@ -158,33 +197,35 @@
 
 protected:
     /* Locks this instance for data change. */
-    Mutex                           object_lock_;
+    Mutex                           mObjectLock;
 
     /*
      * Callbacks, registered in set_callbacks.
      */
 
-    camera_notify_callback          notify_cb_;
-    camera_data_callback            data_cb_;
-    camera_data_timestamp_callback  data_cb_timestamp_;
-    camera_request_memory           get_memory_;
-    void*                           cb_opaque_;
+    camera_notify_callback          mNotifyCB;
+    camera_data_callback            mDataCB;
+    camera_data_timestamp_callback  mDataCBTimestamp;
+    camera_request_memory           mGetMemoryCB;
+    void*                           mCBOpaque;
 
-    /* Timestamp (abs. microseconds) when last frame has been delivered to the
-     * framework. */
-    uint64_t                        last_frame_;
+    /* Timestamp when last frame has been delivered to the framework. */
+    nsecs_t                         mLastFrameTimestamp;
 
-    /* Video frequency in microseconds. */
-    uint32_t                        frame_after_;
+    /* Video frequency in nanosec. */
+    nsecs_t                         mFrameRefreshFreq;
 
     /* Message enabler. */
-    uint32_t                        message_enabler_;
+    uint32_t                        mMessageEnabler;
+
+    /* JPEG quality used to compress frame during picture taking. */
+    int                             mJpegQuality;
 
     /* Video recording status. */
-    bool                            video_recording_enabled_;
+    bool                            mVideoRecEnabled;
 
-    /* Status of the metadata buffering. */
-    bool                            store_meta_data_in_buffers_;
+    /* Picture taking status. */
+    bool                            mTakingPicture;
 };
 
 }; /* namespace android */
diff --git a/tools/emulator/system/camera/Converters.cpp b/tools/emulator/system/camera/Converters.cpp
new file mode 100755
index 0000000..f63f67f
--- /dev/null
+++ b/tools/emulator/system/camera/Converters.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Contains implemenation of framebuffer conversion routines.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera_Converter"
+#include <cutils/log.h>
+#include "Converters.h"
+
+namespace android {
+
+static void _YUV420SToRGB565(const uint8_t* Y,
+                             const uint8_t* U,
+                             const uint8_t* V,
+                             int dUV,
+                             uint16_t* rgb,
+                             int width,
+                             int height)
+{
+    const uint8_t* U_pos = U;
+    const uint8_t* V_pos = V;
+
+    for (int y = 0; y < height; y++) {
+        for (int x = 0; x < width; x += 2, U += dUV, V += dUV) {
+            const uint8_t nU = *U;
+            const uint8_t nV = *V;
+            *rgb = YUVToRGB565(*Y, nU, nV);
+            Y++; rgb++;
+            *rgb = YUVToRGB565(*Y, nU, nV);
+            Y++; rgb++;
+        }
+        if (y & 0x1) {
+            U_pos = U;
+            V_pos = V;
+        } else {
+            U = U_pos;
+            V = V_pos;
+        }
+    }
+}
+
+static void _YUV420SToRGB32(const uint8_t* Y,
+                            const uint8_t* U,
+                            const uint8_t* V,
+                            int dUV,
+                            uint32_t* rgb,
+                            int width,
+                            int height)
+{
+    const uint8_t* U_pos = U;
+    const uint8_t* V_pos = V;
+
+    for (int y = 0; y < height; y++) {
+        for (int x = 0; x < width; x += 2, U += dUV, V += dUV) {
+            const uint8_t nU = *U;
+            const uint8_t nV = *V;
+            *rgb = YUVToRGB32(*Y, nU, nV);
+            Y++; rgb++;
+            *rgb = YUVToRGB32(*Y, nU, nV);
+            Y++; rgb++;
+        }
+        if (y & 0x1) {
+            U_pos = U;
+            V_pos = V;
+        } else {
+            U = U_pos;
+            V = V_pos;
+        }
+    }
+}
+
+void YV12ToRGB565(const void* yv12, void* rgb, int width, int height)
+{
+    const int pix_total = width * height;
+    const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
+    const uint8_t* U = Y + pix_total;
+    const uint8_t* V = U + pix_total / 4;
+    _YUV420SToRGB565(Y, U, V, 1, reinterpret_cast<uint16_t*>(rgb), width, height);
+}
+
+void YV12ToRGB32(const void* yv12, void* rgb, int width, int height)
+{
+    const int pix_total = width * height;
+    const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
+    const uint8_t* V = Y + pix_total;
+    const uint8_t* U = V + pix_total / 4;
+    _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height);
+}
+
+void YU12ToRGB32(const void* yu12, void* rgb, int width, int height)
+{
+    const int pix_total = width * height;
+    const uint8_t* Y = reinterpret_cast<const uint8_t*>(yu12);
+    const uint8_t* U = Y + pix_total;
+    const uint8_t* V = U + pix_total / 4;
+    _YUV420SToRGB32(Y, U, V, 1, reinterpret_cast<uint32_t*>(rgb), width, height);
+}
+
+/* Common converter for YUV 4:2:0 interleaved to RGB565.
+ * y, u, and v point to Y,U, and V panes, where U and V values are interleaved.
+ */
+static void _NVXXToRGB565(const uint8_t* Y,
+                          const uint8_t* U,
+                          const uint8_t* V,
+                          uint16_t* rgb,
+                          int width,
+                          int height)
+{
+    _YUV420SToRGB565(Y, U, V, 2, rgb, width, height);
+}
+
+/* Common converter for YUV 4:2:0 interleaved to RGB32.
+ * y, u, and v point to Y,U, and V panes, where U and V values are interleaved.
+ */
+static void _NVXXToRGB32(const uint8_t* Y,
+                         const uint8_t* U,
+                         const uint8_t* V,
+                         uint32_t* rgb,
+                         int width,
+                         int height)
+{
+    _YUV420SToRGB32(Y, U, V, 2, rgb, width, height);
+}
+
+void NV12ToRGB565(const void* nv12, void* rgb, int width, int height)
+{
+    const int pix_total = width * height;
+    const uint8_t* y = reinterpret_cast<const uint8_t*>(nv12);
+    _NVXXToRGB565(y, y + pix_total, y + pix_total + 1,
+                  reinterpret_cast<uint16_t*>(rgb), width, height);
+}
+
+void NV12ToRGB32(const void* nv12, void* rgb, int width, int height)
+{
+    const int pix_total = width * height;
+    const uint8_t* y = reinterpret_cast<const uint8_t*>(nv12);
+    _NVXXToRGB32(y, y + pix_total, y + pix_total + 1,
+                 reinterpret_cast<uint32_t*>(rgb), width, height);
+}
+
+void NV21ToRGB565(const void* nv21, void* rgb, int width, int height)
+{
+    const int pix_total = width * height;
+    const uint8_t* y = reinterpret_cast<const uint8_t*>(nv21);
+    _NVXXToRGB565(y, y + pix_total + 1, y + pix_total,
+                  reinterpret_cast<uint16_t*>(rgb), width, height);
+}
+
+void NV21ToRGB32(const void* nv21, void* rgb, int width, int height)
+{
+    const int pix_total = width * height;
+    const uint8_t* y = reinterpret_cast<const uint8_t*>(nv21);
+    _NVXXToRGB32(y, y + pix_total + 1, y + pix_total,
+                 reinterpret_cast<uint32_t*>(rgb), width, height);
+}
+
+}; /* namespace android */
diff --git a/tools/emulator/system/camera/Converters.h b/tools/emulator/system/camera/Converters.h
new file mode 100755
index 0000000..13e2a85
--- /dev/null
+++ b/tools/emulator/system/camera/Converters.h
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HW_EMULATOR_CAMERA_CONVERTERS_H
+#define HW_EMULATOR_CAMERA_CONVERTERS_H
+
+#include <endian.h>
+
+#ifndef __BYTE_ORDER
+#error "could not determine byte order"
+#endif
+
+/*
+ * Contains declaration of framebuffer conversion routines.
+ *
+ * NOTE: RGB and big/little endian considerations. Wherewer in this code RGB
+ * pixels are represented as WORD, or DWORD, the color order inside the
+ * WORD / DWORD matches the one that would occur if that WORD / DWORD would have
+ * been read from the typecasted framebuffer:
+ *
+ *      const uint32_t rgb = *reinterpret_cast<const uint32_t*>(framebuffer);
+ *
+ * So, if this code runs on the little endian CPU, red color in 'rgb' would be
+ * masked as 0x000000ff, and blue color would be masked as 0x00ff0000, while if
+ * the code runs on a big endian CPU, the red color in 'rgb' would be masked as
+ * 0xff000000, and blue color would be masked as 0x0000ff00,
+ */
+
+namespace android {
+
+/*
+ * RGB565 color masks
+ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static const uint16_t kRed5     = 0x001f;
+static const uint16_t kGreen6   = 0x07e0;
+static const uint16_t kBlue5    = 0xf800;
+#else   // __BYTE_ORDER
+static const uint16_t kRed5     = 0xf800;
+static const uint16_t kGreen6   = 0x07e0;
+static const uint16_t kBlue5    = 0x001f;
+#endif  // __BYTE_ORDER
+static const uint32_t kBlack16  = 0x0000;
+static const uint32_t kWhite16  = kRed5 | kGreen6 | kBlue5;
+
+/*
+ * RGB32 color masks
+ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static const uint32_t kRed8     = 0x000000ff;
+static const uint32_t kGreen8   = 0x0000ff00;
+static const uint32_t kBlue8    = 0x00ff0000;
+#else   // __BYTE_ORDER
+static const uint32_t kRed8     = 0x00ff0000;
+static const uint32_t kGreen8   = 0x0000ff00;
+static const uint32_t kBlue8    = 0x000000ff;
+#endif  // __BYTE_ORDER
+static const uint32_t kBlack32  = 0x00000000;
+static const uint32_t kWhite32  = kRed8 | kGreen8 | kBlue8;
+
+/*
+ * Extracting, and saving color bytes from / to WORD / DWORD RGB.
+ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+/* Extract red, green, and blue bytes from RGB565 word. */
+#define R16(rgb)    static_cast<uint8_t>(rgb & kRed5)
+#define G16(rgb)    static_cast<uint8_t>((rgb & kGreen6) >> 5)
+#define B16(rgb)    static_cast<uint8_t>((rgb & kBlue5) >> 11)
+/* Make 8 bits red, green, and blue, extracted from RGB565 word. */
+#define R16_32(rgb) static_cast<uint8_t>(((rgb & kRed5) << 3) | ((rgb & kRed5) >> 2))
+#define G16_32(rgb) static_cast<uint8_t>(((rgb & kGreen6) >> 3) | ((rgb & kGreen6) >> 9))
+#define B16_32(rgb) static_cast<uint8_t>(((rgb & kBlue5) >> 8) | ((rgb & kBlue5) >> 14))
+/* Extract red, green, and blue bytes from RGB32 dword. */
+#define R32(rgb)    static_cast<uint8_t>(rgb & kRed8)
+#define G32(rgb)    static_cast<uint8_t>(((rgb & kGreen8) >> 8) & 0xff)
+#define B32(rgb)    static_cast<uint8_t>(((rgb & kBlue8) >> 16) & 0xff)
+/* Build RGB565 word from red, green, and blue bytes. */
+#define RGB565(r, g, b) static_cast<uint16_t>((((static_cast<uint16_t>(b) << 6) | g) << 5) | r)
+/* Build RGB32 dword from red, green, and blue bytes. */
+#define RGB32(r, g, b) static_cast<uint32_t>((((static_cast<uint32_t>(b) << 8) | g) << 8) | r)
+#else   // __BYTE_ORDER
+/* Extract red, green, and blue bytes from RGB565 word. */
+#define R16(rgb)    static_cast<uint8_t>((rgb & kRed5) >> 11)
+#define G16(rgb)    static_cast<uint8_t>((rgb & kGreen6) >> 5)
+#define B16(rgb)    static_cast<uint8_t>(rgb & kBlue5)
+/* Make 8 bits red, green, and blue, extracted from RGB565 word. */
+#define R16_32(rgb) static_cast<uint8_t>(((rgb & kRed5) >> 8) | ((rgb & kRed5) >> 14))
+#define G16_32(rgb) static_cast<uint8_t>(((rgb & kGreen6) >> 3) | ((rgb & kGreen6) >> 9))
+#define B16_32(rgb) static_cast<uint8_t>(((rgb & kBlue5) << 3) | ((rgb & kBlue5) >> 2))
+/* Extract red, green, and blue bytes from RGB32 dword. */
+#define R32(rgb)    static_cast<uint8_t>((rgb & kRed8) >> 16)
+#define G32(rgb)    static_cast<uint8_t>((rgb & kGreen8) >> 8)
+#define B32(rgb)    static_cast<uint8_t>(rgb & kBlue8)
+/* Build RGB565 word from red, green, and blue bytes. */
+#define RGB565(r, g, b) static_cast<uint16_t>((((static_cast<uint16_t>(r) << 6) | g) << 5) | b)
+/* Build RGB32 dword from red, green, and blue bytes. */
+#define RGB32(r, g, b) static_cast<uint32_t>((((static_cast<uint32_t>(r) << 8) | g) << 8) | b)
+#endif  // __BYTE_ORDER
+
+/* An union that simplifies breaking 32 bit RGB into separate R, G, and B colors.
+ */
+typedef union RGB32_t {
+    uint32_t    color;
+    struct {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+        uint8_t r; uint8_t g; uint8_t b; uint8_t a;
+#else   // __BYTE_ORDER
+        uint8_t a; uint8_t b; uint8_t g; uint8_t r;
+#endif  // __BYTE_ORDER
+    };
+} RGB32_t;
+
+
+/* Clips a value to the unsigned 0-255 range, treating negative values as zero.
+ */
+static __inline__ int
+clamp(int x)
+{
+    if (x > 255) return 255;
+    if (x < 0)   return 0;
+    return x;
+}
+
+/********************************************************************************
+ * Basics of RGB -> YUV conversion
+ *******************************************************************************/
+
+/*
+ * RGB -> YUV conversion macros
+ */
+#define RGB2Y(r, g, b) (uint8_t)(((66 * (r) + 129 * (g) +  25 * (b) + 128) >> 8) +  16)
+#define RGB2U(r, g, b) (uint8_t)(((-38 * (r) - 74 * (g) + 112 * (b) + 128) >> 8) + 128)
+#define RGB2V(r, g, b) (uint8_t)(((112 * (r) - 94 * (g) -  18 * (b) + 128) >> 8) + 128)
+
+/* Converts R8 G8 B8 color to YUV. */
+static __inline__ void
+R8G8B8ToYUV(uint8_t r, uint8_t g, uint8_t b, uint8_t* y, uint8_t* u, uint8_t* v)
+{
+    *y = RGB2Y((int)r, (int)g, (int)b);
+    *u = RGB2U((int)r, (int)g, (int)b);
+    *v = RGB2V((int)r, (int)g, (int)b);
+}
+
+/* Converts RGB565 color to YUV. */
+static __inline__ void
+RGB565ToYUV(uint16_t rgb, uint8_t* y, uint8_t* u, uint8_t* v)
+{
+    R8G8B8ToYUV(R16_32(rgb), G16_32(rgb), B16_32(rgb), y, u, v);
+}
+
+/* Converts RGB32 color to YUV. */
+static __inline__ void
+RGB32ToYUV(uint32_t rgb, uint8_t* y, uint8_t* u, uint8_t* v)
+{
+    RGB32_t rgb_c;
+    rgb_c.color = rgb;
+    R8G8B8ToYUV(rgb_c.r, rgb_c.g, rgb_c.b, y, u, v);
+}
+
+/********************************************************************************
+ * Basics of YUV -> RGB conversion.
+ * Note that due to the fact that guest uses RGB only on preview window, and the
+ * RGB format that is used is RGB565, we can limit YUV -> RGB conversions to
+ * RGB565 only.
+ *******************************************************************************/
+
+/*
+ * YUV -> RGB conversion macros
+ */
+
+/* "Optimized" macros that take specialy prepared Y, U, and V values:
+ *  C = Y - 16
+ *  D = U - 128
+ *  E = V - 128
+ */
+#define YUV2RO(C, D, E) clamp((298 * (C) + 409 * (E) + 128) >> 8)
+#define YUV2GO(C, D, E) clamp((298 * (C) - 100 * (D) - 208 * (E) + 128) >> 8)
+#define YUV2BO(C, D, E) clamp((298 * (C) + 516 * (D) + 128) >> 8)
+
+/*
+ *  Main macros that take the original Y, U, and V values
+ */
+#define YUV2R(y, u, v) clamp((298 * ((y)-16) + 409 * ((v)-128) + 128) >> 8)
+#define YUV2G(y, u, v) clamp((298 * ((y)-16) - 100 * ((u)-128) - 208 * ((v)-128) + 128) >> 8)
+#define YUV2B(y, u, v) clamp((298 * ((y)-16) + 516 * ((u)-128) + 128) >> 8)
+
+
+/* Converts YUV color to RGB565. */
+static __inline__ uint16_t
+YUVToRGB565(int y, int u, int v)
+{
+    /* Calculate C, D, and E values for the optimized macro. */
+    y -= 16; u -= 128; v -= 128;
+    const uint16_t r = (YUV2RO(y,u,v) >> 3) & 0x1f;
+    const uint16_t g = (YUV2GO(y,u,v) >> 2) & 0x3f;
+    const uint16_t b = (YUV2BO(y,u,v) >> 3) & 0x1f;
+    return RGB565(r, g, b);
+}
+
+/* Converts YUV color to RGB32. */
+static __inline__ uint32_t
+YUVToRGB32(int y, int u, int v)
+{
+    /* Calculate C, D, and E values for the optimized macro. */
+    y -= 16; u -= 128; v -= 128;
+    RGB32_t rgb;
+    rgb.r = YUV2RO(y,u,v) & 0xff;
+    rgb.g = YUV2GO(y,u,v) & 0xff;
+    rgb.b = YUV2BO(y,u,v) & 0xff;
+    return rgb.color;
+}
+
+/* YUV pixel descriptor. */
+struct YUVPixel {
+    uint8_t     Y;
+    uint8_t     U;
+    uint8_t     V;
+
+    inline YUVPixel()
+        : Y(0), U(0), V(0)
+    {
+    }
+
+    inline explicit YUVPixel(uint16_t rgb565)
+    {
+        RGB565ToYUV(rgb565, &Y, &U, &V);
+    }
+
+    inline explicit YUVPixel(uint32_t rgb32)
+    {
+        RGB32ToYUV(rgb32, &Y, &U, &V);
+    }
+
+    inline void get(uint8_t* pY, uint8_t* pU, uint8_t* pV) const
+    {
+        *pY = Y; *pU = U; *pV = V;
+    }
+};
+
+/* Converts an YV12 framebuffer to RGB565 framebuffer.
+ * Param:
+ *  yv12 - YV12 framebuffer.
+ *  rgb - RGB565 framebuffer.
+ *  width, height - Dimensions for both framebuffers.
+ */
+void YV12ToRGB565(const void* yv12, void* rgb, int width, int height);
+
+/* Converts an YV12 framebuffer to RGB32 framebuffer.
+ * Param:
+ *  yv12 - YV12 framebuffer.
+ *  rgb - RGB32 framebuffer.
+ *  width, height - Dimensions for both framebuffers.
+ */
+void YV12ToRGB32(const void* yv12, void* rgb, int width, int height);
+
+/* Converts an YU12 framebuffer to RGB32 framebuffer.
+ * Param:
+ *  yu12 - YU12 framebuffer.
+ *  rgb - RGB32 framebuffer.
+ *  width, height - Dimensions for both framebuffers.
+ */
+void YU12ToRGB32(const void* yu12, void* rgb, int width, int height);
+
+/* Converts an NV12 framebuffer to RGB565 framebuffer.
+ * Param:
+ *  nv12 - NV12 framebuffer.
+ *  rgb - RGB565 framebuffer.
+ *  width, height - Dimensions for both framebuffers.
+ */
+void NV12ToRGB565(const void* nv12, void* rgb, int width, int height);
+
+/* Converts an NV12 framebuffer to RGB32 framebuffer.
+ * Param:
+ *  nv12 - NV12 framebuffer.
+ *  rgb - RGB32 framebuffer.
+ *  width, height - Dimensions for both framebuffers.
+ */
+void NV12ToRGB32(const void* nv12, void* rgb, int width, int height);
+
+/* Converts an NV21 framebuffer to RGB565 framebuffer.
+ * Param:
+ *  nv21 - NV21 framebuffer.
+ *  rgb - RGB565 framebuffer.
+ *  width, height - Dimensions for both framebuffers.
+ */
+void NV21ToRGB565(const void* nv21, void* rgb, int width, int height);
+
+/* Converts an NV21 framebuffer to RGB32 framebuffer.
+ * Param:
+ *  nv21 - NV21 framebuffer.
+ *  rgb - RGB32 framebuffer.
+ *  width, height - Dimensions for both framebuffers.
+ */
+void NV21ToRGB32(const void* nv21, void* rgb, int width, int height);
+
+}; /* namespace android */
+
+#endif  /* HW_EMULATOR_CAMERA_CONVERTERS_H */
diff --git a/tools/emulator/system/camera/emulated_camera.cpp b/tools/emulator/system/camera/EmulatedCamera.cpp
old mode 100644
new mode 100755
similarity index 60%
rename from tools/emulator/system/camera/emulated_camera.cpp
rename to tools/emulator/system/camera/EmulatedCamera.cpp
index 8808e87..9cabe75
--- a/tools/emulator/system/camera/emulated_camera.cpp
+++ b/tools/emulator/system/camera/EmulatedCamera.cpp
@@ -27,9 +27,9 @@
 #define LOG_TAG "EmulatedCamera_Camera"
 #include <cutils/log.h>
 #include <ui/Rect.h>
-#include "emulated_camera.h"
-#include "emulated_fake_camera_device.h"
-#include "converters.h"
+#include "EmulatedCamera.h"
+#include "EmulatedFakeCameraDevice.h"
+#include "Converters.h"
 
 /* Defines whether we should trace parameter changes. */
 #define DEBUG_PARAM 1
@@ -42,9 +42,9 @@
  *  current - Current set of camera parameters.
  *  new_par - String representation of new parameters.
  */
-static void _PrintParamDiff(const CameraParameters& current, const char* new_par);
+static void PrintParamDiff(const CameraParameters& current, const char* new_par);
 #else
-#define _PrintParamDiff(current, new_par)   (void(0))
+#define PrintParamDiff(current, new_par)   (void(0))
 #endif  /* DEBUG_PARAM */
 
 /* A helper routine that adds a value to the camera parameter.
@@ -56,12 +56,12 @@
  *  a failure. If non-NULL string is returned, the caller is responsible for
  *  freeing it with 'free'.
  */
-static char* _AddValue(const char* param, const char* val);
+static char* AddValue(const char* param, const char* val);
 
 EmulatedCamera::EmulatedCamera(int cameraId, struct hw_module_t* module)
-        : preview_window_(),
-          callback_notifier_(),
-          camera_id_(cameraId)
+        : mPreviewWindow(),
+          mCallbackNotifier(),
+          mCameraID(cameraId)
 {
     /*
      * Initialize camera_device descriptor for this object.
@@ -74,7 +74,7 @@
     common.close = EmulatedCamera::close;
 
     /* camera_device fields. */
-    ops = &device_ops_;
+    ops = &mDeviceOps;
     priv = this;
 }
 
@@ -88,71 +88,88 @@
 
 status_t EmulatedCamera::Initialize()
 {
-    LOGV("%s", __FUNCTION__);
-
-    /* Emulated camera is facing back. */
-    parameters_.set(EmulatedCamera::FACING_KEY, EmulatedCamera::FACING_BACK);
-    /* Portrait orientation. */
-    parameters_.set(EmulatedCamera::ORIENTATION_KEY, 90);
-
     /*
      * Fake required parameters.
      */
 
-    /* Only RGBX are supported by the framework for preview window in the emulator! */
-    parameters_.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, CameraParameters::PIXEL_FORMAT_RGB565);
-    parameters_.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, "60,50,25,15,10");
-    parameters_.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(10,60)");
-    parameters_.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "10,60");
-    parameters_.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, "320x240,0x0");
-    parameters_.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, "6");
-    parameters_.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, "-6");
-    parameters_.set(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, "0.5");
-    parameters_.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, "512");
-    parameters_.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, "384");
-    parameters_.set(CameraParameters::KEY_JPEG_QUALITY, "90");
-    parameters_.set(CameraParameters::KEY_FOCAL_LENGTH, "4.31");
-    parameters_.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "54.8");
-    parameters_.set(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, "42.5");
-    parameters_.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, "90");
-    parameters_.setPreviewFormat(CameraParameters::PIXEL_FORMAT_RGB565);
+    mParameters.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, "320x240,0x0");
+    mParameters.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, "6");
+    mParameters.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, "-6");
+    mParameters.set(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, "0.5");
+    mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, "512");
+    mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, "384");
+    mParameters.set(CameraParameters::KEY_JPEG_QUALITY, "90");
+    mParameters.set(CameraParameters::KEY_FOCAL_LENGTH, "4.31");
+    mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "54.8");
+    mParameters.set(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, "42.5");
+    mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, "90");
+
+    /* Preview format settings used here are related to panoramic view only. It's
+     * not related to the preview window that works only with RGB frames, which
+     * is explicitly stated when set_buffers_geometry is called on the preview
+     * window object. */
+    mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS,
+                    CameraParameters::PIXEL_FORMAT_YUV420SP);
+    mParameters.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP);
+
+    /* We don't relay on the actual frame rates supported by the camera device,
+     * since we will emulate them through timeouts in the emulated camera device
+     * worker thread. */
+    mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES,
+                    "30,24,20,15,10,5");
+    mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(5,30)");
+    mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "5,30");
+    mParameters.setPreviewFrameRate(24);
+
+    /* Only PIXEL_FORMAT_YUV420P is accepted by camera framework in emulator! */
+    mParameters.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
+                    CameraParameters::PIXEL_FORMAT_YUV420P);
+    mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
+                    CameraParameters::PIXEL_FORMAT_JPEG);
+    mParameters.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
 
     /*
      * Not supported features
      */
 
-    parameters_.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, CameraParameters::FOCUS_MODE_FIXED);
-    parameters_.set(CameraParameters::KEY_FOCUS_MODE, CameraParameters::FOCUS_MODE_FIXED);
+    mParameters.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, CameraParameters::FOCUS_MODE_FIXED);
+    mParameters.set(CameraParameters::KEY_FOCUS_MODE, CameraParameters::FOCUS_MODE_FIXED);
 
     return NO_ERROR;
 }
 
-void EmulatedCamera::OnNextFrameAvailable(const void* frame,
+void EmulatedCamera::onNextFrameAvailable(const void* frame,
                                           nsecs_t timestamp,
                                           EmulatedCameraDevice* camera_dev)
 {
     /* Notify the preview window first. */
-    preview_window_.OnNextFrameAvailable(frame, timestamp, camera_dev);
+    mPreviewWindow.onNextFrameAvailable(frame, timestamp, camera_dev);
 
     /* Notify callback notifier next. */
-    callback_notifier_.OnNextFrameAvailable(frame, timestamp, camera_dev);
+    mCallbackNotifier.onNextFrameAvailable(frame, timestamp, camera_dev);
+}
+
+void EmulatedCamera::onCameraDeviceError(int err)
+{
+    /* Errors are reported through the callback notifier */
+    mCallbackNotifier.onCameraDeviceError(err);
 }
 
 /****************************************************************************
  * Camera API implementation.
  ***************************************************************************/
 
-status_t EmulatedCamera::Connect(hw_device_t** device)
+status_t EmulatedCamera::connectCamera(hw_device_t** device)
 {
     LOGV("%s", __FUNCTION__);
 
     status_t res = EINVAL;
-    EmulatedCameraDevice* const camera_dev = GetCameraDevice();
+    EmulatedCameraDevice* const camera_dev = getCameraDevice();
     LOGE_IF(camera_dev == NULL, "%s: No camera device instance.", __FUNCTION__);
 
     if (camera_dev != NULL) {
         /* Connect to the camera device. */
-        res = GetCameraDevice()->Connect();
+        res = getCameraDevice()->connectDevice();
         if (res == NO_ERROR) {
             *device = &common;
         }
@@ -161,20 +178,20 @@
     return -res;
 }
 
-status_t EmulatedCamera::Close()
+status_t EmulatedCamera::closeCamera()
 {
     LOGV("%s", __FUNCTION__);
 
-    return Cleanup();
+    return cleanupCamera();
 }
 
-status_t EmulatedCamera::GetCameraInfo(struct camera_info* info)
+status_t EmulatedCamera::getCameraInfo(struct camera_info* info)
 {
     LOGV("%s", __FUNCTION__);
 
     const char* valstr = NULL;
 
-    valstr = parameters_.get(EmulatedCamera::FACING_KEY);
+    valstr = mParameters.get(EmulatedCamera::FACING_KEY);
     if (valstr != NULL) {
         if (strcmp(valstr, EmulatedCamera::FACING_FRONT) == 0) {
             info->facing = CAMERA_FACING_FRONT;
@@ -186,7 +203,7 @@
         info->facing = CAMERA_FACING_BACK;
     }
 
-    valstr = parameters_.get(EmulatedCamera::ORIENTATION_KEY);
+    valstr = mParameters.get(EmulatedCamera::ORIENTATION_KEY);
     if (valstr != NULL) {
         info->orientation = atoi(valstr);
     } else {
@@ -196,86 +213,82 @@
     return NO_ERROR;
 }
 
-status_t EmulatedCamera::SetPreviewWindow(struct preview_stream_ops* window)
+status_t EmulatedCamera::setPreviewWindow(struct preview_stream_ops* window)
 {
     /* Callback should return a negative errno. */
-    return -preview_window_.SetPreviewWindow(window,
-                                             parameters_.getPreviewFrameRate());
+    return -mPreviewWindow.setPreviewWindow(window,
+                                             mParameters.getPreviewFrameRate());
 }
 
-void EmulatedCamera::SetCallbacks(camera_notify_callback notify_cb,
+void EmulatedCamera::setCallbacks(camera_notify_callback notify_cb,
                                   camera_data_callback data_cb,
                                   camera_data_timestamp_callback data_cb_timestamp,
                                   camera_request_memory get_memory,
                                   void* user)
 {
-    callback_notifier_.SetCallbacks(notify_cb, data_cb, data_cb_timestamp,
+    mCallbackNotifier.setCallbacks(notify_cb, data_cb, data_cb_timestamp,
                                     get_memory, user);
 }
 
-void EmulatedCamera::EnableMsgType(int32_t msg_type)
+void EmulatedCamera::enableMsgType(int32_t msg_type)
 {
-    callback_notifier_.EnableMessage(msg_type);
+    mCallbackNotifier.enableMessage(msg_type);
 }
 
-void EmulatedCamera::DisableMsgType(int32_t msg_type)
+void EmulatedCamera::disableMsgType(int32_t msg_type)
 {
-    callback_notifier_.DisableMessage(msg_type);
+    mCallbackNotifier.disableMessage(msg_type);
 }
 
-int EmulatedCamera::MsgTypeEnabled(int32_t msg_type)
+int EmulatedCamera::isMsgTypeEnabled(int32_t msg_type)
 {
-    return callback_notifier_.IsMessageEnabled(msg_type);
+    return mCallbackNotifier.isMessageEnabled(msg_type);
 }
 
-status_t EmulatedCamera::StartPreview()
-{
-    LOGV("%s", __FUNCTION__);
-
-    /* Callback should return a negative errno. */
-    return -DoStartPreview();
-}
-
-void EmulatedCamera::StopPreview()
-{
-    LOGV("%s", __FUNCTION__);
-
-    DoStopPreview();
-}
-
-int EmulatedCamera::PreviewEnabled()
-{
-    return preview_window_.IsEnabled();
-}
-
-status_t EmulatedCamera::StoreMetaDataInBuffers(int enable)
+status_t EmulatedCamera::startPreview()
 {
     /* Callback should return a negative errno. */
-    return -callback_notifier_.StoreMetaDataInBuffers(enable);
+    return -doStartPreview();
 }
 
-status_t EmulatedCamera::StartRecording()
+void EmulatedCamera::stopPreview()
+{
+    doStopPreview();
+}
+
+int EmulatedCamera::isPreviewEnabled()
+{
+    return mPreviewWindow.isPreviewEnabled();
+}
+
+status_t EmulatedCamera::storeMetaDataInBuffers(int enable)
 {
     /* Callback should return a negative errno. */
-    return -callback_notifier_.EnableVideoRecording(parameters_.getPreviewFrameRate());
+    return -mCallbackNotifier.storeMetaDataInBuffers(enable);
 }
 
-void EmulatedCamera::StopRecording()
+status_t EmulatedCamera::startRecording()
 {
-    callback_notifier_.DisableVideoRecording();
+    /* Callback should return a negative errno. */
+    return -mCallbackNotifier.enableVideoRecording(mParameters.getPreviewFrameRate());
 }
 
-int EmulatedCamera::RecordingEnabled()
+void EmulatedCamera::stopRecording()
 {
-    return callback_notifier_.IsVideoRecordingEnabled();
+    mCallbackNotifier.disableVideoRecording();
 }
 
-void EmulatedCamera::ReleaseRecordingFrame(const void* opaque)
+int EmulatedCamera::isRecordingEnabled()
 {
-    callback_notifier_.ReleaseRecordingFrame(opaque);
+    return mCallbackNotifier.isVideoRecordingEnabled();
 }
 
-status_t EmulatedCamera::AutoFocus()
+void EmulatedCamera::releaseRecordingFrame(const void* opaque)
+{
+    mCallbackNotifier.releaseRecordingFrame(opaque);
+}
+
+status_t EmulatedCamera::setAutoFocus()
 {
     LOGV("%s", __FUNCTION__);
 
@@ -283,7 +296,7 @@
     return NO_ERROR;
 }
 
-status_t EmulatedCamera::CancelAutoFocus()
+status_t EmulatedCamera::cancelAutoFocus()
 {
     LOGV("%s", __FUNCTION__);
 
@@ -291,44 +304,99 @@
     return NO_ERROR;
 }
 
-status_t EmulatedCamera::TakePicture()
+status_t EmulatedCamera::takePicture()
 {
     LOGV("%s", __FUNCTION__);
 
+    status_t res;
+    int width, height;
+    uint32_t org_fmt;
+
+    /* Collect frame info for the picture. */
+    mParameters.getPictureSize(&width, &height);
+    const char* pix_fmt = mParameters.getPictureFormat();
+    if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
+        org_fmt = V4L2_PIX_FMT_YUV420;
+    } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) {
+        org_fmt = V4L2_PIX_FMT_RGB32;
+    } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
+        org_fmt = V4L2_PIX_FMT_NV21;
+    } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_JPEG) == 0) {
+        /* We only have JPEG converted for NV21 format. */
+        org_fmt = V4L2_PIX_FMT_NV21;
+    } else {
+        LOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
+        return EINVAL;
+    }
+    /* Get JPEG quality. */
+    int jpeg_quality = mParameters.getInt(CameraParameters::KEY_JPEG_QUALITY);
+    if (jpeg_quality <= 0) {
+        jpeg_quality = 90;  /* Fall back to default. */
+    }
+
     /*
-     * Before taking picture, pause the camera (pause worker thread), and pause
-     * the preview.
+     * Make sure preview is not running, and device is stopped before taking
+     * picture.
      */
 
+    const bool preview_on = mPreviewWindow.isPreviewEnabled();
+    if (preview_on) {
+        doStopPreview();
+    }
+
+    /* Camera device should have been stopped when the shutter message has been
+     * enabled. */
+    EmulatedCameraDevice* const camera_dev = getCameraDevice();
+    if (camera_dev->isStarted()) {
+        LOGW("%s: Camera device is started", __FUNCTION__);
+        camera_dev->stopDeliveringFrames();
+        camera_dev->stopDevice();
+    }
+
     /*
      * Take the picture now.
      */
 
-    /*
-     * After picture has been taken, resume the preview, and the camera (if any
-     * has been paused.
-     */
+    /* Start camera device for the picture frame. */
+    LOGD("Starting camera for picture: %.4s(%s)[%dx%d]",
+         reinterpret_cast<const char*>(&org_fmt), pix_fmt, width, height);
+    res = camera_dev->startDevice(width, height, org_fmt);
+    if (res != NO_ERROR) {
+        if (preview_on) {
+            doStartPreview();
+        }
+        return res;
+    }
 
-
-    return NO_ERROR;
+    /* Deliver one frame only. */
+    mCallbackNotifier.setJpegQuality(jpeg_quality);
+    mCallbackNotifier.setTakingPicture(true);
+    res = camera_dev->startDeliveringFrames(true);
+    if (res != NO_ERROR) {
+        mCallbackNotifier.setTakingPicture(false);
+        if (preview_on) {
+            doStartPreview();
+        }
+    }
+    return res;
 }
 
-status_t EmulatedCamera::CancelPicture()
+status_t EmulatedCamera::cancelPicture()
 {
     LOGV("%s", __FUNCTION__);
 
     return NO_ERROR;
 }
 
-status_t EmulatedCamera::SetParameters(const char* parms)
+status_t EmulatedCamera::setParameters(const char* parms)
 {
     LOGV("%s", __FUNCTION__);
-    _PrintParamDiff(parameters_, parms);
+    PrintParamDiff(mParameters, parms);
 
     CameraParameters new_param;
     String8 str8_param(parms);
     new_param.unflatten(str8_param);
-    parameters_ = new_param;
+    mParameters = new_param;
 
     /*
      * In emulation, there are certain parameters that are required by the
@@ -338,49 +406,49 @@
      */
 
     /* Supported preview size. */
-    const char* check = parameters_.get(CameraParameters::KEY_PREVIEW_SIZE);
+    const char* check = mParameters.get(CameraParameters::KEY_PREVIEW_SIZE);
     if (check != NULL) {
         const char* current =
-            parameters_.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
+            mParameters.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
         if (strstr(current, check) == NULL) {
             /* Required size doesn't exist in the list. Add it. */
-            char* to_add = _AddValue(current, check);
+            char* to_add = AddValue(current, check);
             if (to_add != NULL) {
                 LOGD("+++ %s: Added %s to supported preview sizes",
                      __FUNCTION__, check);
-                parameters_.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, to_add);
+                mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, to_add);
                 free(to_add);
             }
         }
     }
 
     /* Supported preview frame rate. */
-    check = parameters_.get(CameraParameters::KEY_PREVIEW_FRAME_RATE);
+    check = mParameters.get(CameraParameters::KEY_PREVIEW_FRAME_RATE);
     if (check != NULL) {
         const char* current =
-            parameters_.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
+            mParameters.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
         if (strstr(current, check) == NULL) {
-            char* to_add = _AddValue(current, check);
+            char* to_add = AddValue(current, check);
             if (to_add != NULL) {
                 LOGD("+++ %s: Added %s to supported preview frame rates",
                      __FUNCTION__, check);
-                parameters_.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, to_add);
+                mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, to_add);
                 free(to_add);
             }
         }
     }
 
     /* Supported picture size. */
-    check = parameters_.get(CameraParameters::KEY_PICTURE_SIZE);
+    check = mParameters.get(CameraParameters::KEY_PICTURE_SIZE);
     if (check != NULL) {
         const char* current =
-            parameters_.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
+            mParameters.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
         if (strstr(current, check) == NULL) {
-            char* to_add = _AddValue(current, check);
+            char* to_add = AddValue(current, check);
             if (to_add != NULL) {
                 LOGD("+++ %s: Added %s to supported picture sizes",
                      __FUNCTION__, check);
-                parameters_.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, to_add);
+                mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, to_add);
                 free(to_add);
             }
         }
@@ -390,11 +458,11 @@
 }
 
 /* A dumb variable indicating "no params" / error on the exit from
- * EmulatedCamera::GetParameters(). */
-static char _no_param = '\0';
-char* EmulatedCamera::GetParameters()
+ * EmulatedCamera::getParameters(). */
+static char lNoParam = '\0';
+char* EmulatedCamera::getParameters()
 {
-    String8 params(parameters_.flatten());
+    String8 params(mParameters.flatten());
     char* ret_str =
         reinterpret_cast<char*>(malloc(sizeof(char) * (params.length()+1)));
     memset(ret_str, 0, params.length()+1);
@@ -404,19 +472,19 @@
     } else {
         LOGE("%s: Unable to allocate string for %s", __FUNCTION__, params.string());
         /* Apparently, we can't return NULL fron this routine. */
-        return &_no_param;
+        return &lNoParam;
     }
 }
 
-void EmulatedCamera::PutParameters(char* params)
+void EmulatedCamera::putParameters(char* params)
 {
-    /* This method simply frees parameters allocated in GetParameters(). */
-    if (params != NULL && params != &_no_param) {
+    /* This method simply frees parameters allocated in getParameters(). */
+    if (params != NULL && params != &lNoParam) {
         free(params);
     }
 }
 
-status_t EmulatedCamera::SendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
+status_t EmulatedCamera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
 {
     LOGV("%s: cmd = %d, arg1 = %d, arg2 = %d", __FUNCTION__, cmd, arg1, arg2);
 
@@ -424,14 +492,14 @@
     return 0;
 }
 
-void EmulatedCamera::Release()
+void EmulatedCamera::releaseCamera()
 {
     LOGV("%s", __FUNCTION__);
 
-    Cleanup();
+    cleanupCamera();
 }
 
-status_t EmulatedCamera::Dump(int fd)
+status_t EmulatedCamera::dumpCamera(int fd)
 {
     LOGV("%s", __FUNCTION__);
 
@@ -443,135 +511,131 @@
  * Preview management.
  ***************************************************************************/
 
-status_t EmulatedCamera::DoStartPreview()
+status_t EmulatedCamera::doStartPreview()
 {
-    status_t res = preview_window_.Start();
+    LOGV("%s", __FUNCTION__);
 
-    /* Start the camera. */
-    if (res == NO_ERROR && !GetCameraDevice()->IsCapturing()) {
-        res = StartCamera();
+    EmulatedCameraDevice* camera_dev = getCameraDevice();
+    if (camera_dev->isStarted()) {
+        camera_dev->stopDeliveringFrames();
+        camera_dev->stopDevice();
+    }
+
+    status_t res = mPreviewWindow.startPreview();
+    if (res != NO_ERROR) {
+        return res;
+    }
+
+    /* Make sure camera device is connected. */
+    if (!camera_dev->isConnected()) {
+        res = camera_dev->connectDevice();
         if (res != NO_ERROR) {
-            /* If camera didn't start, disable the preview window. */
-            preview_window_.Stop();
+            mPreviewWindow.stopPreview();
+            return res;
         }
     }
 
+    int width, height;
+    /* Lets see what should we use for frame width, and height. */
+    if (mParameters.get(CameraParameters::KEY_VIDEO_SIZE) != NULL) {
+        mParameters.getVideoSize(&width, &height);
+    } else {
+        mParameters.getPreviewSize(&width, &height);
+    }
+    /* Lets see what should we use for the frame pixel format. */
+    const char* pix_fmt =
+        mParameters.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT);
+    if (pix_fmt == NULL) {
+        pix_fmt = mParameters.getPreviewFormat();
+    }
+    if (pix_fmt == NULL) {
+        LOGE("%s: Unable to obtain video format", __FUNCTION__);
+        mPreviewWindow.stopPreview();
+        return EINVAL;
+    }
+    uint32_t org_fmt;
+    if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
+        org_fmt = V4L2_PIX_FMT_YUV420;
+    } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) {
+        org_fmt = V4L2_PIX_FMT_RGB32;
+    } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
+        org_fmt = V4L2_PIX_FMT_NV21;
+    } else {
+        LOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
+        mPreviewWindow.stopPreview();
+        return EINVAL;
+    }
+    LOGD("Starting camera: %dx%d -> %.4s(%s)",
+         width, height, reinterpret_cast<const char*>(&org_fmt), pix_fmt);
+    res = camera_dev->startDevice(width, height, org_fmt);
+    if (res != NO_ERROR) {
+        mPreviewWindow.stopPreview();
+        return res;
+    }
+
+    res = camera_dev->startDeliveringFrames(false);
+    if (res != NO_ERROR) {
+        camera_dev->stopDevice();
+        mPreviewWindow.stopPreview();
+    }
+
     return res;
 }
 
-status_t EmulatedCamera::DoStopPreview()
+status_t EmulatedCamera::doStopPreview()
 {
-    status_t res = NO_ERROR;
-    /* Stop the camera. */
-    if (GetCameraDevice()->IsCapturing()) {
-        res = StopCamera();
-    }
+    LOGV("%s", __FUNCTION__);
 
-    if (res == NO_ERROR) {
-        /* Disable preview as well. */
-        preview_window_.Stop();
+    status_t res = NO_ERROR;
+    if (mPreviewWindow.isPreviewEnabled()) {
+        /* Stop the camera. */
+        if (getCameraDevice()->isStarted()) {
+            getCameraDevice()->stopDeliveringFrames();
+            res = getCameraDevice()->stopDevice();
+        }
+
+        if (res == NO_ERROR) {
+            /* Disable preview as well. */
+            mPreviewWindow.stopPreview();
+        }
     }
 
     return NO_ERROR;
 }
 
-status_t EmulatedCamera::StartCamera()
-{
-    status_t res = EINVAL;
-    EmulatedCameraDevice* camera_dev = GetCameraDevice();
-    if (camera_dev != NULL) {
-        if (!camera_dev->IsConnected()) {
-            res = camera_dev->Connect();
-            if (res != NO_ERROR) {
-                return res;
-            }
-        }
-        if (!camera_dev->IsCapturing()) {
-            int width, height;
-            /* Lets see what should we use for frame width, and height. */
-            if (parameters_.get(CameraParameters::KEY_VIDEO_SIZE) != NULL) {
-                parameters_.getVideoSize(&width, &height);
-            } else {
-                parameters_.getPreviewSize(&width, &height);
-            }
-            /* Lets see what should we use for the frame pixel format. */
-            const char* pix_fmt = parameters_.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT);
-            if (pix_fmt == NULL) {
-                pix_fmt = parameters_.getPreviewFormat();
-            }
-            if (pix_fmt == NULL) {
-                LOGE("%s: Unable to obtain video format", __FUNCTION__);
-                return EINVAL;
-            }
-            uint32_t org_fmt;
-            if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGB565) == 0) {
-                org_fmt = V4L2_PIX_FMT_RGB565;
-            } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
-                org_fmt = V4L2_PIX_FMT_YVU420;
-            } else {
-                LOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
-                return EINVAL;
-            }
-            LOGD("Starting camera: %dx%d -> %s", width, height, pix_fmt);
-            res = camera_dev->StartCapturing(width, height, org_fmt);
-            if (res != NO_ERROR) {
-                return res;
-            }
-        }
-    }
-
-    return res;
-}
-
-status_t EmulatedCamera::StopCamera()
-{
-    status_t res = NO_ERROR;
-    EmulatedCameraDevice* const camera_dev = GetCameraDevice();
-    if (camera_dev != NULL) {
-        if (camera_dev->IsCapturing()) {
-            res = camera_dev->StopCapturing();
-            if (res != NO_ERROR) {
-                return res;
-            }
-        }
-    }
-
-    return res;
-}
-
-
 /****************************************************************************
  * Private API.
  ***************************************************************************/
 
-status_t EmulatedCamera::Cleanup()
+status_t EmulatedCamera::cleanupCamera()
 {
     status_t res = NO_ERROR;
 
     /* If preview is running - stop it. */
-    res = DoStopPreview();
+    res = doStopPreview();
     if (res != NO_ERROR) {
         return -res;
     }
 
     /* Stop and disconnect the camera device. */
-    EmulatedCameraDevice* const camera_dev = GetCameraDevice();
+    EmulatedCameraDevice* const camera_dev = getCameraDevice();
     if (camera_dev != NULL) {
-        if (camera_dev->IsCapturing()) {
-            res = camera_dev->StopCapturing();
+        if (camera_dev->isStarted()) {
+            camera_dev->stopDeliveringFrames();
+            res = camera_dev->stopDevice();
             if (res != NO_ERROR) {
                 return -res;
             }
         }
-        if (camera_dev->IsConnected()) {
-            res = camera_dev->Disconnect();
+        if (camera_dev->isConnected()) {
+            res = camera_dev->disconnectDevice();
             if (res != NO_ERROR) {
                 return -res;
             }
         }
     }
 
-    callback_notifier_.Cleanup();
+    mCallbackNotifier.cleanupCBNotifier();
 
     return NO_ERROR;
 }
@@ -591,7 +655,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->SetPreviewWindow(window);
+    return ec->setPreviewWindow(window);
 }
 
 void EmulatedCamera::set_callbacks(
@@ -607,7 +671,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return;
     }
-    ec->SetCallbacks(notify_cb, data_cb, data_cb_timestamp, get_memory, user);
+    ec->setCallbacks(notify_cb, data_cb, data_cb_timestamp, get_memory, user);
 }
 
 void EmulatedCamera::enable_msg_type(struct camera_device* dev, int32_t msg_type)
@@ -617,7 +681,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return;
     }
-    ec->EnableMsgType(msg_type);
+    ec->enableMsgType(msg_type);
 }
 
 void EmulatedCamera::disable_msg_type(struct camera_device* dev, int32_t msg_type)
@@ -627,7 +691,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return;
     }
-    ec->DisableMsgType(msg_type);
+    ec->disableMsgType(msg_type);
 }
 
 int EmulatedCamera::msg_type_enabled(struct camera_device* dev, int32_t msg_type)
@@ -637,7 +701,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->MsgTypeEnabled(msg_type);
+    return ec->isMsgTypeEnabled(msg_type);
 }
 
 int EmulatedCamera::start_preview(struct camera_device* dev)
@@ -647,7 +711,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->StartPreview();
+    return ec->startPreview();
 }
 
 void EmulatedCamera::stop_preview(struct camera_device* dev)
@@ -657,7 +721,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return;
     }
-    ec->StopPreview();
+    ec->stopPreview();
 }
 
 int EmulatedCamera::preview_enabled(struct camera_device* dev)
@@ -667,7 +731,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->PreviewEnabled();
+    return ec->isPreviewEnabled();
 }
 
 int EmulatedCamera::store_meta_data_in_buffers(struct camera_device* dev,
@@ -678,7 +742,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->StoreMetaDataInBuffers(enable);
+    return ec->storeMetaDataInBuffers(enable);
 }
 
 int EmulatedCamera::start_recording(struct camera_device* dev)
@@ -688,7 +752,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->StartRecording();
+    return ec->startRecording();
 }
 
 void EmulatedCamera::stop_recording(struct camera_device* dev)
@@ -698,7 +762,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return;
     }
-    ec->StopRecording();
+    ec->stopRecording();
 }
 
 int EmulatedCamera::recording_enabled(struct camera_device* dev)
@@ -708,7 +772,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->RecordingEnabled();
+    return ec->isRecordingEnabled();
 }
 
 void EmulatedCamera::release_recording_frame(struct camera_device* dev,
@@ -719,7 +783,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return;
     }
-    ec->ReleaseRecordingFrame(opaque);
+    ec->releaseRecordingFrame(opaque);
 }
 
 int EmulatedCamera::auto_focus(struct camera_device* dev)
@@ -729,7 +793,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->AutoFocus();
+    return ec->setAutoFocus();
 }
 
 int EmulatedCamera::cancel_auto_focus(struct camera_device* dev)
@@ -739,7 +803,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->CancelAutoFocus();
+    return ec->cancelAutoFocus();
 }
 
 int EmulatedCamera::take_picture(struct camera_device* dev)
@@ -749,7 +813,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->TakePicture();
+    return ec->takePicture();
 }
 
 int EmulatedCamera::cancel_picture(struct camera_device* dev)
@@ -759,7 +823,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->CancelPicture();
+    return ec->cancelPicture();
 }
 
 int EmulatedCamera::set_parameters(struct camera_device* dev, const char* parms)
@@ -769,7 +833,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->SetParameters(parms);
+    return ec->setParameters(parms);
 }
 
 char* EmulatedCamera::get_parameters(struct camera_device* dev)
@@ -779,7 +843,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return NULL;
     }
-    return ec->GetParameters();
+    return ec->getParameters();
 }
 
 void EmulatedCamera::put_parameters(struct camera_device* dev, char* params)
@@ -789,7 +853,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return;
     }
-    ec->PutParameters(params);
+    ec->putParameters(params);
 }
 
 int EmulatedCamera::send_command(struct camera_device* dev,
@@ -802,7 +866,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->SendCommand(cmd, arg1, arg2);
+    return ec->sendCommand(cmd, arg1, arg2);
 }
 
 void EmulatedCamera::release(struct camera_device* dev)
@@ -812,7 +876,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return;
     }
-    ec->Release();
+    ec->releaseCamera();
 }
 
 int EmulatedCamera::dump(struct camera_device* dev, int fd)
@@ -822,7 +886,7 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->Dump(fd);
+    return ec->dumpCamera(fd);
 }
 
 int EmulatedCamera::close(struct hw_device_t* device)
@@ -833,14 +897,14 @@
         LOGE("%s: Unexpected NULL camera device", __FUNCTION__);
         return -EINVAL;
     }
-    return ec->Close();
+    return ec->closeCamera();
 }
 
 /****************************************************************************
  * Static initializer for the camera callback API
  ****************************************************************************/
 
-camera_device_ops_t EmulatedCamera::device_ops_ = {
+camera_device_ops_t EmulatedCamera::mDeviceOps = {
     EmulatedCamera::set_preview_window,
     EmulatedCamera::set_callbacks,
     EmulatedCamera::enable_msg_type,
@@ -884,7 +948,7 @@
  * Helper routines
  ***************************************************************************/
 
-static char* _AddValue(const char* param, const char* val)
+static char* AddValue(const char* param, const char* val)
 {
     const size_t len1 = strlen(param);
     const size_t len2 = strlen(val);
@@ -904,7 +968,7 @@
  ***************************************************************************/
 
 #if DEBUG_PARAM
-static void _PrintParamDiff(const CameraParameters& current,
+static void PrintParamDiff(const CameraParameters& current,
                             const char* new_par)
 {
     char tmp[2048];
diff --git a/tools/emulator/system/camera/emulated_camera.h b/tools/emulator/system/camera/EmulatedCamera.h
old mode 100644
new mode 100755
similarity index 86%
rename from tools/emulator/system/camera/emulated_camera.h
rename to tools/emulator/system/camera/EmulatedCamera.h
index a5b2aac..8afdd83
--- a/tools/emulator/system/camera/emulated_camera.h
+++ b/tools/emulator/system/camera/EmulatedCamera.h
@@ -27,9 +27,9 @@
  */
 
 #include <camera/CameraParameters.h>
-#include "emulated_camera_device.h"
-#include "preview_window.h"
-#include "callback_notifier.h"
+#include "EmulatedCameraDevice.h"
+#include "PreviewWindow.h"
+#include "CallbackNotifier.h"
 
 namespace android {
 
@@ -38,8 +38,8 @@
  *
  * Note that EmulatedCameraFactory instantiates object of this class just once,
  * when EmulatedCameraFactory instance gets constructed. Connection to /
- * disconnection from the actual camera device is handled by calls to Connect(),
- * and Close() methods of this class that are ivoked in response to
+ * disconnection from the actual camera device is handled by calls to connectDevice(),
+ * and closeCamera() methods of this class that are ivoked in response to
  * hw_module_methods_t::open, and camera_device::close callbacks.
  */
 class EmulatedCamera : public camera_device {
@@ -62,7 +62,7 @@
 public:
     /* Gets emulated camera device used by this instance of the emulated camera.
      */
-    virtual EmulatedCameraDevice* GetCameraDevice() = 0;
+    virtual EmulatedCameraDevice* getCameraDevice() = 0;
 
     /****************************************************************************
      * Public API
@@ -90,10 +90,16 @@
      * timestamp - Frame's timestamp.
      * camera_dev - Camera device instance that delivered the frame.
      */
-    virtual void OnNextFrameAvailable(const void* frame,
+    virtual void onNextFrameAvailable(const void* frame,
                                       nsecs_t timestamp,
                                       EmulatedCameraDevice* camera_dev);
 
+    /* Entry point for notifications that occur in camera device.
+     * Param:
+     *  err - CAMERA_ERROR_XXX error code.
+     */
+    virtual void onCameraDeviceError(int err);
+
     /****************************************************************************
      * Camera API implementation
      ***************************************************************************/
@@ -104,14 +110,14 @@
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t Connect(hw_device_t** device);
+    virtual status_t connectCamera(hw_device_t** device);
 
     /* Closes connection to the emulated camera.
      * This method is called in response to camera_device::close callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t Close();
+    virtual status_t closeCamera();
 
     /* Gets camera information.
      * This method is called in response to camera_module_t::get_camera_info
@@ -119,7 +125,7 @@
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t GetCameraInfo(struct camera_info* info);
+    virtual status_t getCameraInfo(struct camera_info* info);
 
     /****************************************************************************
      * Camera API implementation.
@@ -131,12 +137,12 @@
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t SetPreviewWindow(struct preview_stream_ops *window);
+    virtual status_t setPreviewWindow(struct preview_stream_ops *window);
 
     /* Actual handler for camera_device_ops_t::set_callbacks callback.
      * NOTE: When this method is called the object is locked.
      */
-    virtual void SetCallbacks(camera_notify_callback notify_cb,
+    virtual void setCallbacks(camera_notify_callback notify_cb,
                               camera_data_callback data_cb,
                               camera_data_timestamp_callback data_cb_timestamp,
                               camera_request_memory get_memory,
@@ -145,96 +151,96 @@
     /* Actual handler for camera_device_ops_t::enable_msg_type callback.
      * NOTE: When this method is called the object is locked.
      */
-    virtual void EnableMsgType(int32_t msg_type);
+    virtual void enableMsgType(int32_t msg_type);
 
     /* Actual handler for camera_device_ops_t::disable_msg_type callback.
      * NOTE: When this method is called the object is locked.
      */
-    virtual void DisableMsgType(int32_t msg_type);
+    virtual void disableMsgType(int32_t msg_type);
 
     /* Actual handler for camera_device_ops_t::msg_type_enabled callback.
      * NOTE: When this method is called the object is locked.
      * Return:
      *  0 if message(s) is (are) disabled, != 0 if enabled.
      */
-    virtual int MsgTypeEnabled(int32_t msg_type);
+    virtual int isMsgTypeEnabled(int32_t msg_type);
 
     /* Actual handler for camera_device_ops_t::start_preview callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t StartPreview();
+    virtual status_t startPreview();
 
     /* Actual handler for camera_device_ops_t::stop_preview callback.
      * NOTE: When this method is called the object is locked.
      */
-    virtual void StopPreview();
+    virtual void stopPreview();
 
     /* Actual handler for camera_device_ops_t::preview_enabled callback.
      * NOTE: When this method is called the object is locked.
      * Return:
      *  0 if preview is disabled, != 0 if enabled.
      */
-    virtual int PreviewEnabled();
+    virtual int isPreviewEnabled();
 
     /* Actual handler for camera_device_ops_t::store_meta_data_in_buffers callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t StoreMetaDataInBuffers(int enable);
+    virtual status_t storeMetaDataInBuffers(int enable);
 
     /* Actual handler for camera_device_ops_t::start_recording callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t StartRecording();
+    virtual status_t startRecording();
 
     /* Actual handler for camera_device_ops_t::stop_recording callback.
      * NOTE: When this method is called the object is locked.
      */
-    virtual void StopRecording();
+    virtual void stopRecording();
 
     /* Actual handler for camera_device_ops_t::recording_enabled callback.
      * NOTE: When this method is called the object is locked.
      * Return:
      *  0 if recording is disabled, != 0 if enabled.
      */
-    virtual int RecordingEnabled();
+    virtual int isRecordingEnabled();
 
     /* Actual handler for camera_device_ops_t::release_recording_frame callback.
      * NOTE: When this method is called the object is locked.
      */
-    virtual void ReleaseRecordingFrame(const void* opaque);
+    virtual void releaseRecordingFrame(const void* opaque);
 
     /* Actual handler for camera_device_ops_t::auto_focus callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t AutoFocus();
+    virtual status_t setAutoFocus();
 
     /* Actual handler for camera_device_ops_t::cancel_auto_focus callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t CancelAutoFocus();
+    virtual status_t cancelAutoFocus();
 
     /* Actual handler for camera_device_ops_t::take_picture callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t TakePicture();
+    virtual status_t takePicture();
 
     /* Actual handler for camera_device_ops_t::cancel_picture callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t CancelPicture();
+    virtual status_t cancelPicture();
 
     /* Actual handler for camera_device_ops_t::set_parameters callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t SetParameters(const char* parms);
+    virtual status_t setParameters(const char* parms);
 
     /* Actual handler for camera_device_ops_t::get_parameters callback.
      * NOTE: When this method is called the object is locked.
@@ -242,7 +248,7 @@
      *  Flattened parameters string. The caller will free the buffer allocated
      *  for the string by calling camera_device_ops_t::put_parameters callback.
      */
-    virtual char* GetParameters();
+    virtual char* getParameters();
 
     /* Actual handler for camera_device_ops_t::put_parameters callback.
      * Called to free the string returned from camera_device_ops_t::get_parameters
@@ -250,24 +256,24 @@
      * misleading.
      * NOTE: When this method is called the object is locked.
      */
-    virtual void PutParameters(char* params);
+    virtual void putParameters(char* params);
 
     /* Actual handler for camera_device_ops_t::send_command callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t SendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+    virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
 
     /* Actual handler for camera_device_ops_t::release callback.
      * NOTE: When this method is called the object is locked.
      */
-    virtual void Release();
+    virtual void releaseCamera();
 
     /* Actual handler for camera_device_ops_t::dump callback.
      * NOTE: When this method is called the object is locked.
      * Note that failures in this method are reported as negave EXXX statuses.
      */
-    virtual status_t Dump(int fd);
+    virtual status_t dumpCamera(int fd);
 
     /****************************************************************************
      * Preview management.
@@ -275,32 +281,20 @@
 
 protected:
     /* Starts preview.
-     * Note that when this method is called preview_window_ may be NULL,
+     * Note that when this method is called mPreviewWindow may be NULL,
      * indicating that framework has an intention to start displaying video
      * frames, but didn't create the preview window yet.
      * Return:
      *  NO_ERROR on success, or an appropriate error status on failure.
      */
-    virtual status_t DoStartPreview();
+    virtual status_t doStartPreview();
 
     /* Stops preview.
      * This method reverts DoStartPreview.
      * Return:
      *  NO_ERROR on success, or an appropriate error status on failure.
      */
-    virtual status_t DoStopPreview();
-
-    /* Starts capturing frames
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status on failure.
-     */
-    virtual status_t StartCamera();
-
-    /* Stops capturing frames.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status on failure.
-     */
-    virtual status_t StopCamera();
+    virtual status_t doStopPreview();
 
     /****************************************************************************
      * Private API.
@@ -308,7 +302,7 @@
 
 protected:
     /* Cleans up camera when released. */
-    virtual status_t Cleanup();
+    virtual status_t cleanupCamera();
 
     /****************************************************************************
      * Camera API callbacks as defined by camera_device_ops structure.
@@ -383,23 +377,23 @@
 
 protected:
     /* Locks this instance for parameters, state, etc. change. */
-    Mutex                           object_lock_;
+    Mutex                           mObjectLock;
 
     /* Camera parameters. */
-    CameraParameters                parameters_;
+    CameraParameters                mParameters;
 
     /* Preview window. */
-    PreviewWindow                   preview_window_;
+    PreviewWindow                   mPreviewWindow;
 
     /* Callback notifier. */
-    CallbackNotifier                callback_notifier_;
+    CallbackNotifier                mCallbackNotifier;
 
     /* Zero-based ID assigned to this camera. */
-    int                             camera_id_;
+    int                             mCameraID;
 
 private:
     /* Registered callbacks implementing camera API. */
-    static camera_device_ops_t      device_ops_;
+    static camera_device_ops_t      mDeviceOps;
 
     /****************************************************************************
      * Common keys
diff --git a/tools/emulator/system/camera/emulated_camera_common.h b/tools/emulator/system/camera/EmulatedCameraCommon.h
old mode 100644
new mode 100755
similarity index 83%
rename from tools/emulator/system/camera/emulated_camera_common.h
rename to tools/emulator/system/camera/EmulatedCameraCommon.h
index 1b8b740..907985a
--- a/tools/emulator/system/camera/emulated_camera_common.h
+++ b/tools/emulator/system/camera/EmulatedCameraCommon.h
@@ -33,33 +33,23 @@
 public:
     /* Constructor that prints an "entry" trace message. */
     explicit HWERoutineTracker(const char* name)
-            : name_(name) {
-        LOGV("Entering %s", name_);
+            : mName(name) {
+        LOGV("Entering %s", mName);
     }
 
     /* Destructor that prints a "leave" trace message. */
     ~HWERoutineTracker() {
-        LOGV("Leaving %s", name_);
+        LOGV("Leaving %s", mName);
     }
 
 private:
     /* Stores the routine name. */
-    const char* name_;
+    const char* mName;
 };
 
 /* Logs an execution of a routine / method. */
 #define LOGRE() HWERoutineTracker hwertracker_##__LINE__(__FUNCTION__)
 
-static __inline__ void Sleep(int millisec)
-{
-    if (millisec != 0) {
-        timeval to;
-        to.tv_sec = millisec / 1000;
-        to.tv_usec = (millisec % 1000) * 1000;
-        select(0, NULL, NULL, NULL, &to);
-    }
-}
-
 /*
  * min / max macros
  */
diff --git a/tools/emulator/system/camera/EmulatedCameraDevice.cpp b/tools/emulator/system/camera/EmulatedCameraDevice.cpp
new file mode 100755
index 0000000..e09bead
--- /dev/null
+++ b/tools/emulator/system/camera/EmulatedCameraDevice.cpp
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Contains implementation of an abstract class EmulatedCameraDevice that defines
+ * functionality expected from an emulated physical camera device:
+ *  - Obtaining and setting camera parameters
+ *  - Capturing frames
+ *  - Streaming video
+ *  - etc.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera_Device"
+#include <cutils/log.h>
+#include <sys/select.h>
+#include "EmulatedCameraDevice.h"
+#include "Converters.h"
+
+namespace android {
+
+EmulatedCameraDevice::EmulatedCameraDevice(EmulatedCamera* camera_hal)
+    : mObjectLock(),
+      mCurFrameTimestamp(0),
+      mCameraHAL(camera_hal),
+      mCurrentFrame(NULL),
+      mState(ECDS_CONSTRUCTED)
+{
+}
+
+EmulatedCameraDevice::~EmulatedCameraDevice()
+{
+    if (mCurrentFrame != NULL) {
+        delete[] mCurrentFrame;
+    }
+}
+
+/****************************************************************************
+ * Emulated camera device public API
+ ***************************************************************************/
+
+status_t EmulatedCameraDevice::Initialize()
+{
+    if (isInitialized()) {
+        LOGW("%s: Emulated camera device is already initialized: mState = %d",
+             __FUNCTION__, mState);
+        return NO_ERROR;
+    }
+
+    /* Instantiate worker thread object. */
+    mWorkerThread = new WorkerThread(this);
+    if (getWorkerThread() == NULL) {
+        LOGE("%s: Unable to instantiate worker thread object", __FUNCTION__);
+        return ENOMEM;
+    }
+
+    mState = ECDS_INITIALIZED;
+
+    return NO_ERROR;
+}
+
+status_t EmulatedCameraDevice::startDeliveringFrames(bool one_burst)
+{
+    LOGV("%s", __FUNCTION__);
+
+    if (!isStarted()) {
+        LOGE("%s: Device is not started", __FUNCTION__);
+        return EINVAL;
+    }
+
+    /* Frames will be delivered from the thread routine. */
+    const status_t res = startWorkerThread(one_burst);
+    LOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__);
+    return res;
+}
+
+status_t EmulatedCameraDevice::stopDeliveringFrames()
+{
+    LOGV("%s", __FUNCTION__);
+
+    if (!isStarted()) {
+        LOGW("%s: Device is not started", __FUNCTION__);
+        return NO_ERROR;
+    }
+
+    const status_t res = stopWorkerThread();
+    LOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__);
+    return res;
+}
+
+status_t EmulatedCameraDevice::getCurrentPreviewFrame(void* buffer)
+{
+    if (!isStarted()) {
+        LOGE("%s: Device is not started", __FUNCTION__);
+        return EINVAL;
+    }
+    if (mCurrentFrame == NULL || buffer == NULL) {
+        LOGE("%s: No framebuffer", __FUNCTION__);
+        return EINVAL;
+    }
+
+    /* In emulation the framebuffer is never RGB. */
+    switch (mPixelFormat) {
+        case V4L2_PIX_FMT_YVU420:
+            YV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
+            return NO_ERROR;
+        case V4L2_PIX_FMT_YUV420:
+            YU12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
+            return NO_ERROR;
+        case V4L2_PIX_FMT_NV21:
+            NV21ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
+            return NO_ERROR;
+        case V4L2_PIX_FMT_NV12:
+            NV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
+            return NO_ERROR;
+
+        default:
+            LOGE("%s: Unknown pixel format %.4s",
+                 __FUNCTION__, reinterpret_cast<const char*>(&mPixelFormat));
+            return EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Emulated camera device private API
+ ***************************************************************************/
+
+status_t EmulatedCameraDevice::commonStartDevice(int width,
+                                                 int height,
+                                                 uint32_t pix_fmt)
+{
+    /* Validate pixel format, and calculate framebuffer size at the same time. */
+    switch (pix_fmt) {
+        case V4L2_PIX_FMT_YVU420:
+        case V4L2_PIX_FMT_YUV420:
+        case V4L2_PIX_FMT_NV21:
+        case V4L2_PIX_FMT_NV12:
+            mFrameBufferSize = (width * height * 12) / 8;
+            break;
+
+        default:
+            LOGE("%s: Unknown pixel format %.4s",
+                 __FUNCTION__, reinterpret_cast<const char*>(&pix_fmt));
+            return EINVAL;
+    }
+
+    /* Cache framebuffer info. */
+    mFrameWidth = width;
+    mFrameHeight = height;
+    mPixelFormat = pix_fmt;
+    mTotalPixels = width * height;
+
+    /* Allocate framebuffer. */
+    mCurrentFrame = new uint8_t[mFrameBufferSize];
+    if (mCurrentFrame == NULL) {
+        LOGE("%s: Unable to allocate framebuffer", __FUNCTION__);
+        return ENOMEM;
+    }
+    LOGV("%s: Allocated %p %d bytes for %d pixels in %.4s[%dx%d] frame",
+         __FUNCTION__, mCurrentFrame, mFrameBufferSize, mTotalPixels,
+         reinterpret_cast<const char*>(&mPixelFormat), mFrameWidth, mFrameHeight);
+    return NO_ERROR;
+}
+
+void EmulatedCameraDevice::commonStopDevice()
+{
+    mFrameWidth = mFrameHeight = mTotalPixels = 0;
+    mPixelFormat = 0;
+
+    if (mCurrentFrame != NULL) {
+        delete[] mCurrentFrame;
+        mCurrentFrame = NULL;
+    }
+}
+
+/****************************************************************************
+ * Worker thread management.
+ ***************************************************************************/
+
+status_t EmulatedCameraDevice::startWorkerThread(bool one_burst)
+{
+    LOGV("%s", __FUNCTION__);
+
+    if (!isInitialized()) {
+        LOGE("%s: Emulated camera device is not initialized", __FUNCTION__);
+        return EINVAL;
+    }
+
+    const status_t res = getWorkerThread()->startThread(one_burst);
+    LOGE_IF(res != NO_ERROR, "%s: Unable to start worker thread", __FUNCTION__);
+    return res;
+}
+
+status_t EmulatedCameraDevice::stopWorkerThread()
+{
+    LOGV("%s", __FUNCTION__);
+
+    if (!isInitialized()) {
+        LOGE("%s: Emulated camera device is not initialized", __FUNCTION__);
+        return EINVAL;
+    }
+
+    const status_t res = getWorkerThread()->stopThread();
+    LOGE_IF(res != NO_ERROR, "%s: Unable to stop worker thread", __FUNCTION__);
+    return res;
+}
+
+bool EmulatedCameraDevice::inWorkerThread()
+{
+    /* This will end the thread loop, and will terminate the thread. Derived
+     * classes must override this method. */
+    return false;
+}
+
+/****************************************************************************
+ * Worker thread implementation.
+ ***************************************************************************/
+
+status_t EmulatedCameraDevice::WorkerThread::readyToRun()
+{
+    LOGV("Starting emulated camera device worker thread...");
+
+    LOGW_IF(mThreadControl >= 0 || mControlFD >= 0,
+            "%s: Thread control FDs are opened", __FUNCTION__);
+    /* Create a pair of FDs that would be used to control the thread. */
+    int thread_fds[2];
+    if (pipe(thread_fds) == 0) {
+        mThreadControl = thread_fds[1];
+        mControlFD = thread_fds[0];
+        LOGV("Emulated device's worker thread has been started.");
+        return NO_ERROR;
+    } else {
+        LOGE("%s: Unable to create thread control FDs: %d -> %s",
+             __FUNCTION__, errno, strerror(errno));
+        return errno;
+    }
+}
+
+status_t EmulatedCameraDevice::WorkerThread::stopThread()
+{
+    LOGV("Stopping emulated camera device's worker thread...");
+
+    status_t res = EINVAL;
+    if (mThreadControl >= 0) {
+        /* Send "stop" message to the thread loop. */
+        const ControlMessage msg = THREAD_STOP;
+        const int wres =
+            TEMP_FAILURE_RETRY(write(mThreadControl, &msg, sizeof(msg)));
+        if (wres == sizeof(msg)) {
+            /* Stop the thread, and wait till it's terminated. */
+            res = requestExitAndWait();
+            if (res == NO_ERROR) {
+                /* Close control FDs. */
+                if (mThreadControl >= 0) {
+                    close(mThreadControl);
+                    mThreadControl = -1;
+                }
+                if (mControlFD >= 0) {
+                    close(mControlFD);
+                    mControlFD = -1;
+                }
+                LOGV("Emulated camera device's worker thread has been stopped.");
+            } else {
+                LOGE("%s: requestExitAndWait failed: %d -> %s",
+                     __FUNCTION__, res, strerror(-res));
+            }
+        } else {
+            LOGE("%s: Unable to send THREAD_STOP message: %d -> %s",
+                 __FUNCTION__, errno, strerror(errno));
+            res = errno ? errno : EINVAL;
+        }
+    } else {
+        LOGE("%s: Thread control FDs are not opened", __FUNCTION__);
+    }
+
+    return res;
+}
+
+EmulatedCameraDevice::WorkerThread::SelectRes
+EmulatedCameraDevice::WorkerThread::Select(int fd, int timeout)
+{
+    fd_set fds[1];
+    struct timeval tv, *tvp = NULL;
+
+    const int fd_num = (fd >= 0) ? max(fd, mControlFD) + 1 :
+                                   mControlFD + 1;
+    FD_ZERO(fds);
+    FD_SET(mControlFD, fds);
+    if (fd >= 0) {
+        FD_SET(fd, fds);
+    }
+    if (timeout) {
+        tv.tv_sec = timeout / 1000000;
+        tv.tv_usec = timeout % 1000000;
+        tvp = &tv;
+    }
+    int res = TEMP_FAILURE_RETRY(select(fd_num, fds, NULL, NULL, tvp));
+    if (res < 0) {
+        LOGE("%s: select returned %d and failed: %d -> %s",
+             __FUNCTION__, res, errno, strerror(errno));
+        return ERROR;
+    } else if (res == 0) {
+        /* Timeout. */
+        return TIMEOUT;
+    } else if (FD_ISSET(mControlFD, fds)) {
+        /* A control event. Lets read the message. */
+        ControlMessage msg;
+        res = TEMP_FAILURE_RETRY(read(mControlFD, &msg, sizeof(msg)));
+        if (res != sizeof(msg)) {
+            LOGE("%s: Unexpected message size %d, or an error %d -> %s",
+                 __FUNCTION__, res, errno, strerror(errno));
+            return ERROR;
+        }
+        /* THREAD_STOP is the only message expected here. */
+        if (msg == THREAD_STOP) {
+            LOGV("%s: THREAD_STOP message is received", __FUNCTION__);
+            return EXIT_THREAD;
+        } else {
+            LOGE("Unknown worker thread message %d", msg);
+            return ERROR;
+        }
+    } else {
+        /* Must be an FD. */
+        LOGW_IF(fd < 0 || !FD_ISSET(fd, fds), "%s: Undefined 'select' result",
+                __FUNCTION__);
+        return READY;
+    }
+}
+
+};  /* namespace android */
diff --git a/tools/emulator/system/camera/EmulatedCameraDevice.h b/tools/emulator/system/camera/EmulatedCameraDevice.h
new file mode 100755
index 0000000..88e2dd2
--- /dev/null
+++ b/tools/emulator/system/camera/EmulatedCameraDevice.h
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H
+#define HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H
+
+/*
+ * Contains declaration of an abstract class EmulatedCameraDevice that defines
+ * functionality expected from an emulated physical camera device:
+ *  - Obtaining and setting camera device parameters
+ *  - Capturing frames
+ *  - Streaming video
+ *  - etc.
+ */
+
+#include <utils/threads.h>
+#include "EmulatedCameraCommon.h"
+
+namespace android {
+
+class EmulatedCamera;
+
+/* Encapsulates an abstract class EmulatedCameraDevice that defines
+ * functionality expected from an emulated physical camera device:
+ *  - Obtaining and setting camera device parameters
+ *  - Capturing frames
+ *  - Streaming video
+ *  - etc.
+ */
+class EmulatedCameraDevice {
+public:
+    /* Constructs EmulatedCameraDevice instance.
+     * Param:
+     *  camera_hal - Emulated camera that implements the camera HAL API, and
+     *      manages (contains) this object.
+     */
+    explicit EmulatedCameraDevice(EmulatedCamera* camera_hal);
+
+    /* Destructs EmulatedCameraDevice instance. */
+    virtual ~EmulatedCameraDevice();
+
+    /***************************************************************************
+     * Emulated camera device abstract interface
+     **************************************************************************/
+
+public:
+    /* Connects to the camera device.
+     * This method must be called on an initialized instance of this class.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    virtual status_t connectDevice() = 0;
+
+    /* Disconnects from the camera device.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status. If this method is
+     *  called for already disconnected, or uninitialized instance of this class,
+     *  a successful status must be returned from this method. If this method is
+     *  called for an instance that is in the "started" state, this method must
+     *  return a failure.
+     */
+    virtual status_t disconnectDevice() = 0;
+
+    /* Starts the camera device.
+     * This method tells the camera device to start capturing frames of the given
+     * dimensions for the given pixel format. Note that this method doesn't start
+     * the delivery of the captured frames to the emulated camera. Call
+     * startDeliveringFrames method to start delivering frames. This method must
+     * be called on a connected instance of this class. If it is called on a
+     * disconnected instance, this method must return a failure.
+     * Param:
+     *  width, height - Frame dimensions to use when capturing video frames.
+     *  pix_fmt - Pixel format to use when capturing video frames.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    virtual status_t startDevice(int width, int height, uint32_t pix_fmt) = 0;
+
+    /* Stops the camera device.
+     * This method tells the camera device to stop capturing frames. Note that
+     * this method doesn't stop delivering frames to the emulated camera. Always
+     * call stopDeliveringFrames prior to calling this method.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status. If this method is
+     *  called for an object that is not capturing frames, or is disconnected,
+     *  or is uninitialized, a successful status must be returned from this
+     *  method.
+     */
+    virtual status_t stopDevice() = 0;
+
+    /***************************************************************************
+     * Emulated camera device public API
+     **************************************************************************/
+
+public:
+    /* Initializes EmulatedCameraDevice instance.
+     * Derived classes should override this method in order to cache static
+     * properties of the physical device (list of supported pixel formats, frame
+     * sizes, etc.) If this method is called on an already initialized instance,
+     * it must return a successful status.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    virtual status_t Initialize();
+
+    /* Starts delivering frames captured from the camera device.
+     * This method will start the worker thread that would be pulling frames from
+     * the camera device, and will deliver the pulled frames back to the emulated
+     * camera via onNextFrameAvailable callback. This method must be called on a
+     * connected instance of this class with a started camera device. If it is
+     * called on a disconnected instance, or camera device has not been started,
+     * this method must return a failure.
+     * Param:
+     *  one_burst - Controls how many frames should be delivered. If this
+     *      parameter is 'true', only one captured frame will be delivered to the
+     *      emulated camera. If this parameter is 'false', frames will keep
+     *      coming until stopDeliveringFrames method is called. Typically, this
+     *      parameter is set to 'true' only in order to obtain a single frame
+     *      that will be used as a "picture" in takePicture method of the
+     *      emulated camera.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    virtual status_t startDeliveringFrames(bool one_burst);
+
+    /* Stops delivering frames captured from the camera device.
+     * This method will stop the worker thread started by startDeliveringFrames.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    virtual status_t stopDeliveringFrames();
+
+    /* Gets current framebuffer, converted into preview frame format.
+     * This method must be called on a connected instance of this class with a
+     * started camera device. If it is called on a disconnected instance, or
+     * camera device has not been started, this method must return a failure.
+     * Note that this method should be called only after at least one frame has
+     * been captured and delivered. Otherwise it will return garbage in the
+     * preview frame buffer. Typically, this method shuld be called from
+     * onNextFrameAvailable callback.
+     * Param:
+     *  buffer - Buffer, large enough to contain the entire preview frame.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    virtual status_t getCurrentPreviewFrame(void* buffer);
+
+    /* Gets width of the frame obtained from the physical device.
+     * Return:
+     *  Width of the frame obtained from the physical device. Note that value
+     *  returned from this method is valid only in case if camera device has been
+     *  started.
+     */
+    inline int getFrameWidth() const
+    {
+        LOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
+        return mFrameWidth;
+    }
+
+    /* Gets height of the frame obtained from the physical device.
+     * Return:
+     *  Height of the frame obtained from the physical device. Note that value
+     *  returned from this method is valid only in case if camera device has been
+     *  started.
+     */
+    inline int getFrameHeight() const
+    {
+        LOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
+        return mFrameHeight;
+    }
+
+    /* Gets byte size of the current frame buffer.
+     * Return:
+     *  Byte size of the frame buffer. Note that value returned from this method
+     *  is valid only in case if camera device has been started.
+     */
+    inline size_t getFrameBufferSize() const
+    {
+        LOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
+        return mFrameBufferSize;
+    }
+
+    /* Gets number of pixels in the current frame buffer.
+     * Return:
+     *  Number of pixels in the frame buffer. Note that value returned from this
+     *  method is valid only in case if camera device has been started.
+     */
+    inline int getPixelNum() const
+    {
+        LOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
+        return mTotalPixels;
+    }
+
+    /* Gets pixel format of the frame that camera device streams to this class.
+     * Throughout camera framework, there are three different forms of pixel
+     * format representation:
+     *  - Original format, as reported by the actual camera device. Values for
+     *    this format are declared in bionic/libc/kernel/common/linux/videodev2.h
+     *  - String representation as defined in CameraParameters::PIXEL_FORMAT_XXX
+     *    strings in frameworks/base/include/camera/CameraParameters.h
+     *  - HAL_PIXEL_FORMAT_XXX format, as defined in system/core/include/system/graphics.h
+     * Since emulated camera device gets its data from the actual device, it gets
+     * pixel format in the original form. And that's the pixel format
+     * representation that will be returned from this method. HAL components will
+     * need to translate value returned from this method to the appropriate form.
+     * This method must be called only on started instance of this class, since
+     * it's applicable only when camera device is ready to stream frames.
+     * Param:
+     *  pix_fmt - Upon success contains the original pixel format.
+     * Return:
+     *  Current framebuffer's pixel format. Note that value returned from this
+     *  method is valid only in case if camera device has been started.
+     */
+    inline uint32_t getOriginalPixelFormat() const
+    {
+        LOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
+        return mPixelFormat;
+    }
+
+    /*
+     * State checkers.
+     */
+
+    inline bool isInitialized() const {
+        /* Instance is initialized when the worker thread has been successfuly
+         * created (but not necessarily started). */
+        return mWorkerThread.get() != NULL && mState != ECDS_CONSTRUCTED;
+    }
+    inline bool isConnected() const {
+        /* Instance is connected when its status is either"connected", or
+         * "started". */
+        return mState == ECDS_CONNECTED || mState == ECDS_STARTED;
+    }
+    inline bool isStarted() const {
+        return mState == ECDS_STARTED;
+    }
+
+    /****************************************************************************
+     * Emulated camera device private API
+     ***************************************************************************/
+protected:
+    /* Performs common validation and calculation of startDevice parameters.
+     * Param:
+     *  width, height, pix_fmt - Parameters passed to the startDevice method.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    virtual status_t commonStartDevice(int width, int height, uint32_t pix_fmt);
+
+    /* Performs common cleanup on stopDevice.
+     * This method will undo what commonStartDevice had done.
+     */
+    virtual void commonStopDevice();
+
+    /****************************************************************************
+     * Worker thread management.
+     * Typicaly when emulated camera device starts capturing frames from the
+     * actual device, it does that in a worker thread created in StartCapturing,
+     * and terminated in StopCapturing. Since this is such a typical scenario,
+     * it makes sence to encapsulate worker thread management in the base class
+     * for all emulated camera devices.
+     ***************************************************************************/
+
+protected:
+    /* Starts the worker thread.
+     * Typically, worker thread is started from startDeliveringFrames method of
+     * this class.
+     * Param:
+     *  one_burst - Controls how many times thread loop should run. If this
+     *      parameter is 'true', thread routine will run only once If this
+     *      parameter is 'false', thread routine will run until stopWorkerThread
+     *      method is called. See startDeliveringFrames for more info.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    virtual status_t startWorkerThread(bool one_burst);
+
+    /* Stops the worker thread.
+     * Note that this method will always wait for the worker thread to terminate.
+     * Typically, worker thread is started from stopDeliveringFrames method of
+     * this class.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    virtual status_t stopWorkerThread();
+
+    /* Implementation of the worker thread routine.
+     * In the default implementation of the worker thread routine we simply
+     * return 'false' forcing the thread loop to exit, and the thread to
+     * terminate. Derived class should override that method to provide there the
+     * actual frame delivery.
+     * Return:
+     *  true To continue thread loop (this method will be called again), or false
+     *  to exit the thread loop and to terminate the thread.
+     */
+    virtual bool inWorkerThread();
+
+    /* Encapsulates a worker thread used by the emulated camera device.
+     */
+    friend class WorkerThread;
+    class WorkerThread : public Thread {
+
+        /****************************************************************************
+         * Public API
+         ***************************************************************************/
+
+        public:
+            inline explicit WorkerThread(EmulatedCameraDevice* camera_dev)
+                : Thread(true),   // Callbacks may involve Java calls.
+                  mCameraDevice(camera_dev),
+                  mThreadControl(-1),
+                  mControlFD(-1)
+            {
+            }
+
+            inline ~WorkerThread()
+            {
+                LOGW_IF(mThreadControl >= 0 || mControlFD >= 0,
+                        "%s: Control FDs are opened in the destructor",
+                        __FUNCTION__);
+                if (mThreadControl >= 0) {
+                    close(mThreadControl);
+                }
+                if (mControlFD >= 0) {
+                    close(mControlFD);
+                }
+            }
+
+            /* Starts the thread
+             * Param:
+             *  one_burst - Controls how many times thread loop should run. If
+             *      this parameter is 'true', thread routine will run only once
+             *      If this parameter is 'false', thread routine will run until
+             *      stopThread method is called. See startWorkerThread for more
+             *      info.
+             * Return:
+             *  NO_ERROR on success, or an appropriate error status.
+             */
+            inline status_t startThread(bool one_burst)
+            {
+                mOneBurst = one_burst;
+                return run(NULL, ANDROID_PRIORITY_URGENT_DISPLAY, 0);
+            }
+
+            /* Overriden base class method.
+             * It is overriden in order to provide one-time initialization just
+             * prior to starting the thread routine.
+             */
+            status_t readyToRun();
+
+            /* Stops the thread. */
+            status_t stopThread();
+
+            /* Values returned from the Select method of this class. */
+            enum SelectRes {
+                /* A timeout has occurred. */
+                TIMEOUT,
+                /* Data are available for read on the provided FD. */
+                READY,
+                /* Thread exit request has been received. */
+                EXIT_THREAD,
+                /* An error has occurred. */
+                ERROR
+            };
+
+            /* Select on an FD event, keeping in mind thread exit message.
+             * Param:
+             *  fd - File descriptor on which to wait for an event. This
+             *      parameter may be negative. If it is negative this method will
+             *      only wait on a control message to the thread.
+             *  timeout - Timeout in microseconds. 0 indicates no timeout (wait
+             *      forever).
+             * Return:
+             *  See SelectRes enum comments.
+             */
+            SelectRes Select(int fd, int timeout);
+
+        /****************************************************************************
+         * Private API
+         ***************************************************************************/
+
+        private:
+            /* Implements abstract method of the base Thread class. */
+            bool threadLoop()
+            {
+                /* Simply dispatch the call to the containing camera device. */
+                if (mCameraDevice->inWorkerThread()) {
+                    /* Respect "one burst" parameter (see startThread). */
+                    return !mOneBurst;
+                } else {
+                    return false;
+                }
+            }
+
+            /* Containing camera device object. */
+            EmulatedCameraDevice*   mCameraDevice;
+
+            /* FD that is used to send control messages into the thread. */
+            int                     mThreadControl;
+
+            /* FD that thread uses to receive control messages. */
+            int                     mControlFD;
+
+            /* Controls number of times the thread loop runs.
+             * See startThread for more information. */
+            bool                    mOneBurst;
+
+            /* Enumerates control messages that can be sent into the thread. */
+            enum ControlMessage {
+                /* Stop the thread. */
+                THREAD_STOP
+            };
+    };
+
+    /* Worker thread accessor. */
+    inline WorkerThread* getWorkerThread() const
+    {
+        return mWorkerThread.get();
+    }
+
+    /****************************************************************************
+     * Data members
+     ***************************************************************************/
+
+protected:
+    /* Locks this instance for parameters, state, etc. change. */
+    Mutex                       mObjectLock;
+
+    /* Worker thread that is used in frame capturing. */
+    sp<WorkerThread>            mWorkerThread;
+
+    /* Timestamp of the current frame. */
+    nsecs_t                     mCurFrameTimestamp;
+
+    /* Emulated camera object containing this instance. */
+    EmulatedCamera*             mCameraHAL;
+
+    /* Framebuffer containing the current frame. */
+    uint8_t*                    mCurrentFrame;
+
+    /*
+     * Framebuffer properties.
+     */
+
+    /* Byte size of the framebuffer. */
+    size_t                      mFrameBufferSize;
+
+    /* Original pixel format (one of the V4L2_PIX_FMT_XXX values, as defined in
+     * bionic/libc/kernel/common/linux/videodev2.h */
+    uint32_t                    mPixelFormat;
+
+    /* Frame width */
+    int                         mFrameWidth;
+
+    /* Frame height */
+    int                         mFrameHeight;
+
+    /* Total number of pixels */
+    int                         mTotalPixels;
+
+    /* Defines possible states of the emulated camera device object.
+     */
+    enum EmulatedCameraDeviceState {
+        /* Object has been constructed. */
+        ECDS_CONSTRUCTED,
+        /* Object has been initialized. */
+        ECDS_INITIALIZED,
+        /* Object has been connected to the physical device. */
+        ECDS_CONNECTED,
+        /* Camera device has been started. */
+        ECDS_STARTED,
+    };
+
+    /* Object state. */
+    EmulatedCameraDeviceState   mState;
+};
+
+}; /* namespace android */
+
+#endif  /* HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H */
diff --git a/tools/emulator/system/camera/EmulatedCameraFactory.cpp b/tools/emulator/system/camera/EmulatedCameraFactory.cpp
new file mode 100755
index 0000000..5c5c5de
--- /dev/null
+++ b/tools/emulator/system/camera/EmulatedCameraFactory.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Contains implementation of a class EmulatedCameraFactory that manages cameras
+ * available for emulation.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera_Factory"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include "EmulatedQemuCamera.h"
+#include "EmulatedFakeCamera.h"
+#include "EmulatedCameraFactory.h"
+
+extern camera_module_t HAL_MODULE_INFO_SYM;
+
+/* A global instance of EmulatedCameraFactory is statically instantiated and
+ * initialized when camera emulation HAL is loaded.
+ */
+android::EmulatedCameraFactory  gEmulatedCameraFactory;
+
+namespace android {
+
+EmulatedCameraFactory::EmulatedCameraFactory()
+        : mQemuClient(),
+          mEmulatedCameras(NULL),
+          mEmulatedCameraNum(0),
+          mFakeCameraID(-1),
+          mConstructedOK(false)
+
+{
+    /* Connect to the factory service in the emulator, and create Qemu cameras. */
+    if (mQemuClient.connectClient(NULL) == NO_ERROR) {
+        /* Connection has succeeded. Create emulated cameras for each camera
+         * device, reported by the service. */
+        createQemuCameras();
+    }
+
+    if (isFakeCameraEmulationOn()) {
+        /* ID fake camera with the number of created 'qemud' cameras. */
+        mFakeCameraID = mEmulatedCameraNum;
+        mEmulatedCameraNum++;
+
+        /* Make sure that array is allocated (in case there were no 'qemu'
+         * cameras created. */
+        if (mEmulatedCameras == NULL) {
+            mEmulatedCameras = new EmulatedCamera*[mEmulatedCameraNum];
+            if (mEmulatedCameras == NULL) {
+                LOGE("%s: Unable to allocate emulated camera array for %d entries",
+                     __FUNCTION__, mEmulatedCameraNum);
+                return;
+            }
+            memset(mEmulatedCameras, 0, mEmulatedCameraNum * sizeof(EmulatedCamera*));
+        }
+
+        /* Create, and initialize the fake camera */
+        mEmulatedCameras[mFakeCameraID] =
+            new EmulatedFakeCamera(mFakeCameraID, &HAL_MODULE_INFO_SYM.common);
+        if (mEmulatedCameras[mFakeCameraID] != NULL) {
+            if (mEmulatedCameras[mFakeCameraID]->Initialize() != NO_ERROR) {
+                delete mEmulatedCameras[mFakeCameraID];
+                mEmulatedCameras--;
+                mFakeCameraID = -1;
+            }
+        } else {
+            mEmulatedCameras--;
+            mFakeCameraID = -1;
+            LOGE("%s: Unable to instantiate fake camera class", __FUNCTION__);
+        }
+    } else {
+        LOGD("Fake camera emulation is disabled.");
+    }
+
+    LOGV("%d cameras are being emulated. Fake camera ID is %d",
+         mEmulatedCameraNum, mFakeCameraID);
+
+    mConstructedOK = true;
+}
+
+EmulatedCameraFactory::~EmulatedCameraFactory()
+{
+    if (mEmulatedCameras != NULL) {
+        for (int n = 0; n < mEmulatedCameraNum; n++) {
+            if (mEmulatedCameras[n] != NULL) {
+                delete mEmulatedCameras[n];
+            }
+        }
+        delete[] mEmulatedCameras;
+    }
+}
+
+/****************************************************************************
+ * Camera HAL API handlers.
+ *
+ * Each handler simply verifies existence of an appropriate EmulatedCamera
+ * instance, and dispatches the call to that instance.
+ *
+ ***************************************************************************/
+
+int EmulatedCameraFactory::cameraDeviceOpen(int camera_id, hw_device_t** device)
+{
+    LOGV("%s: id = %d", __FUNCTION__, camera_id);
+
+    *device = NULL;
+
+    if (!isConstructedOK()) {
+        LOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) {
+        LOGE("%s: Camera id %d is out of bounds (%d)",
+             __FUNCTION__, camera_id, getEmulatedCameraNum());
+        return -EINVAL;
+    }
+
+    return mEmulatedCameras[camera_id]->connectCamera(device);
+}
+
+int EmulatedCameraFactory::getCameraInfo(int camera_id, struct camera_info* info)
+{
+    LOGV("%s: id = %d", __FUNCTION__, camera_id);
+
+    if (!isConstructedOK()) {
+        LOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) {
+        LOGE("%s: Camera id %d is out of bounds (%d)",
+             __FUNCTION__, camera_id, getEmulatedCameraNum());
+        return -EINVAL;
+    }
+
+    return mEmulatedCameras[camera_id]->getCameraInfo(info);
+}
+
+/****************************************************************************
+ * Camera HAL API callbacks.
+ ***************************************************************************/
+
+int EmulatedCameraFactory::device_open(const hw_module_t* module,
+                                       const char* name,
+                                       hw_device_t** device)
+{
+    /*
+     * Simply verify the parameters, and dispatch the call inside the
+     * EmulatedCameraFactory instance.
+     */
+
+    if (module != &HAL_MODULE_INFO_SYM.common) {
+        LOGE("%s: Invalid module %p expected %p",
+             __FUNCTION__, module, &HAL_MODULE_INFO_SYM.common);
+        return -EINVAL;
+    }
+    if (name == NULL) {
+        LOGE("%s: NULL name is not expected here", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    return gEmulatedCameraFactory.cameraDeviceOpen(atoi(name), device);
+}
+
+int EmulatedCameraFactory::get_number_of_cameras(void)
+{
+    return gEmulatedCameraFactory.getEmulatedCameraNum();
+}
+
+int EmulatedCameraFactory::get_camera_info(int camera_id,
+                                           struct camera_info* info)
+{
+    return gEmulatedCameraFactory.getCameraInfo(camera_id, info);
+}
+
+/********************************************************************************
+ * Internal API
+ *******************************************************************************/
+
+/*
+ * Camera information tokens passed in response to the "list" factory query.
+ */
+
+/* Device name token. */
+static const char lListNameToken[]    = "name=";
+/* Frame dimensions token. */
+static const char lListDimsToken[]    = "framedims=";
+/* Facing direction token. */
+static const char lListDirToken[]     = "dir=";
+
+void EmulatedCameraFactory::createQemuCameras()
+{
+    /* Obtain camera list. */
+    char* camera_list = NULL;
+    status_t res = mQemuClient.listCameras(&camera_list);
+    /* Empty list, or list containing just an EOL means that there were no
+     * connected cameras found. */
+    if (res != NO_ERROR || camera_list == NULL || *camera_list == '\0' ||
+        *camera_list == '\n') {
+        if (camera_list != NULL) {
+            free(camera_list);
+        }
+        return;
+    }
+
+    /*
+     * Calculate number of connected cameras. Number of EOLs in the camera list
+     * is the number of the connected cameras.
+     */
+
+    int num = 0;
+    const char* eol = strchr(camera_list, '\n');
+    while (eol != NULL) {
+        num++;
+        eol = strchr(eol + 1, '\n');
+    }
+
+    /* Allocate the array for emulated camera instances. Note that we allocate
+     * one more entry for the fake camera emulation. */
+    mEmulatedCameras = new EmulatedCamera*[num + 1];
+    if (mEmulatedCameras == NULL) {
+        LOGE("%s: Unable to allocate emulated camera array for %d entries",
+             __FUNCTION__, num + 1);
+        free(camera_list);
+        return;
+    }
+    memset(mEmulatedCameras, 0, sizeof(EmulatedCamera*) * (num + 1));
+
+    /*
+     * Iterate the list, creating, and initializin emulated qemu cameras for each
+     * entry (line) in the list.
+     */
+
+    int index = 0;
+    char* cur_entry = camera_list;
+    while (cur_entry != NULL && *cur_entry != '\0' && index < num) {
+        /* Find the end of the current camera entry, and terminate it with zero
+         * for simpler string manipulation. */
+        char* next_entry = strchr(cur_entry, '\n');
+        if (next_entry != NULL) {
+            *next_entry = '\0';
+            next_entry++;   // Start of the next entry.
+        }
+
+        /* Find 'name', 'framedims', and 'dir' tokens that are required here. */
+        char* name_start = strstr(cur_entry, lListNameToken);
+        char* dim_start = strstr(cur_entry, lListDimsToken);
+        char* dir_start = strstr(cur_entry, lListDirToken);
+        if (name_start != NULL && dim_start != NULL && dir_start != NULL) {
+            /* Advance to the token values. */
+            name_start += strlen(lListNameToken);
+            dim_start += strlen(lListDimsToken);
+            dir_start += strlen(lListDirToken);
+
+            /* Terminate token values with zero. */
+            char* s = strchr(name_start, ' ');
+            if (s != NULL) {
+                *s = '\0';
+            }
+            s = strchr(dim_start, ' ');
+            if (s != NULL) {
+                *s = '\0';
+            }
+            s = strchr(dir_start, ' ');
+            if (s != NULL) {
+                *s = '\0';
+            }
+
+            /* Create and initialize qemu camera. */
+            EmulatedQemuCamera* qemu_cam =
+                new EmulatedQemuCamera(index, &HAL_MODULE_INFO_SYM.common);
+            if (NULL != qemu_cam) {
+                res = qemu_cam->Initialize(name_start, dim_start, dir_start);
+                if (res == NO_ERROR) {
+                    mEmulatedCameras[index] = qemu_cam;
+                    index++;
+                } else {
+                    delete qemu_cam;
+                }
+            } else {
+                LOGE("%s: Unable to instantiate EmulatedQemuCamera",
+                     __FUNCTION__);
+            }
+        } else {
+            LOGW("%s: Bad camera information: %s", __FUNCTION__, cur_entry);
+        }
+
+        cur_entry = next_entry;
+    }
+
+    mEmulatedCameraNum = index;
+}
+
+bool EmulatedCameraFactory::isFakeCameraEmulationOn()
+{
+    /* Defined by 'qemu.sf.fake_camera' boot property: If property is there
+     * and contains 'off', fake camera emulation is disabled. */
+    char prop[PROPERTY_VALUE_MAX];
+    if (property_get("qemu.sf.fake_camera", prop, NULL) <= 0 ||
+        strcmp(prop, "off")) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+/********************************************************************************
+ * Initializer for the static member structure.
+ *******************************************************************************/
+
+/* Entry point for camera HAL API. */
+struct hw_module_methods_t EmulatedCameraFactory::mCameraModuleMethods = {
+    open: EmulatedCameraFactory::device_open
+};
+
+}; /* namespace android */
diff --git a/tools/emulator/system/camera/emulated_camera_factory.h b/tools/emulator/system/camera/EmulatedCameraFactory.h
old mode 100644
new mode 100755
similarity index 79%
rename from tools/emulator/system/camera/emulated_camera_factory.h
rename to tools/emulator/system/camera/EmulatedCameraFactory.h
index 68d0ed0..19745a3
--- a/tools/emulator/system/camera/emulated_camera_factory.h
+++ b/tools/emulator/system/camera/EmulatedCameraFactory.h
@@ -17,7 +17,8 @@
 #ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA_FACTORY_H
 #define HW_EMULATOR_CAMERA_EMULATED_CAMERA_FACTORY_H
 
-#include "emulated_camera.h"
+#include "EmulatedCamera.h"
+#include "QemuClient.h"
 
 namespace android {
 
@@ -49,7 +50,7 @@
     /* Constructs EmulatedCameraFactory instance.
      * In this constructor the factory will create and initialize a list of
      * emulated cameras. All errors that occur on this constructor are reported
-     * via constructed_ok_ data member of this class.
+     * via mConstructedOK data member of this class.
      */
     EmulatedCameraFactory();
 
@@ -64,12 +65,12 @@
     /* Opens (connects to) a camera device.
      * This method is called in response to hw_module_methods_t::open callback.
      */
-    int CameraDeviceOpen(int camera_id, hw_device_t** device);
+    int cameraDeviceOpen(int camera_id, hw_device_t** device);
 
     /* Gets emulated camera information.
      * This method is called in response to camera_module_t::get_camera_info callback.
      */
-    int GetCameraInfo(int camera_id, struct camera_info *info);
+    int getCameraInfo(int camera_id, struct camera_info *info);
 
     /****************************************************************************
      * Camera HAL API callbacks.
@@ -93,16 +94,29 @@
      ***************************************************************************/
 
 public:
+
+    /* Gets fake camera orientation. */
+    int getFakeCameraOrientation() {
+        /* TODO: Have a boot property that controls that. */
+        return 90;
+    }
+
+    /* Gets qemu camera orientation. */
+    int getQemuCameraOrientation() {
+        /* TODO: Have a boot property that controls that. */
+        return 270;
+    }
+
     /* Gets number of emulated cameras.
      */
-    int emulated_camera_num() const {
-        return emulated_camera_num_;
+    int getEmulatedCameraNum() const {
+        return mEmulatedCameraNum;
     }
 
     /* Checks whether or not the constructor has succeeded.
      */
-    bool constructed_ok() const {
-        return constructed_ok_;
+    bool isConstructedOK() const {
+        return mConstructedOK;
     }
 
     /****************************************************************************
@@ -110,50 +124,44 @@
      ***************************************************************************/
 
 private:
-    /* Gets number of cameras that are available via 'camera' service in the
-     * emulator.
-     * Return:
-     *  Number of 'qemud' cameras reported by the 'camera' service, or -1 on
-     *  failure.
-     */
-    int GetQemudCameraNumber();
-
     /* Populates emulated cameras array with cameras that are available via
      * 'camera' service in the emulator. For each such camera and instance of
-     * the EmulatedCameraQemud will be created and added to the emulated_cameras_
+     * the EmulatedCameraQemud will be created and added to the mEmulatedCameras
      * array.
-     * Param:
-     *  num - Number of cameras returned by GetQemudCameraNumber method.
-     * Return:
-     *  true on success, or false on failure.
      */
-    bool CreateQemudCameras(int num);
+    void createQemuCameras();
+
+    /* Checks if fake camera emulation is on. */
+    bool isFakeCameraEmulationOn();
 
     /****************************************************************************
      * Data members.
      ***************************************************************************/
 
 private:
+    /* Connection to the camera service in the emulator. */
+    FactoryQemuClient   mQemuClient;
+
     /* Array of cameras available for the emulation. */
-    EmulatedCamera**    emulated_cameras_;
+    EmulatedCamera**    mEmulatedCameras;
 
     /* Number of emulated cameras (including the fake one). */
-    int                 emulated_camera_num_;
+    int                 mEmulatedCameraNum;
 
     /* Fake camera ID. */
-    int                 fake_camera_id_;
+    int                 mFakeCameraID;
 
     /* Flags whether or not constructor has succeeded. */
-    bool                constructed_ok_;
+    bool                mConstructedOK;
 
 public:
     /* Contains device open entry point, as required by HAL API. */
-    static struct hw_module_methods_t   camera_module_methods_;
+    static struct hw_module_methods_t   mCameraModuleMethods;
 };
 
 }; /* namespace android */
 
 /* References the global EmulatedCameraFactory instance. */
-extern android::EmulatedCameraFactory   _emulated_camera_factory;
+extern android::EmulatedCameraFactory   gEmulatedCameraFactory;
 
 #endif  /* HW_EMULATOR_CAMERA_EMULATED_CAMERA_FACTORY_H */
diff --git a/tools/emulator/system/camera/emulated_camera_hal.cpp b/tools/emulator/system/camera/EmulatedCameraHal.cpp
old mode 100644
new mode 100755
similarity index 92%
rename from tools/emulator/system/camera/emulated_camera_hal.cpp
rename to tools/emulator/system/camera/EmulatedCameraHal.cpp
index e6d565f..7f3f7b8
--- a/tools/emulator/system/camera/emulated_camera_hal.cpp
+++ b/tools/emulator/system/camera/EmulatedCameraHal.cpp
@@ -23,7 +23,7 @@
  * managing emulated cameras.
  */
 
-#include "emulated_camera_factory.h"
+#include "EmulatedCameraFactory.h"
 
 /*
  * Required HAL header.
@@ -36,7 +36,7 @@
          id:            CAMERA_HARDWARE_MODULE_ID,
          name:          "Emulated Camera Module",
          author:        "The Android Open Source Project",
-         methods:       &android::EmulatedCameraFactory::camera_module_methods_,
+         methods:       &android::EmulatedCameraFactory::mCameraModuleMethods,
          dso:           NULL,
          reserved:      {0},
     },
diff --git a/tools/emulator/system/camera/emulated_fake_camera.cpp b/tools/emulator/system/camera/EmulatedFakeCamera.cpp
old mode 100644
new mode 100755
similarity index 61%
rename from tools/emulator/system/camera/emulated_fake_camera.cpp
rename to tools/emulator/system/camera/EmulatedFakeCamera.cpp
index f1861a4..d82fd78
--- a/tools/emulator/system/camera/emulated_fake_camera.cpp
+++ b/tools/emulator/system/camera/EmulatedFakeCamera.cpp
@@ -22,13 +22,15 @@
 #define LOG_NDEBUG 0
 #define LOG_TAG "EmulatedCamera_FakeCamera"
 #include <cutils/log.h>
-#include "emulated_fake_camera.h"
+#include <cutils/properties.h>
+#include "EmulatedFakeCamera.h"
+#include "EmulatedCameraFactory.h"
 
 namespace android {
 
 EmulatedFakeCamera::EmulatedFakeCamera(int cameraId, struct hw_module_t* module)
         : EmulatedCamera(cameraId, module),
-          fake_camera_dev_(this)
+          mFakeCameraDevice(this)
 {
 }
 
@@ -42,13 +44,22 @@
 
 status_t EmulatedFakeCamera::Initialize()
 {
-    LOGV("%s", __FUNCTION__);
-
-    status_t res = fake_camera_dev_.Initialize();
+    status_t res = mFakeCameraDevice.Initialize();
     if (res != NO_ERROR) {
         return res;
     }
 
+    /* Fake camera facing is defined by the qemu.sf.fake_camera boot property. */
+    char prop[PROPERTY_VALUE_MAX];
+    property_get("qemu.sf.fake_camera", prop, EmulatedCamera::FACING_BACK);
+    const char* facing = prop;
+
+    mParameters.set(EmulatedCamera::FACING_KEY, facing);
+    LOGD("%s: Fake camera is facing %s", __FUNCTION__, facing);
+
+    mParameters.set(EmulatedCamera::ORIENTATION_KEY,
+                    gEmulatedCameraFactory.getFakeCameraOrientation());
+
     res = EmulatedCamera::Initialize();
     if (res != NO_ERROR) {
         return res;
@@ -58,24 +69,17 @@
      * Parameters provided by the camera device.
      */
 
-    parameters_.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "640x480");
-    parameters_.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "640x480");
-    parameters_.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
-                    CameraParameters::PIXEL_FORMAT_YUV420P);
-    parameters_.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
-                    CameraParameters::PIXEL_FORMAT_YUV420P);
-
-    parameters_.setPreviewFrameRate(25);
-    parameters_.setPreviewSize(640, 480);
-    parameters_.setPictureSize(640, 480);
-    parameters_.setPictureFormat(CameraParameters::PIXEL_FORMAT_YUV420P);
+    mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "640x480");
+    mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "640x480");
+    mParameters.setPreviewSize(640, 480);
+    mParameters.setPictureSize(640, 480);
 
     return NO_ERROR;
 }
 
-EmulatedCameraDevice* EmulatedFakeCamera::GetCameraDevice()
+EmulatedCameraDevice* EmulatedFakeCamera::getCameraDevice()
 {
-    return &fake_camera_dev_;
+    return &mFakeCameraDevice;
 }
 
 };  /* namespace android */
diff --git a/tools/emulator/system/camera/emulated_fake_camera.h b/tools/emulator/system/camera/EmulatedFakeCamera.h
old mode 100644
new mode 100755
similarity index 85%
rename from tools/emulator/system/camera/emulated_fake_camera.h
rename to tools/emulator/system/camera/EmulatedFakeCamera.h
index 228b8fd..3debe9e
--- a/tools/emulator/system/camera/emulated_fake_camera.h
+++ b/tools/emulator/system/camera/EmulatedFakeCamera.h
@@ -23,8 +23,8 @@
  * for EmulatedFakeCameraDevice instance.
  */
 
-#include "emulated_camera.h"
-#include "emulated_fake_camera_device.h"
+#include "EmulatedCamera.h"
+#include "EmulatedFakeCameraDevice.h"
 
 namespace android {
 
@@ -45,11 +45,7 @@
      ***************************************************************************/
 
 public:
-    /* Initializes EmulatedFakeCamera instance.
-     * The contained EmulatedFakeCameraDevice will be initialized in this method.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error statsu on failure.
-     */
+    /* Initializes EmulatedFakeCamera instance. */
      status_t Initialize();
 
     /****************************************************************************
@@ -59,7 +55,7 @@
 protected:
     /* Gets emulated camera device ised by this instance of the emulated camera.
      */
-    EmulatedCameraDevice* GetCameraDevice();
+    EmulatedCameraDevice* getCameraDevice();
 
     /****************************************************************************
      * Data memebers.
@@ -67,7 +63,7 @@
 
 protected:
     /* Contained fake camera device object. */
-    EmulatedFakeCameraDevice    fake_camera_dev_;
+    EmulatedFakeCameraDevice    mFakeCameraDevice;
 };
 
 }; /* namespace android */
diff --git a/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp b/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp
new file mode 100755
index 0000000..53a5b1b
--- /dev/null
+++ b/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Contains implementation of a class EmulatedFakeCameraDevice that encapsulates
+ * fake camera device.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera_FakeDevice"
+#include <cutils/log.h>
+#include "EmulatedFakeCamera.h"
+#include "EmulatedFakeCameraDevice.h"
+
+namespace android {
+
+EmulatedFakeCameraDevice::EmulatedFakeCameraDevice(EmulatedFakeCamera* camera_hal)
+    : EmulatedCameraDevice(camera_hal),
+      mBlackYUV(kBlack32),
+      mWhiteYUV(kWhite32),
+      mRedYUV(kRed8),
+      mGreenYUV(kGreen8),
+      mBlueYUV(kBlue8),
+      mLastRedrawn(0),
+      mCheckX(0),
+      mCheckY(0),
+      mCcounter(0)
+#if EFCD_ROTATE_FRAME
+      , mLastRotatedAt(0),
+        mCurrentFrameType(0),
+        mCurrentColor(&mWhiteYUV)
+#endif  // EFCD_ROTATE_FRAME
+{
+}
+
+EmulatedFakeCameraDevice::~EmulatedFakeCameraDevice()
+{
+}
+
+/****************************************************************************
+ * Emulated camera device abstract interface implementation.
+ ***************************************************************************/
+
+status_t EmulatedFakeCameraDevice::connectDevice()
+{
+    LOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock locker(&mObjectLock);
+    if (!isInitialized()) {
+        LOGE("%s: Fake camera device is not initialized.", __FUNCTION__);
+        return EINVAL;
+    }
+    if (isConnected()) {
+        LOGW("%s: Fake camera device is already connected.", __FUNCTION__);
+        return NO_ERROR;
+    }
+
+    /* There is no device to connect to. */
+    mState = ECDS_CONNECTED;
+
+    return NO_ERROR;
+}
+
+status_t EmulatedFakeCameraDevice::disconnectDevice()
+{
+    LOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock locker(&mObjectLock);
+    if (!isConnected()) {
+        LOGW("%s: Fake camera device is already disconnected.", __FUNCTION__);
+        return NO_ERROR;
+    }
+    if (isStarted()) {
+        LOGE("%s: Cannot disconnect from the started device.", __FUNCTION__);
+        return EINVAL;
+    }
+
+    /* There is no device to disconnect from. */
+    mState = ECDS_INITIALIZED;
+
+    return NO_ERROR;
+}
+
+status_t EmulatedFakeCameraDevice::startDevice(int width,
+                                               int height,
+                                               uint32_t pix_fmt)
+{
+    LOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock locker(&mObjectLock);
+    if (!isConnected()) {
+        LOGE("%s: Fake camera device is not connected.", __FUNCTION__);
+        return EINVAL;
+    }
+    if (isStarted()) {
+        LOGE("%s: Fake camera device is already started.", __FUNCTION__);
+        return EINVAL;
+    }
+
+    /* Initialize the base class. */
+    const status_t res =
+        EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt);
+    if (res == NO_ERROR) {
+        /* Calculate U/V panes inside the framebuffer. */
+        switch (mPixelFormat) {
+            case V4L2_PIX_FMT_YVU420:
+                mFrameV = mCurrentFrame + mTotalPixels;
+                mFrameU = mFrameU + mTotalPixels / 4;
+                mUVStep = 1;
+                mUVTotalNum = mTotalPixels / 4;
+                break;
+
+            case V4L2_PIX_FMT_YUV420:
+                mFrameU = mCurrentFrame + mTotalPixels;
+                mFrameV = mFrameU + mTotalPixels / 4;
+                mUVStep = 1;
+                mUVTotalNum = mTotalPixels / 4;
+                break;
+
+            case V4L2_PIX_FMT_NV21:
+                /* Interleaved UV pane, V first. */
+                mFrameV = mCurrentFrame + mTotalPixels;
+                mFrameU = mFrameV + 1;
+                mUVStep = 2;
+                mUVTotalNum = mTotalPixels / 4;
+                break;
+
+            case V4L2_PIX_FMT_NV12:
+                /* Interleaved UV pane, U first. */
+                mFrameU = mCurrentFrame + mTotalPixels;
+                mFrameV = mFrameU + 1;
+                mUVStep = 2;
+                mUVTotalNum = mTotalPixels / 4;
+                break;
+
+            default:
+                LOGE("%s: Unknown pixel format %.4s", __FUNCTION__,
+                     reinterpret_cast<const char*>(&mPixelFormat));
+                return EINVAL;
+        }
+        /* Number of items in a single row inside U/V panes. */
+        mUVInRow = (width / 2) * mUVStep;
+        mState = ECDS_STARTED;
+    } else {
+        LOGE("%s: commonStartDevice failed", __FUNCTION__);
+    }
+
+    return res;
+}
+
+status_t EmulatedFakeCameraDevice::stopDevice()
+{
+    LOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock locker(&mObjectLock);
+    if (!isStarted()) {
+        LOGW("%s: Fake camera device is not started.", __FUNCTION__);
+        return NO_ERROR;
+    }
+
+    mFrameU = mFrameV = NULL;
+    EmulatedCameraDevice::commonStopDevice();
+    mState = ECDS_CONNECTED;
+
+    return NO_ERROR;
+}
+
+/****************************************************************************
+ * Worker thread management overrides.
+ ***************************************************************************/
+
+bool EmulatedFakeCameraDevice::inWorkerThread()
+{
+    /* Wait till FPS timeout expires, or thread exit message is received. */
+    WorkerThread::SelectRes res =
+        getWorkerThread()->Select(-1, 1000000 / mEmulatedFPS);
+    if (res == WorkerThread::EXIT_THREAD) {
+        LOGV("%s: Worker thread has been terminated.", __FUNCTION__);
+        return false;
+    }
+
+    /* Lets see if we need to generate a new frame. */
+    if ((systemTime(SYSTEM_TIME_MONOTONIC) - mLastRedrawn) >= mRedrawAfter) {
+        /*
+         * Time to generate a new frame.
+         */
+
+#if EFCD_ROTATE_FRAME
+        const int frame_type = rotateFrame();
+        switch (frame_type) {
+            case 0:
+                drawCheckerboard();
+                break;
+            case 1:
+                drawStripes();
+                break;
+            case 2:
+                drawSolid(mCurrentColor);
+                break;
+        }
+#else
+        /* Draw the checker board. */
+        drawCheckerboard();
+
+#endif  // EFCD_ROTATE_FRAME
+
+        mLastRedrawn = systemTime(SYSTEM_TIME_MONOTONIC);
+    }
+
+    /* Timestamp the current frame, and notify the camera HAL about new frame. */
+    mCurFrameTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+    mCameraHAL->onNextFrameAvailable(mCurrentFrame, mCurFrameTimestamp, this);
+
+    return true;
+}
+
+/****************************************************************************
+ * Fake camera device private API
+ ***************************************************************************/
+
+void EmulatedFakeCameraDevice::drawCheckerboard()
+{
+    const int size = mFrameWidth / 10;
+    bool black = true;
+
+    if((mCheckX / size) & 1)
+        black = false;
+    if((mCheckY / size) & 1)
+        black = !black;
+
+    int county = mCheckY % size;
+    int checkxremainder = mCheckX % size;
+    uint8_t* Y = mCurrentFrame;
+    uint8_t* U_pos = mFrameU;
+    uint8_t* V_pos = mFrameV;
+    uint8_t* U = U_pos;
+    uint8_t* V = V_pos;
+
+    for(int y = 0; y < mFrameHeight; y++) {
+        int countx = checkxremainder;
+        bool current = black;
+        for(int x = 0; x < mFrameWidth; x += 2) {
+            if (current) {
+                mBlackYUV.get(Y, U, V);
+            } else {
+                mWhiteYUV.get(Y, U, V);
+            }
+            Y[1] = *Y;
+            Y += 2; U += mUVStep; V += mUVStep;
+            countx += 2;
+            if(countx >= size) {
+                countx = 0;
+                current = !current;
+            }
+        }
+        if (y & 0x1) {
+            U_pos = U;
+            V_pos = V;
+        } else {
+            U = U_pos;
+            V = V_pos;
+        }
+        if(county++ >= size) {
+            county = 0;
+            black = !black;
+        }
+    }
+    mCheckX += 3;
+    mCheckY++;
+
+    /* Run the square. */
+    int sqx = ((mCcounter * 3) & 255);
+    if(sqx > 128) sqx = 255 - sqx;
+    int sqy = ((mCcounter * 5) & 255);
+    if(sqy > 128) sqy = 255 - sqy;
+    const int sqsize = mFrameWidth / 10;
+    drawSquare(sqx * sqsize / 32, sqy * sqsize / 32, (sqsize * 5) >> 1,
+               (mCcounter & 0x100) ? &mRedYUV : &mGreenYUV);
+    mCcounter++;
+}
+
+void EmulatedFakeCameraDevice::drawSquare(int x,
+                                          int y,
+                                          int size,
+                                          const YUVPixel* color)
+{
+    const int square_xstop = min(mFrameWidth, x + size);
+    const int square_ystop = min(mFrameHeight, y + size);
+    uint8_t* Y_pos = mCurrentFrame + y * mFrameWidth + x;
+
+    // Draw the square.
+    for (; y < square_ystop; y++) {
+        const int iUV = (y / 2) * mUVInRow + (x / 2) * mUVStep;
+        uint8_t* sqU = mFrameU + iUV;
+        uint8_t* sqV = mFrameV + iUV;
+        uint8_t* sqY = Y_pos;
+        for (int i = x; i < square_xstop; i += 2) {
+            color->get(sqY, sqU, sqV);
+            sqY[1] = *sqY;
+            sqY += 2; sqU += mUVStep; sqV += mUVStep;
+        }
+        Y_pos += mFrameWidth;
+    }
+}
+
+#if EFCD_ROTATE_FRAME
+
+void EmulatedFakeCameraDevice::drawSolid(YUVPixel* color)
+{
+    /* All Ys are the same. */
+    memset(mCurrentFrame, color->Y, mTotalPixels);
+
+    /* Fill U, and V panes. */
+    uint8_t* U = mFrameU;
+    uint8_t* V = mFrameV;
+    for (int k = 0; k < mUVTotalNum; k++, U += mUVStep, V += mUVStep) {
+        *U = color->U;
+        *V = color->V;
+    }
+}
+
+void EmulatedFakeCameraDevice::drawStripes()
+{
+    /* Divide frame into 4 stripes. */
+    const int change_color_at = mFrameHeight / 4;
+    const int each_in_row = mUVInRow / mUVStep;
+    uint8_t* pY = mCurrentFrame;
+    for (int y = 0; y < mFrameHeight; y++, pY += mFrameWidth) {
+        /* Select the color. */
+        YUVPixel* color;
+        const int color_index = y / change_color_at;
+        if (color_index == 0) {
+            /* White stripe on top. */
+            color = &mWhiteYUV;
+        } else if (color_index == 1) {
+            /* Then the red stripe. */
+            color = &mRedYUV;
+        } else if (color_index == 2) {
+            /* Then the green stripe. */
+            color = &mGreenYUV;
+        } else {
+            /* And the blue stripe at the bottom. */
+            color = &mBlueYUV;
+        }
+
+        /* All Ys at the row are the same. */
+        memset(pY, color->Y, mFrameWidth);
+
+        /* Offset of the current row inside U/V panes. */
+        const int uv_off = (y / 2) * mUVInRow;
+        /* Fill U, and V panes. */
+        uint8_t* U = mFrameU + uv_off;
+        uint8_t* V = mFrameV + uv_off;
+        for (int k = 0; k < each_in_row; k++, U += mUVStep, V += mUVStep) {
+            *U = color->U;
+            *V = color->V;
+        }
+    }
+}
+
+int EmulatedFakeCameraDevice::rotateFrame()
+{
+    if ((systemTime(SYSTEM_TIME_MONOTONIC) - mLastRotatedAt) >= mRotateFreq) {
+        mLastRotatedAt = systemTime(SYSTEM_TIME_MONOTONIC);
+        mCurrentFrameType++;
+        if (mCurrentFrameType > 2) {
+            mCurrentFrameType = 0;
+        }
+        if (mCurrentFrameType == 2) {
+            LOGD("********** Rotated to the SOLID COLOR frame **********");
+            /* Solid color: lets rotate color too. */
+            if (mCurrentColor == &mWhiteYUV) {
+                LOGD("----- Painting a solid RED frame -----");
+                mCurrentColor = &mRedYUV;
+            } else if (mCurrentColor == &mRedYUV) {
+                LOGD("----- Painting a solid GREEN frame -----");
+                mCurrentColor = &mGreenYUV;
+            } else if (mCurrentColor == &mGreenYUV) {
+                LOGD("----- Painting a solid BLUE frame -----");
+                mCurrentColor = &mBlueYUV;
+            } else {
+                /* Back to white. */
+                LOGD("----- Painting a solid WHITE frame -----");
+                mCurrentColor = &mWhiteYUV;
+            }
+        } else if (mCurrentFrameType == 0) {
+            LOGD("********** Rotated to the CHECKERBOARD frame **********");
+        } else {
+            LOGD("********** Rotated to the STRIPED frame **********");
+        }
+    }
+
+    return mCurrentFrameType;
+}
+
+#endif  // EFCD_ROTATE_FRAME
+
+}; /* namespace android */
diff --git a/tools/emulator/system/camera/EmulatedFakeCameraDevice.h b/tools/emulator/system/camera/EmulatedFakeCameraDevice.h
new file mode 100755
index 0000000..f54127e
--- /dev/null
+++ b/tools/emulator/system/camera/EmulatedFakeCameraDevice.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_DEVICE_H
+#define HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_DEVICE_H
+
+/*
+ * Contains declaration of a class EmulatedFakeCameraDevice that encapsulates
+ * a fake camera device.
+ */
+
+#include "Converters.h"
+#include "EmulatedCameraDevice.h"
+
+/* This is used for debugging format / conversion issues. If EFCD_ROTATE_FRAME is
+ * set to 0, the frame content will be always the "checkerboard". Otherwise, if
+ * EFCD_ROTATE_FRAME is set to a non-zero value, the frame content will "rotate"
+ * from a "checkerboard" frame to a "white/red/green/blue stripes" frame, to a
+ * "white/red/green/blue" frame. Frame content rotation helps finding bugs in
+ * format conversions.
+ */
+#define EFCD_ROTATE_FRAME   1
+
+namespace android {
+
+class EmulatedFakeCamera;
+
+/* Encapsulates a fake camera device.
+ * Fake camera device emulates a camera device by providing frames containing
+ * a black and white checker board, moving diagonally towards the 0,0 corner.
+ * There is also a green, or red square that bounces inside the frame, changing
+ * its color when bouncing off the 0,0 corner.
+ */
+class EmulatedFakeCameraDevice : public EmulatedCameraDevice {
+public:
+    /* Constructs EmulatedFakeCameraDevice instance. */
+    explicit EmulatedFakeCameraDevice(EmulatedFakeCamera* camera_hal);
+
+    /* Destructs EmulatedFakeCameraDevice instance. */
+    ~EmulatedFakeCameraDevice();
+
+    /***************************************************************************
+     * Emulated camera device abstract interface implementation.
+     * See declarations of these methods in EmulatedCameraDevice class for
+     * information on each of these methods.
+     **************************************************************************/
+
+public:
+    /* Connects to the camera device.
+     * Since there is no real device to connect to, this method does nothing,
+     * but changes the state.
+     */
+    status_t connectDevice();
+
+    /* Disconnects from the camera device.
+     * Since there is no real device to disconnect from, this method does
+     * nothing, but changes the state.
+     */
+    status_t disconnectDevice();
+
+    /* Starts the camera device. */
+    status_t startDevice(int width, int height, uint32_t pix_fmt);
+
+    /* Stops the camera device. */
+    status_t stopDevice();
+
+    /* Gets current preview fame into provided buffer. */
+    status_t getPreviewFrame(void* buffer);
+
+    /***************************************************************************
+     * Worker thread management overrides.
+     * See declarations of these methods in EmulatedCameraDevice class for
+     * information on each of these methods.
+     **************************************************************************/
+
+protected:
+    /* Implementation of the worker thread routine.
+     * This method simply sleeps for a period of time defined by the FPS property
+     * of the fake camera (simulating frame frequency), and then calls emulated
+     * camera's onNextFrameAvailable method.
+     */
+    bool inWorkerThread();
+
+    /****************************************************************************
+     * Fake camera device private API
+     ***************************************************************************/
+
+private:
+    /* Draws a black and white checker board in the current frame buffer. */
+    void drawCheckerboard();
+
+    /* Draws a square of the given color in the current frame buffer.
+     * Param:
+     *  x, y - Coordinates of the top left corner of the square in the buffer.
+     *  size - Size of the square's side.
+     *  color - Square's color.
+     */
+    void drawSquare(int x, int y, int size, const YUVPixel* color);
+
+#if EFCD_ROTATE_FRAME
+    void drawSolid(YUVPixel* color);
+    void drawStripes();
+    int rotateFrame();
+#endif  // EFCD_ROTATE_FRAME
+
+    /****************************************************************************
+     * Fake camera device data members
+     ***************************************************************************/
+
+private:
+    /*
+     * Pixel colors in YUV format used when drawing the checker board.
+     */
+
+    YUVPixel    mBlackYUV;
+    YUVPixel    mWhiteYUV;
+    YUVPixel    mRedYUV;
+    YUVPixel    mGreenYUV;
+    YUVPixel    mBlueYUV;
+
+    /* Last time the frame has been redrawn. */
+    nsecs_t     mLastRedrawn;
+
+    /*
+     * Precalculated values related to U/V panes.
+     */
+
+    /* U pane inside the framebuffer. */
+    uint8_t*    mFrameU;
+
+    /* V pane inside the framebuffer. */
+    uint8_t*    mFrameV;
+
+    /* Defines byte distance between adjacent U, and V values. */
+    int         mUVStep;
+
+    /* Defines number of Us and Vs in a row inside the U/V panes.
+     * Note that if U/V panes are interleaved, this value reflects the total
+     * number of both, Us and Vs in a single row in the interleaved UV pane. */
+    int         mUVInRow;
+
+    /* Total number of each, U, and V elements in the framebuffer. */
+    int         mUVTotalNum;
+
+    /*
+     * Checkerboard drawing related stuff
+     */
+
+    int         mCheckX;
+    int         mCheckY;
+    int         mCcounter;
+
+    /* Emulated FPS (frames per second).
+     * We will emulate 50 FPS. */
+    static const int        mEmulatedFPS = 50;
+
+    /* Defines time (in nanoseconds) between redrawing the checker board.
+     * We will redraw the checker board every 15 milliseconds. */
+    static const nsecs_t    mRedrawAfter = 15000000LL;
+
+#if EFCD_ROTATE_FRAME
+    /* Frame rotation frequency in nanosec (currently - 3 sec) */
+    static const nsecs_t    mRotateFreq = 3000000000LL;
+
+    /* Last time the frame has rotated. */
+    nsecs_t     mLastRotatedAt;
+
+    /* Type of the frame to display in the current rotation:
+     *  0 - Checkerboard.
+     *  1 - White/Red/Green/Blue horisontal stripes
+     *  2 - Solid color. */
+    int         mCurrentFrameType;
+
+    /* Color to use to paint the solid color frame. Colors will rotate between
+     * white, red, gree, and blue each time rotation comes to the solid color
+     * frame. */
+    YUVPixel*   mCurrentColor;
+#endif  // EFCD_ROTATE_FRAME
+};
+
+}; /* namespace android */
+
+#endif  /* HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_DEVICE_H */
diff --git a/tools/emulator/system/camera/EmulatedQemuCamera.cpp b/tools/emulator/system/camera/EmulatedQemuCamera.cpp
new file mode 100755
index 0000000..611b6b5
--- /dev/null
+++ b/tools/emulator/system/camera/EmulatedQemuCamera.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Contains implementation of a class EmulatedQemuCamera that encapsulates
+ * functionality of an emulated camera connected to the host.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera_QemuCamera"
+#include <cutils/log.h>
+#include "EmulatedQemuCamera.h"
+#include "EmulatedCameraFactory.h"
+
+namespace android {
+
+EmulatedQemuCamera::EmulatedQemuCamera(int cameraId, struct hw_module_t* module)
+        : EmulatedCamera(cameraId, module),
+          mQemuCameraDevice(this)
+{
+}
+
+EmulatedQemuCamera::~EmulatedQemuCamera()
+{
+}
+
+/****************************************************************************
+ * EmulatedCamera virtual overrides.
+ ***************************************************************************/
+
+status_t EmulatedQemuCamera::Initialize(const char* device_name,
+                                        const char* frame_dims,
+                                        const char* facing_dir)
+{
+    LOGV("%s:\n   Name=%s\n   Facing '%s'\n   Dimensions=%s",
+         __FUNCTION__, device_name, facing_dir, frame_dims);
+    /* Save dimensions. */
+    mFrameDims = frame_dims;
+
+    /* Initialize camera device. */
+    status_t res = mQemuCameraDevice.Initialize(device_name);
+    if (res != NO_ERROR) {
+        return res;
+    }
+
+    /* Initialize base class. */
+    res = EmulatedCamera::Initialize();
+    if (res != NO_ERROR) {
+        return res;
+    }
+
+    /*
+     * Set customizable parameters.
+     */
+
+    mParameters.set(EmulatedCamera::FACING_KEY, facing_dir);
+    mParameters.set(EmulatedCamera::ORIENTATION_KEY,
+                    gEmulatedCameraFactory.getQemuCameraOrientation());
+    mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, frame_dims);
+    mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, frame_dims);
+
+    /*
+     * Use first dimension reported by the device to set current preview and
+     * picture sizes.
+     */
+
+    char first_dim[128];
+    /* Dimensions are separated with ',' */
+    const char* c = strchr(frame_dims, ',');
+    if (c == NULL) {
+        strncpy(first_dim, frame_dims, sizeof(first_dim));
+        first_dim[sizeof(first_dim)-1] = '\0';
+    } else if (static_cast<size_t>(c - frame_dims) < sizeof(first_dim)) {
+        memcpy(first_dim, frame_dims, c - frame_dims);
+        first_dim[c - frame_dims] = '\0';
+    } else {
+        memcpy(first_dim, frame_dims, sizeof(first_dim));
+        first_dim[sizeof(first_dim)-1] = '\0';
+    }
+
+    /* Width and height are separated with 'x' */
+    char* sep = strchr(first_dim, 'x');
+    if (sep == NULL) {
+        LOGE("%s: Invalid first dimension format in %s",
+             __FUNCTION__, frame_dims);
+        return EINVAL;
+    }
+
+    *sep = '\0';
+    const int x = atoi(first_dim);
+    const int y = atoi(sep + 1);
+    mParameters.setPreviewSize(x, y);
+    mParameters.setPictureSize(x, y);
+
+    LOGV("%s: Qemu camera %s is initialized. Current frame is %dx%d",
+         __FUNCTION__, device_name, x, y);
+
+    return NO_ERROR;
+}
+
+EmulatedCameraDevice* EmulatedQemuCamera::getCameraDevice()
+{
+    return &mQemuCameraDevice;
+}
+
+};  /* namespace android */
diff --git a/tools/emulator/system/camera/EmulatedQemuCamera.h b/tools/emulator/system/camera/EmulatedQemuCamera.h
new file mode 100755
index 0000000..1b826c7
--- /dev/null
+++ b/tools/emulator/system/camera/EmulatedQemuCamera.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_H
+#define HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_H
+
+/*
+ * Contains declaration of a class EmulatedQemuCamera that encapsulates
+ * functionality of an emulated camera connected to the host.
+ */
+
+#include "EmulatedCamera.h"
+#include "EmulatedQemuCameraDevice.h"
+
+namespace android {
+
+/* Encapsulates functionality of an emulated camera connected to the host.
+ */
+class EmulatedQemuCamera : public EmulatedCamera {
+public:
+    /* Constructs EmulatedQemuCamera instance. */
+    EmulatedQemuCamera(int cameraId, struct hw_module_t* module);
+
+    /* Destructs EmulatedQemuCamera instance. */
+    ~EmulatedQemuCamera();
+
+    /***************************************************************************
+     * EmulatedCamera virtual overrides.
+     **************************************************************************/
+
+public:
+    /* Initializes EmulatedQemuCamera instance. */
+     status_t Initialize(const char* device_name,
+                         const char* frame_dims,
+                         const char* facing_dir);
+
+    /***************************************************************************
+     * EmulatedCamera abstract API implementation.
+     **************************************************************************/
+
+protected:
+    /* Gets emulated camera device ised by this instance of the emulated camera.
+     */
+    EmulatedCameraDevice* getCameraDevice();
+
+    /***************************************************************************
+     * Data memebers.
+     **************************************************************************/
+
+protected:
+    /* Contained qemu camera device object. */
+    EmulatedQemuCameraDevice    mQemuCameraDevice;
+
+    /* Supported frame dimensions reported by the camera device. */
+    String8                     mFrameDims;
+};
+
+}; /* namespace android */
+
+#endif  /* HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_H */
diff --git a/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp b/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp
new file mode 100755
index 0000000..57dbc98
--- /dev/null
+++ b/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Contains implementation of a class EmulatedQemuCameraDevice that encapsulates
+ * an emulated camera device connected to the host.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera_QemuDevice"
+#include <cutils/log.h>
+#include "EmulatedQemuCamera.h"
+#include "EmulatedQemuCameraDevice.h"
+
+namespace android {
+
+EmulatedQemuCameraDevice::EmulatedQemuCameraDevice(EmulatedQemuCamera* camera_hal)
+    : EmulatedCameraDevice(camera_hal),
+      mQemuClient(),
+      mPreviewFrame(NULL)
+{
+}
+
+EmulatedQemuCameraDevice::~EmulatedQemuCameraDevice()
+{
+    if (mPreviewFrame != NULL) {
+        delete[] mPreviewFrame;
+    }
+}
+
+/****************************************************************************
+ * Public API
+ ***************************************************************************/
+
+status_t EmulatedQemuCameraDevice::Initialize(const char* device_name)
+{
+    /* Connect to the service. */
+    char connect_str[256];
+    snprintf(connect_str, sizeof(connect_str), "name=%s", device_name);
+    status_t res = mQemuClient.connectClient(connect_str);
+    if (res != NO_ERROR) {
+        return res;
+    }
+
+    /* Initialize base class. */
+    res = EmulatedCameraDevice::Initialize();
+    if (res == NO_ERROR) {
+        LOGV("%s: Connected to the emulated camera service '%s'",
+             __FUNCTION__, device_name);
+        mDeviceName = device_name;
+    } else {
+        mQemuClient.queryDisconnect();
+    }
+
+    return res;
+}
+
+/****************************************************************************
+ * Emulated camera device abstract interface implementation.
+ ***************************************************************************/
+
+status_t EmulatedQemuCameraDevice::connectDevice()
+{
+    LOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock locker(&mObjectLock);
+    if (!isInitialized()) {
+        LOGE("%s: Qemu camera device is not initialized.", __FUNCTION__);
+        return EINVAL;
+    }
+    if (isConnected()) {
+        LOGW("%s: Qemu camera device '%s' is already connected.",
+             __FUNCTION__, (const char*)mDeviceName);
+        return NO_ERROR;
+    }
+
+    /* Connect to the camera device via emulator. */
+    const status_t res = mQemuClient.queryConnect();
+    if (res == NO_ERROR) {
+        LOGV("%s: Connected to device '%s'",
+             __FUNCTION__, (const char*)mDeviceName);
+        mState = ECDS_CONNECTED;
+    } else {
+        LOGE("%s: Connection to device '%s' failed",
+             __FUNCTION__, (const char*)mDeviceName);
+    }
+
+    return res;
+}
+
+status_t EmulatedQemuCameraDevice::disconnectDevice()
+{
+    LOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock locker(&mObjectLock);
+    if (!isConnected()) {
+        LOGW("%s: Qemu camera device '%s' is already disconnected.",
+             __FUNCTION__, (const char*)mDeviceName);
+        return NO_ERROR;
+    }
+    if (isStarted()) {
+        LOGE("%s: Cannot disconnect from the started device '%s.",
+             __FUNCTION__, (const char*)mDeviceName);
+        return EINVAL;
+    }
+
+    /* Disconnect from the camera device via emulator. */
+    const status_t res = mQemuClient.queryDisconnect();
+    if (res == NO_ERROR) {
+        LOGV("%s: Disonnected from device '%s'",
+             __FUNCTION__, (const char*)mDeviceName);
+        mState = ECDS_INITIALIZED;
+    } else {
+        LOGE("%s: Disconnection from device '%s' failed",
+             __FUNCTION__, (const char*)mDeviceName);
+    }
+
+    return res;
+}
+
+status_t EmulatedQemuCameraDevice::startDevice(int width,
+                                               int height,
+                                               uint32_t pix_fmt)
+{
+    LOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock locker(&mObjectLock);
+    if (!isConnected()) {
+        LOGE("%s: Qemu camera device '%s' is not connected.",
+             __FUNCTION__, (const char*)mDeviceName);
+        return EINVAL;
+    }
+    if (isStarted()) {
+        LOGW("%s: Qemu camera device '%s' is already started.",
+             __FUNCTION__, (const char*)mDeviceName);
+        return NO_ERROR;
+    }
+
+    status_t res = EmulatedCameraDevice::commonStartDevice(width, height, pix_fmt);
+    if (res != NO_ERROR) {
+        LOGE("%s: commonStartDevice failed", __FUNCTION__);
+        return res;
+    }
+
+    /* Allocate preview frame buffer. */
+    /* TODO: Watch out for preview format changes! At this point we implement
+     * RGB32 only.*/
+    mPreviewFrame = new uint32_t[mTotalPixels];
+    if (mPreviewFrame == NULL) {
+        LOGE("%s: Unable to allocate %d bytes for preview frame",
+             __FUNCTION__, mTotalPixels);
+        return ENOMEM;
+    }
+
+    /* Start the actual camera device. */
+    res = mQemuClient.queryStart(mPixelFormat, mFrameWidth, mFrameHeight);
+    if (res == NO_ERROR) {
+        LOGV("%s: Qemu camera device '%s' is started for %.4s[%dx%d] frames",
+             __FUNCTION__, (const char*)mDeviceName,
+             reinterpret_cast<const char*>(&mPixelFormat),
+             mFrameWidth, mFrameHeight);
+        mState = ECDS_STARTED;
+    } else {
+        LOGE("%s: Unable to start device '%s' for %.4s[%dx%d] frames",
+             __FUNCTION__, (const char*)mDeviceName,
+             reinterpret_cast<const char*>(&pix_fmt), width, height);
+    }
+
+    return res;
+}
+
+status_t EmulatedQemuCameraDevice::stopDevice()
+{
+    LOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock locker(&mObjectLock);
+    if (!isStarted()) {
+        LOGW("%s: Qemu camera device '%s' is not started.",
+             __FUNCTION__, (const char*)mDeviceName);
+        return NO_ERROR;
+    }
+
+    /* Stop the actual camera device. */
+    status_t res = mQemuClient.queryStop();
+    if (res == NO_ERROR) {
+        if (mPreviewFrame == NULL) {
+            delete[] mPreviewFrame;
+            mPreviewFrame = NULL;
+        }
+        EmulatedCameraDevice::commonStopDevice();
+        mState = ECDS_CONNECTED;
+        LOGV("%s: Qemu camera device '%s' is stopped",
+             __FUNCTION__, (const char*)mDeviceName);
+    } else {
+        LOGE("%s: Unable to stop device '%s'",
+             __FUNCTION__, (const char*)mDeviceName);
+    }
+
+    return res;
+}
+
+/****************************************************************************
+ * EmulatedCameraDevice virtual overrides
+ ***************************************************************************/
+
+status_t EmulatedQemuCameraDevice::getCurrentPreviewFrame(void* buffer)
+{
+    LOGW_IF(mPreviewFrame == NULL, "%s: No preview frame", __FUNCTION__);
+    if (mPreviewFrame != NULL) {
+        memcpy(buffer, mPreviewFrame, mTotalPixels * 4);
+        return 0;
+    } else {
+        return EmulatedCameraDevice::getCurrentPreviewFrame(buffer);
+    }
+}
+
+/****************************************************************************
+ * Worker thread management overrides.
+ ***************************************************************************/
+
+bool EmulatedQemuCameraDevice::inWorkerThread()
+{
+    /* Wait till FPS timeout expires, or thread exit message is received. */
+    WorkerThread::SelectRes res =
+        getWorkerThread()->Select(-1, 1000000 / mEmulatedFPS);
+    if (res == WorkerThread::EXIT_THREAD) {
+        LOGV("%s: Worker thread has been terminated.", __FUNCTION__);
+        return false;
+    }
+
+    /* Query frames from the service. */
+    status_t query_res = mQemuClient.queryFrame(mCurrentFrame, mPreviewFrame,
+                                                 mFrameBufferSize,
+                                                 mTotalPixels * 4);
+    if (query_res == NO_ERROR) {
+        /* Timestamp the current frame, and notify the camera HAL. */
+        mCurFrameTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+        mCameraHAL->onNextFrameAvailable(mCurrentFrame, mCurFrameTimestamp, this);
+        return true;
+    } else {
+        LOGE("%s: Unable to get current video frame: %s",
+             __FUNCTION__, strerror(query_res));
+        mCameraHAL->onCameraDeviceError(CAMERA_ERROR_SERVER_DIED);
+        return false;
+    }
+}
+
+}; /* namespace android */
diff --git a/tools/emulator/system/camera/EmulatedQemuCameraDevice.h b/tools/emulator/system/camera/EmulatedQemuCameraDevice.h
new file mode 100755
index 0000000..8ef562b
--- /dev/null
+++ b/tools/emulator/system/camera/EmulatedQemuCameraDevice.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_DEVICE_H
+#define HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_DEVICE_H
+
+/*
+ * Contains declaration of a class EmulatedQemuCameraDevice that encapsulates
+ * an emulated camera device connected to the host.
+ */
+
+#include "EmulatedCameraDevice.h"
+#include "QemuClient.h"
+
+namespace android {
+
+class EmulatedQemuCamera;
+
+/* Encapsulates an emulated camera device connected to the host.
+ */
+class EmulatedQemuCameraDevice : public EmulatedCameraDevice {
+public:
+    /* Constructs EmulatedQemuCameraDevice instance. */
+    explicit EmulatedQemuCameraDevice(EmulatedQemuCamera* camera_hal);
+
+    /* Destructs EmulatedQemuCameraDevice instance. */
+    ~EmulatedQemuCameraDevice();
+
+    /***************************************************************************
+     * Public API
+     **************************************************************************/
+
+public:
+    /* Initializes EmulatedQemuCameraDevice instance.
+     * Param:
+     *  device_name - Name of the camera device connected to the host. The name
+     *      that is used here must have been reported by the 'factory' camera
+     *      service when it listed camera devices connected to the host.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    status_t Initialize(const char* device_name);
+
+    /***************************************************************************
+     * Emulated camera device abstract interface implementation.
+     * See declarations of these methods in EmulatedCameraDevice class for
+     * information on each of these methods.
+     **************************************************************************/
+
+public:
+    /* Connects to the camera device. */
+    status_t connectDevice();
+
+    /* Disconnects from the camera device. */
+    status_t disconnectDevice();
+
+    /* Starts capturing frames from the camera device. */
+    status_t startDevice(int width, int height, uint32_t pix_fmt);
+
+    /* Stops capturing frames from the camera device. */
+    status_t stopDevice();
+
+    /***************************************************************************
+     * EmulatedCameraDevice virtual overrides
+     * See declarations of these methods in EmulatedCameraDevice class for
+     * information on each of these methods.
+     **************************************************************************/
+
+public:
+    /* Gets current preview fame into provided buffer.
+     * We override this method in order to provide preview frames cached in this
+     * object.
+     */
+    status_t getCurrentPreviewFrame(void* buffer);
+
+    /***************************************************************************
+     * Worker thread management overrides.
+     * See declarations of these methods in EmulatedCameraDevice class for
+     * information on each of these methods.
+     **************************************************************************/
+
+protected:
+    /* Implementation of the worker thread routine. */
+    bool inWorkerThread();
+
+    /***************************************************************************
+     * Qemu camera device data members
+     **************************************************************************/
+
+private:
+    /* Qemu client that is used to communicate with the 'emulated camera'
+     * service, created for this instance in the emulator. */
+    CameraQemuClient    mQemuClient;
+
+    /* Name of the camera device connected to the host. */
+    String8             mDeviceName;
+
+    /* Current preview framebuffer. */
+    uint32_t*           mPreviewFrame;
+
+    /* Emulated FPS (frames per second).
+     * We will emulate 50 FPS. */
+    static const int    mEmulatedFPS = 50;
+};
+
+}; /* namespace android */
+
+#endif  /* HW_EMULATOR_CAMERA_EMULATED_QEMU_CAMERA_DEVICE_H */
diff --git a/tools/emulator/system/camera/JpegCompressor.cpp b/tools/emulator/system/camera/JpegCompressor.cpp
new file mode 100644
index 0000000..0e538a1
--- /dev/null
+++ b/tools/emulator/system/camera/JpegCompressor.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Contains implementation of a class NV21JpegCompressor that encapsulates a
+ * converter between NV21, and JPEG formats.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "EmulatedCamera_JPEG"
+#include <cutils/log.h>
+#include "JpegCompressor.h"
+
+namespace android {
+
+NV21JpegCompressor::NV21JpegCompressor()
+    : Yuv420SpToJpegEncoder(mStrides)
+{
+}
+
+NV21JpegCompressor::~NV21JpegCompressor()
+{
+}
+
+/****************************************************************************
+ * Public API
+ ***************************************************************************/
+
+status_t NV21JpegCompressor::compressRawImage(const void* image,
+                                              int width,
+                                              int height,
+                                              int quality)
+{
+    LOGV("%s: %p[%dx%d]", __FUNCTION__, image, width, height);
+    void* pY = const_cast<void*>(image);
+    int offsets[2];
+    offsets[0] = 0;
+    offsets[1] = width * height;
+    mStrides[0] = width;
+    mStrides[1] = width;
+    if (encode(&mStream, pY, width, height, offsets, quality)) {
+        LOGV("%s: Compressed JPEG: %d[%dx%d] -> %d bytes",
+             __FUNCTION__, (width * height * 12) / 8, width, height, mStream.getOffset());
+        return NO_ERROR;
+    } else {
+        LOGE("%s: JPEG compression failed", __FUNCTION__);
+        return errno ? errno : EINVAL;
+    }
+}
+
+}; /* namespace android */
diff --git a/tools/emulator/system/camera/JpegCompressor.h b/tools/emulator/system/camera/JpegCompressor.h
new file mode 100644
index 0000000..1f97ae4
--- /dev/null
+++ b/tools/emulator/system/camera/JpegCompressor.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HW_EMULATOR_CAMERA_JPEG_COMPRESSOR_H
+#define HW_EMULATOR_CAMERA_JPEG_COMPRESSOR_H
+
+/*
+ * Contains declaration of a class NV21JpegCompressor that encapsulates a
+ * converter between YV21, and JPEG formats.
+ */
+
+#include <YuvToJpegEncoder.h>
+
+namespace android {
+
+/* Encapsulates a converter between YV12, and JPEG formats.
+ */
+class NV21JpegCompressor : protected Yuv420SpToJpegEncoder
+{
+public:
+    /* Constructs JpegCompressor instance. */
+    NV21JpegCompressor();
+    /* Destructs JpegCompressor instance. */
+    ~NV21JpegCompressor();
+
+    /****************************************************************************
+     * Public API
+     ***************************************************************************/
+
+public:
+    /* Compresses raw NV21 image into a JPEG.
+     * The compressed image will be saved in mStream member of this class. Use
+     * getCompressedSize method to obtain buffer size of the compressed image,
+     * and getCompressedImage to copy out the compressed image.
+     * Param:
+     *  image - Raw NV21 image.
+     *  width, height - Image dimensions.
+     *  quality - JPEG quality.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     *
+     */
+    status_t compressRawImage(const void* image,
+                              int width,
+                              int height,
+                              int quality);
+
+    /* Get size of the compressed JPEG buffer.
+     * This method must be called only after a successful completion of
+     * compressRawImage call.
+     * Return:
+     *  Size of the compressed JPEG buffer.
+     */
+    size_t getCompressedSize() const
+    {
+        return mStream.getOffset();
+    }
+
+    /* Copies out compressed JPEG buffer.
+     * This method must be called only after a successful completion of
+     * compressRawImage call.
+     * Param:
+     *  buff - Buffer where to copy the JPEG. Must be large enough to contain the
+     *      entire image.
+     */
+    void getCompressedImage(void* buff) const
+    {
+        mStream.copyTo(buff);
+    }
+
+    /****************************************************************************
+     * Class data
+     ***************************************************************************/
+
+protected:
+    /* Memory stream where converted JPEG is saved. */
+    SkDynamicMemoryWStream  mStream;
+    /* Strides for Y (the first element), and UV (the second one) panes. */
+    int                     mStrides[2];
+};
+
+}; /* namespace android */
+
+#endif  /* HW_EMULATOR_CAMERA_JPEG_COMPRESSOR_H */
diff --git a/tools/emulator/system/camera/preview_window.cpp b/tools/emulator/system/camera/PreviewWindow.cpp
old mode 100644
new mode 100755
similarity index 65%
rename from tools/emulator/system/camera/preview_window.cpp
rename to tools/emulator/system/camera/PreviewWindow.cpp
index 151e466..fb708d5
--- a/tools/emulator/system/camera/preview_window.cpp
+++ b/tools/emulator/system/camera/PreviewWindow.cpp
@@ -24,17 +24,17 @@
 #include <cutils/log.h>
 #include <ui/Rect.h>
 #include <ui/GraphicBufferMapper.h>
-#include "emulated_camera_device.h"
-#include "preview_window.h"
+#include "EmulatedCameraDevice.h"
+#include "PreviewWindow.h"
 
 namespace android {
 
 PreviewWindow::PreviewWindow()
-    : preview_window_(NULL),
-      last_previewed_(0),
-      preview_frame_width_(0),
-      preview_frame_height_(0),
-      preview_enabled_(false)
+    : mPreviewWindow(NULL),
+      mLastPreviewed(0),
+      mPreviewFrameWidth(0),
+      mPreviewFrameHeight(0),
+      mPreviewEnabled(false)
 {
 }
 
@@ -46,18 +46,18 @@
  * Camera API
  ***************************************************************************/
 
-status_t PreviewWindow::SetPreviewWindow(struct preview_stream_ops* window,
+status_t PreviewWindow::setPreviewWindow(struct preview_stream_ops* window,
                                          int preview_fps)
 {
-    LOGV("%s: current: %p -> new: %p", __FUNCTION__, preview_window_, window);
+    LOGV("%s: current: %p -> new: %p", __FUNCTION__, mPreviewWindow, window);
 
     status_t res = NO_ERROR;
-    Mutex::Autolock locker(&object_lock_);
+    Mutex::Autolock locker(&mObjectLock);
 
     /* Reset preview info. */
-    preview_frame_width_ = preview_frame_height_ = 0;
-    preview_after_ = 0;
-    last_previewed_ = 0;
+    mPreviewFrameWidth = mPreviewFrameHeight = 0;
+    mPreviewAfter = 0;
+    mLastPreviewed = 0;
 
     if (window != NULL) {
         /* The CPU will write each frame to the preview window buffer.
@@ -66,7 +66,7 @@
         res = window->set_usage(window, GRALLOC_USAGE_SW_WRITE_OFTEN);
         if (res == NO_ERROR) {
             /* Set preview frequency. */
-            preview_after_ = 1000000 / preview_fps;
+            mPreviewAfter = 1000000 / preview_fps;
         } else {
             window = NULL;
             res = -res; // set_usage returns a negative errno.
@@ -74,62 +74,56 @@
                  __FUNCTION__, res, strerror(res));
         }
     }
-    preview_window_ = window;
+    mPreviewWindow = window;
 
     return res;
 }
 
-status_t PreviewWindow::Start()
+status_t PreviewWindow::startPreview()
 {
     LOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock locker(&object_lock_);
-    preview_enabled_ = true;
+    Mutex::Autolock locker(&mObjectLock);
+    mPreviewEnabled = true;
 
     return NO_ERROR;
 }
 
-void PreviewWindow::Stop()
+void PreviewWindow::stopPreview()
 {
     LOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock locker(&object_lock_);
-    preview_enabled_ = false;
-}
-
-bool PreviewWindow::IsEnabled()
-{
-    Mutex::Autolock locker(&object_lock_);
-    return preview_enabled_;
+    Mutex::Autolock locker(&mObjectLock);
+    mPreviewEnabled = false;
 }
 
 /****************************************************************************
  * Public API
  ***************************************************************************/
 
-void PreviewWindow::OnNextFrameAvailable(const void* frame,
+void PreviewWindow::onNextFrameAvailable(const void* frame,
                                          nsecs_t timestamp,
                                          EmulatedCameraDevice* camera_dev)
 {
     int res;
-    Mutex::Autolock locker(&object_lock_);
+    Mutex::Autolock locker(&mObjectLock);
 
-    if (!preview_enabled_ || preview_window_ == NULL || !IsTimeToPreview()) {
+    if (!isPreviewEnabled() || mPreviewWindow == NULL || !isPreviewTime()) {
         return;
     }
 
-    /* Make sure that preview window dimensions are OK with the camera device. */
-    if (AdjustPreviewDimensions(camera_dev)) {
+    /* Make sure that preview window dimensions are OK with the camera device */
+    if (adjustPreviewDimensions(camera_dev)) {
         /* Need to set / adjust buffer geometry for the preview window.
          * Note that in the emulator preview window uses only RGB for pixel
          * formats. */
         LOGV("%s: Adjusting preview windows %p geometry to %dx%d",
-             __FUNCTION__, preview_window_, preview_frame_width_,
-             preview_frame_height_);
-        res = preview_window_->set_buffers_geometry(preview_window_,
-                                                    preview_frame_width_,
-                                                    preview_frame_height_,
-                                                    HAL_PIXEL_FORMAT_RGB_565);
+             __FUNCTION__, mPreviewWindow, mPreviewFrameWidth,
+             mPreviewFrameHeight);
+        res = mPreviewWindow->set_buffers_geometry(mPreviewWindow,
+                                                   mPreviewFrameWidth,
+                                                   mPreviewFrameHeight,
+                                                   HAL_PIXEL_FORMAT_RGBA_8888);
         if (res != NO_ERROR) {
             LOGE("%s: Error in set_buffers_geometry %d -> %s",
                  __FUNCTION__, -res, strerror(-res));
@@ -144,7 +138,7 @@
     /* Dequeue preview window buffer for the frame. */
     buffer_handle_t* buffer = NULL;
     int stride = 0;
-    res = preview_window_->dequeue_buffer(preview_window_, &buffer, &stride);
+    res = mPreviewWindow->dequeue_buffer(mPreviewWindow, &buffer, &stride);
     if (res != NO_ERROR || buffer == NULL) {
         LOGE("%s: Unable to dequeue preview window buffer: %d -> %s",
             __FUNCTION__, -res, strerror(-res));
@@ -152,63 +146,67 @@
     }
 
     /* Let the preview window to lock the buffer. */
-    res = preview_window_->lock_buffer(preview_window_, buffer);
+    res = mPreviewWindow->lock_buffer(mPreviewWindow, buffer);
     if (res != NO_ERROR) {
         LOGE("%s: Unable to lock preview window buffer: %d -> %s",
              __FUNCTION__, -res, strerror(-res));
-        preview_window_->cancel_buffer(preview_window_, buffer);
+        mPreviewWindow->cancel_buffer(mPreviewWindow, buffer);
         return;
     }
 
     /* Now let the graphics framework to lock the buffer, and provide
      * us with the framebuffer data address. */
     void* img = NULL;
-    const Rect rect(preview_frame_width_, preview_frame_height_);
+    const Rect rect(mPreviewFrameWidth, mPreviewFrameHeight);
     GraphicBufferMapper& grbuffer_mapper(GraphicBufferMapper::get());
     res = grbuffer_mapper.lock(*buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, rect, &img);
     if (res != NO_ERROR) {
         LOGE("%s: grbuffer_mapper.lock failure: %d -> %s",
              __FUNCTION__, res, strerror(res));
-        preview_window_->cancel_buffer(preview_window_, buffer);
+        mPreviewWindow->cancel_buffer(mPreviewWindow, buffer);
         return;
     }
 
     /* Frames come in in YV12/NV12/NV21 format. Since preview window doesn't
      * supports those formats, we need to obtain the frame in RGB565. */
-    res = camera_dev->GetCurrentPreviewFrame(img);
+    res = camera_dev->getCurrentPreviewFrame(img);
     if (res == NO_ERROR) {
         /* Show it. */
-        preview_window_->enqueue_buffer(preview_window_, buffer);
+        mPreviewWindow->enqueue_buffer(mPreviewWindow, buffer);
     } else {
         LOGE("%s: Unable to obtain preview frame: %d", __FUNCTION__, res);
-        preview_window_->cancel_buffer(preview_window_, buffer);
+        mPreviewWindow->cancel_buffer(mPreviewWindow, buffer);
     }
     grbuffer_mapper.unlock(*buffer);
 }
 
-bool PreviewWindow::AdjustPreviewDimensions(EmulatedCameraDevice* camera_dev)
+/***************************************************************************
+ * Private API
+ **************************************************************************/
+
+bool PreviewWindow::adjustPreviewDimensions(EmulatedCameraDevice* camera_dev)
 {
     /* Match the cached frame dimensions against the actual ones. */
-    if (preview_frame_width_ == camera_dev->GetFrameWidth() &&
-        preview_frame_height_ == camera_dev->GetFrameHeight()) {
+    if (mPreviewFrameWidth == camera_dev->getFrameWidth() &&
+        mPreviewFrameHeight == camera_dev->getFrameHeight()) {
         /* They match. */
         return false;
     }
 
     /* They don't match: adjust the cache. */
-    preview_frame_width_ = camera_dev->GetFrameWidth();
-    preview_frame_height_ = camera_dev->GetFrameHeight();
+    mPreviewFrameWidth = camera_dev->getFrameWidth();
+    mPreviewFrameHeight = camera_dev->getFrameHeight();
 
     return true;
 }
 
-bool PreviewWindow::IsTimeToPreview()
+bool PreviewWindow::isPreviewTime()
 {
     timeval cur_time;
     gettimeofday(&cur_time, NULL);
     const uint64_t cur_mks = cur_time.tv_sec * 1000000LL + cur_time.tv_usec;
-    if ((cur_mks - last_previewed_) >= preview_after_) {
-        last_previewed_ = cur_mks;
+    if ((cur_mks - mLastPreviewed) >= mPreviewAfter) {
+        mLastPreviewed = cur_mks;
         return true;
     }
     return false;
diff --git a/tools/emulator/system/camera/preview_window.h b/tools/emulator/system/camera/PreviewWindow.h
old mode 100644
new mode 100755
similarity index 81%
rename from tools/emulator/system/camera/preview_window.h
rename to tools/emulator/system/camera/PreviewWindow.h
index a37f22f..d037c95
--- a/tools/emulator/system/camera/preview_window.h
+++ b/tools/emulator/system/camera/PreviewWindow.h
@@ -40,9 +40,9 @@
     /* Destructs PreviewWindow instance. */
     ~PreviewWindow();
 
-    /****************************************************************************
+    /***************************************************************************
      * Camera API
-     ***************************************************************************/
+     **************************************************************************/
 
 public:
     /* Actual handler for camera_device_ops_t::set_preview_window callback.
@@ -52,29 +52,32 @@
      *  window - Preview window to set. This parameter might be NULL, which
      *      indicates preview window reset.
      *  preview_fps - Preview's frame frequency. This parameter determins when
-     *      a frame received via OnNextFrameAvailable call will be pushed to the
-     *      preview window. If 'window' parameter passed to this method is NULL,
-     *      this parameter is ignored.
+     *      a frame received via onNextFrameAvailable call will be pushed to
+     *      the preview window. If 'window' parameter passed to this method is
+     *      NULL, this parameter is ignored.
      * Return:
      *  NO_ERROR on success, or an appropriate error status.
      */
-    status_t SetPreviewWindow(struct preview_stream_ops* window,
+    status_t setPreviewWindow(struct preview_stream_ops* window,
                               int preview_fps);
 
     /* Starts the preview.
      * This method is called by the containing emulated camera object when it is
      * handing the camera_device_ops_t::start_preview callback.
      */
-    status_t Start();
+    status_t startPreview();
 
     /* Stops the preview.
      * This method is called by the containing emulated camera object when it is
      * handing the camera_device_ops_t::start_preview callback.
      */
-    void Stop();
+    void stopPreview();
 
     /* Checks if preview is enabled. */
-    bool IsEnabled();
+    inline bool isPreviewEnabled()
+    {
+        return mPreviewEnabled;
+    }
 
     /****************************************************************************
      * Public API
@@ -96,13 +99,13 @@
      * timestamp - Frame's timestamp.
      * camera_dev - Camera device instance that delivered the frame.
      */
-    void OnNextFrameAvailable(const void* frame,
+    void onNextFrameAvailable(const void* frame,
                               nsecs_t timestamp,
                               EmulatedCameraDevice* camera_dev);
 
-    /****************************************************************************
+    /***************************************************************************
      * Private API
-     ***************************************************************************/
+     **************************************************************************/
 
 protected:
     /* Adjusts cached dimensions of the preview window frame according to the
@@ -111,9 +114,9 @@
      * When preview is started, it's not known (hard to define) what are going
      * to be the dimensions of the frames that are going to be displayed. Plus,
      * it might be possible, that such dimensions can be changed on the fly. So,
-     * in order to be always in sync with frame dimensions, this method is called
-     * for each frame passed to OnNextFrameAvailable method, in order to properly
-     * adjust frame dimensions, used by the preview window.
+     * in order to be always in sync with frame dimensions, this method is
+     * called for each frame passed to onNextFrameAvailable method, in order to
+     * properly adjust frame dimensions, used by the preview window.
      * Note that this method must be called while object is locked.
      * Param:
      *  camera_dev - Camera device, prpviding frames displayed in the preview
@@ -122,39 +125,39 @@
      *  true if cached dimensions have been adjusted, or false if cached
      *  dimensions match device's frame dimensions.
      */
-    bool AdjustPreviewDimensions(EmulatedCameraDevice* camera_dev);
+    bool adjustPreviewDimensions(EmulatedCameraDevice* camera_dev);
 
     /* Checks if it's the time to push new frame to the preview window.
      * Note that this method must be called while object is locked. */
-    bool IsTimeToPreview();
+    bool isPreviewTime();
 
-    /****************************************************************************
+    /***************************************************************************
      * Data members
-     ***************************************************************************/
+     **************************************************************************/
 
 protected:
     /* Locks this instance for data changes. */
-    Mutex                           object_lock_;
+    Mutex                           mObjectLock;
 
     /* Preview window instance. */
-    preview_stream_ops*             preview_window_;
+    preview_stream_ops*             mPreviewWindow;
 
     /* Timestamp (abs. microseconds) when last frame has been pushed to the
      * preview window. */
-    uint64_t                        last_previewed_;
+    uint64_t                        mLastPreviewed;
 
     /* Preview frequency in microseconds. */
-    uint32_t                        preview_after_;
+    uint32_t                        mPreviewAfter;
 
     /*
      * Cached preview window frame dimensions.
      */
 
-    int                             preview_frame_width_;
-    int                             preview_frame_height_;
+    int                             mPreviewFrameWidth;
+    int                             mPreviewFrameHeight;
 
     /* Preview status. */
-    bool                            preview_enabled_;
+    bool                            mPreviewEnabled;
 };
 
 }; /* namespace android */
diff --git a/tools/emulator/system/camera/QemuClient.cpp b/tools/emulator/system/camera/QemuClient.cpp
new file mode 100755
index 0000000..fd49585
--- /dev/null
+++ b/tools/emulator/system/camera/QemuClient.cpp
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Contains implementation of classes that encapsulate connection to camera
+ * services in the emulator via qemu pipe.
+ */
+
+#define LOG_NDEBUG 1
+#define LOG_TAG "EmulatedCamera_QemuClient"
+#include <cutils/log.h>
+#include "EmulatedCamera.h"
+#include "QemuClient.h"
+
+#define LOG_QUERIES 0
+#if LOG_QUERIES
+#define LOGQ(...)   LOGD(__VA_ARGS__)
+#else
+#define LOGQ(...)   (void(0))
+
+#endif  // LOG_QUERIES
+namespace android {
+
+/****************************************************************************
+ * Qemu query
+ ***************************************************************************/
+
+QemuQuery::QemuQuery()
+    : mQuery(mQueryPrealloc),
+      mQueryDeliveryStatus(NO_ERROR),
+      mReplyBuffer(NULL),
+      mReplyData(NULL),
+      mReplySize(0),
+      mReplyDataSize(0),
+      mReplyStatus(0)
+{
+    *mQuery = '\0';
+}
+
+QemuQuery::QemuQuery(const char* query_string)
+    : mQuery(mQueryPrealloc),
+      mQueryDeliveryStatus(NO_ERROR),
+      mReplyBuffer(NULL),
+      mReplyData(NULL),
+      mReplySize(0),
+      mReplyDataSize(0),
+      mReplyStatus(0)
+{
+    mQueryDeliveryStatus = QemuQuery::createQuery(query_string, NULL);
+}
+
+QemuQuery::QemuQuery(const char* query_name, const char* query_param)
+    : mQuery(mQueryPrealloc),
+      mQueryDeliveryStatus(NO_ERROR),
+      mReplyBuffer(NULL),
+      mReplyData(NULL),
+      mReplySize(0),
+      mReplyDataSize(0),
+      mReplyStatus(0)
+{
+    mQueryDeliveryStatus = QemuQuery::createQuery(query_name, query_param);
+}
+
+QemuQuery::~QemuQuery()
+{
+    QemuQuery::resetQuery();
+}
+
+status_t QemuQuery::createQuery(const char* name, const char* param)
+{
+    /* Reset from the previous use. */
+    resetQuery();
+
+    /* Query name cannot be NULL or an empty string. */
+    if (name == NULL || *name == '\0') {
+        LOGE("%s: NULL or an empty string is passed as query name.",
+             __FUNCTION__);
+        mQueryDeliveryStatus = EINVAL;
+        return EINVAL;
+    }
+
+    const size_t name_len = strlen(name);
+    const size_t param_len = (param != NULL) ? strlen(param) : 0;
+    const size_t required = strlen(name) + (param_len ? (param_len + 2) : 1);
+
+    if (required > sizeof(mQueryPrealloc)) {
+        /* Preallocated buffer was too small. Allocate a bigger query buffer. */
+        mQuery = new char[required];
+        if (mQuery == NULL) {
+            LOGE("%s: Unable to allocate %d bytes for query buffer",
+                 __FUNCTION__, required);
+            mQueryDeliveryStatus = ENOMEM;
+            return ENOMEM;
+        }
+    }
+
+    /* At this point mQuery buffer is big enough for the query. */
+    if (param_len) {
+        sprintf(mQuery, "%s %s", name, param);
+    } else {
+        memcpy(mQuery, name, name_len + 1);
+    }
+
+    return NO_ERROR;
+}
+
+status_t QemuQuery::completeQuery(status_t status)
+{
+    /* Save query completion status. */
+    mQueryDeliveryStatus = status;
+    if (mQueryDeliveryStatus != NO_ERROR) {
+        return mQueryDeliveryStatus;
+    }
+
+    /* Make sure reply buffer contains at least 'ok', or 'ko'.
+     * Note that 'ok', or 'ko' prefixes are always 3 characters long: in case
+     * there are more data in the reply, that data will be separated from 'ok'/'ko'
+     * with a ':'. If there is no more data in the reply, the prefix will be
+     * zero-terminated, and the terminator will be inculded in the reply. */
+    if (mReplyBuffer == NULL || mReplySize < 3) {
+        LOGE("%s: Invalid reply to the query", __FUNCTION__);
+        mQueryDeliveryStatus = EINVAL;
+        return EINVAL;
+    }
+
+    /* Lets see the reply status. */
+    if (!memcmp(mReplyBuffer, "ok", 2)) {
+        mReplyStatus = 1;
+    } else if (!memcmp(mReplyBuffer, "ko", 2)) {
+        mReplyStatus = 0;
+    } else {
+        LOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
+        mQueryDeliveryStatus = EINVAL;
+        return EINVAL;
+    }
+
+    /* Lets see if there are reply data that follow. */
+    if (mReplySize > 3) {
+        /* There are extra data. Make sure they are separated from the status
+         * with a ':' */
+        if (mReplyBuffer[2] != ':') {
+            LOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
+            mQueryDeliveryStatus = EINVAL;
+            return EINVAL;
+        }
+        mReplyData = mReplyBuffer + 3;
+        mReplyDataSize = mReplySize - 3;
+    } else {
+        /* Make sure reply buffer containing just 'ok'/'ko' ends with
+         * zero-terminator. */
+        if (mReplyBuffer[2] != '\0') {
+            LOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
+            mQueryDeliveryStatus = EINVAL;
+            return EINVAL;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+void QemuQuery::resetQuery()
+{
+    if (mQuery != NULL && mQuery != mQueryPrealloc) {
+        delete[] mQuery;
+    }
+    mQuery = mQueryPrealloc;
+    mQueryDeliveryStatus = NO_ERROR;
+    if (mReplyBuffer != NULL) {
+        free(mReplyBuffer);
+        mReplyBuffer = NULL;
+    }
+    mReplyData = NULL;
+    mReplySize = mReplyDataSize = 0;
+    mReplyStatus = 0;
+}
+
+/****************************************************************************
+ * Qemu client base
+ ***************************************************************************/
+
+/* Camera service name. */
+const char QemuClient::mCameraServiceName[]   = "camera";
+
+QemuClient::QemuClient()
+    : mPipeFD(-1)
+{
+}
+
+QemuClient::~QemuClient()
+{
+    if (mPipeFD >= 0) {
+        close(mPipeFD);
+    }
+}
+
+/****************************************************************************
+ * Qemu client API
+ ***************************************************************************/
+
+status_t QemuClient::connectClient(const char* param)
+{
+    LOGV("%s: '%s'", __FUNCTION__, param ? param : "");
+
+    /* Make sure that client is not connected already. */
+    if (mPipeFD >= 0) {
+        LOGE("%s: Qemu client is already connected", __FUNCTION__);
+        return EINVAL;
+    }
+
+    /* Select one of the two: 'factory', or 'emulated camera' service */
+    if (param == NULL || *param == '\0') {
+        /* No parameters: connect to the factory service. */
+        char pipe_name[512];
+        snprintf(pipe_name, sizeof(pipe_name), "qemud:%s", mCameraServiceName);
+        mPipeFD = qemu_pipe_open(pipe_name);
+    } else {
+        /* One extra char ':' that separates service name and parameters + six
+         * characters for 'qemud:'. This is required by qemu pipe protocol. */
+        char* connection_str = new char[strlen(mCameraServiceName) +
+                                        strlen(param) + 8];
+        sprintf(connection_str, "qemud:%s:%s", mCameraServiceName, param);
+
+        mPipeFD = qemu_pipe_open(connection_str);
+        delete[] connection_str;
+    }
+    if (mPipeFD < 0) {
+        LOGE("%s: Unable to connect to the camera service '%s': %s",
+             __FUNCTION__, param ? param : "Factory", strerror(errno));
+        return errno ? errno : EINVAL;
+    }
+
+    return NO_ERROR;
+}
+
+void QemuClient::disconnectClient()
+{
+    LOGV("%s", __FUNCTION__);
+
+    if (mPipeFD >= 0) {
+        close(mPipeFD);
+        mPipeFD = -1;
+    }
+}
+
+status_t QemuClient::sendMessage(const void* data, size_t data_size)
+{
+    if (mPipeFD < 0) {
+        LOGE("%s: Qemu client is not connected", __FUNCTION__);
+        return EINVAL;
+    }
+
+    /* Note that we don't use here qemud_client_send, since with qemu pipes we
+     * don't need to provide payload size prior to payload when we're writing to
+     * the pipe. So, we can use simple write, and qemu pipe will take care of the
+     * rest, calling the receiving end with the number of bytes transferred. */
+    const size_t written = qemud_fd_write(mPipeFD, data, data_size);
+    if (written == data_size) {
+        return NO_ERROR;
+    } else {
+        LOGE("%s: Error sending data via qemu pipe: '%s'",
+             __FUNCTION__, strerror(errno));
+        return errno ? errno : EIO;
+    }
+}
+
+status_t QemuClient::receiveMessage(void** data, size_t* data_size)
+{
+    *data = NULL;
+    *data_size = 0;
+
+    if (mPipeFD < 0) {
+        LOGE("%s: Qemu client is not connected", __FUNCTION__);
+        return EINVAL;
+    }
+
+    /* The way the service replies to a query, it sends payload size first, and
+     * then it sends the payload itself. Note that payload size is sent as a
+     * string, containing 8 characters representing a hexadecimal payload size
+     * value. Note also, that the string doesn't contain zero-terminator. */
+    size_t payload_size;
+    char payload_size_str[9];
+    int rd_res = qemud_fd_read(mPipeFD, payload_size_str, 8);
+    if (rd_res != 8) {
+        LOGE("%s: Unable to obtain payload size: %s",
+             __FUNCTION__, strerror(errno));
+        return errno ? errno : EIO;
+    }
+
+    /* Convert payload size. */
+    errno = 0;
+    payload_size_str[8] = '\0';
+    payload_size = strtol(payload_size_str, NULL, 16);
+    if (errno) {
+        LOGE("%s: Invalid payload size '%s'", __FUNCTION__, payload_size_str);
+        return EIO;
+    }
+
+    /* Allocate payload data buffer, and read the payload there. */
+    *data = malloc(payload_size);
+    if (*data == NULL) {
+        LOGE("%s: Unable to allocate %d bytes payload buffer",
+             __FUNCTION__, payload_size);
+        return ENOMEM;
+    }
+    rd_res = qemud_fd_read(mPipeFD, *data, payload_size);
+    if (static_cast<size_t>(rd_res) == payload_size) {
+        *data_size = payload_size;
+        return NO_ERROR;
+    } else {
+        LOGE("%s: Read size %d doesnt match expected payload size %d: %s",
+             __FUNCTION__, rd_res, payload_size, strerror(errno));
+        free(*data);
+        *data = NULL;
+        return errno ? errno : EIO;
+    }
+}
+
+status_t QemuClient::doQuery(QemuQuery* query)
+{
+    /* Make sure that query has been successfuly constructed. */
+    if (query->mQueryDeliveryStatus != NO_ERROR) {
+        LOGE("%s: Query is invalid", __FUNCTION__);
+        return query->mQueryDeliveryStatus;
+    }
+
+    LOGQ("Send query '%s'", query->mQuery);
+
+    /* Send the query. */
+    status_t res = sendMessage(query->mQuery, strlen(query->mQuery) + 1);
+    if (res == NO_ERROR) {
+        /* Read the response. */
+        res = receiveMessage(reinterpret_cast<void**>(&query->mReplyBuffer),
+                      &query->mReplySize);
+        if (res == NO_ERROR) {
+            LOGQ("Response to query '%s': Status = '%.2s', %d bytes in response",
+                 query->mQuery, query->mReplyBuffer, query->mReplySize);
+        } else {
+            LOGE("%s Response to query '%s' has failed: %s",
+                 __FUNCTION__, query->mQuery, strerror(res));
+        }
+    } else {
+        LOGE("%s: Send query '%s' failed: %s",
+             __FUNCTION__, query->mQuery, strerror(res));
+    }
+
+    /* Complete the query, and return its completion handling status. */
+    const status_t res1 = query->completeQuery(res);
+    LOGE_IF(res1 != NO_ERROR && res1 != res,
+            "%s: Error %d in query '%s' completion",
+            __FUNCTION__, res1, query->mQuery);
+    return res1;
+}
+
+/****************************************************************************
+ * Qemu client for the 'factory' service.
+ ***************************************************************************/
+
+/*
+ * Factory service queries.
+ */
+
+/* Queries list of cameras connected to the host. */
+const char FactoryQemuClient::mQueryList[] = "list";
+
+FactoryQemuClient::FactoryQemuClient()
+    : QemuClient()
+{
+}
+
+FactoryQemuClient::~FactoryQemuClient()
+{
+}
+
+status_t FactoryQemuClient::listCameras(char** list)
+{
+    LOGV("%s", __FUNCTION__);
+
+    QemuQuery query(mQueryList);
+    if (doQuery(&query) || !query.isQuerySucceeded()) {
+        LOGE("%s: List cameras query failed: %s", __FUNCTION__,
+             query.mReplyData ? query.mReplyData : "No error message");
+        return query.getCompletionStatus();
+    }
+
+    /* Make sure there is a list returned. */
+    if (query.mReplyDataSize == 0) {
+        LOGE("%s: No camera list is returned.", __FUNCTION__);
+        return EINVAL;
+    }
+
+    /* Copy the list over. */
+    *list = (char*)malloc(query.mReplyDataSize);
+    if (*list != NULL) {
+        memcpy(*list, query.mReplyData, query.mReplyDataSize);
+        LOGD("Emulated camera list: %s", *list);
+        return NO_ERROR;
+    } else {
+        LOGE("%s: Unable to allocate %d bytes",
+             __FUNCTION__, query.mReplyDataSize);
+        return ENOMEM;
+    }
+}
+
+/****************************************************************************
+ * Qemu client for an 'emulated camera' service.
+ ***************************************************************************/
+
+/*
+ * Emulated camera queries
+ */
+
+/* Connect to the camera device. */
+const char CameraQemuClient::mQueryConnect[]    = "connect";
+/* Disconect from the camera device. */
+const char CameraQemuClient::mQueryDisconnect[] = "disconnect";
+/* Start capturing video from the camera device. */
+const char CameraQemuClient::mQueryStart[]      = "start";
+/* Stop capturing video from the camera device. */
+const char CameraQemuClient::mQueryStop[]       = "stop";
+/* Get next video frame from the camera device. */
+const char CameraQemuClient::mQueryFrame[]      = "frame";
+
+CameraQemuClient::CameraQemuClient()
+    : QemuClient()
+{
+}
+
+CameraQemuClient::~CameraQemuClient()
+{
+
+}
+
+status_t CameraQemuClient::queryConnect()
+{
+    LOGV("%s", __FUNCTION__);
+
+    QemuQuery query(mQueryConnect);
+    doQuery(&query);
+    const status_t res = query.getCompletionStatus();
+    LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
+            __FUNCTION__, query.mReplyData ? query.mReplyData :
+                                             "No error message");
+    return res;
+}
+
+status_t CameraQemuClient::queryDisconnect()
+{
+    LOGV("%s", __FUNCTION__);
+
+    QemuQuery query(mQueryDisconnect);
+    doQuery(&query);
+    const status_t res = query.getCompletionStatus();
+    LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
+            __FUNCTION__, query.mReplyData ? query.mReplyData :
+                                             "No error message");
+    return res;
+}
+
+status_t CameraQemuClient::queryStart(uint32_t pixel_format,
+                                      int width,
+                                      int height)
+{
+    LOGV("%s", __FUNCTION__);
+
+    char query_str[256];
+    snprintf(query_str, sizeof(query_str), "%s dim=%dx%d pix=%d",
+             mQueryStart, width, height, pixel_format);
+    QemuQuery query(query_str);
+    doQuery(&query);
+    const status_t res = query.getCompletionStatus();
+    LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
+            __FUNCTION__, query.mReplyData ? query.mReplyData :
+                                             "No error message");
+    return res;
+}
+
+status_t CameraQemuClient::queryStop()
+{
+    LOGV("%s", __FUNCTION__);
+
+    QemuQuery query(mQueryStop);
+    doQuery(&query);
+    const status_t res = query.getCompletionStatus();
+    LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
+            __FUNCTION__, query.mReplyData ? query.mReplyData :
+                                             "No error message");
+    return res;
+}
+
+status_t CameraQemuClient::queryFrame(void* vframe,
+                                      void* pframe,
+                                      size_t vframe_size,
+                                      size_t pframe_size)
+{
+    LOGV("%s", __FUNCTION__);
+
+    char query_str[256];
+    snprintf(query_str, sizeof(query_str), "%s video=%d preview=%d",
+             mQueryFrame, (vframe && vframe_size) ? vframe_size : 0,
+                           (pframe && pframe_size) ? pframe_size : 0);
+    QemuQuery query(query_str);
+    doQuery(&query);
+    const status_t res = query.getCompletionStatus();
+    if( res != NO_ERROR) {
+        LOGE("%s: Query failed: %s",
+             __FUNCTION__, query.mReplyData ? query.mReplyData :
+                                              "No error message");
+        return res;
+    }
+
+    /* Copy requested frames. */
+    size_t cur_offset = 0;
+    const uint8_t* frame = reinterpret_cast<const uint8_t*>(query.mReplyData);
+    /* Video frame is always first. */
+    if (vframe != NULL && vframe_size != 0) {
+        /* Make sure that video frame is in. */
+        if ((query.mReplyDataSize - cur_offset) >= vframe_size) {
+            memcpy(vframe, frame, vframe_size);
+            cur_offset += vframe_size;
+        } else {
+            LOGE("%s: Reply %d bytes is to small to contain %d bytes video frame",
+                 __FUNCTION__, query.mReplyDataSize - cur_offset, vframe_size);
+            return EINVAL;
+        }
+    }
+    if (pframe != NULL && pframe_size != 0) {
+        /* Make sure that preview frame is in. */
+        if ((query.mReplyDataSize - cur_offset) >= pframe_size) {
+            memcpy(pframe, frame + cur_offset, pframe_size);
+            cur_offset += pframe_size;
+        } else {
+            LOGE("%s: Reply %d bytes is to small to contain %d bytes preview frame",
+                 __FUNCTION__, query.mReplyDataSize - cur_offset, pframe_size);
+            return EINVAL;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+}; /* namespace android */
diff --git a/tools/emulator/system/camera/QemuClient.h b/tools/emulator/system/camera/QemuClient.h
new file mode 100755
index 0000000..c0b8e61
--- /dev/null
+++ b/tools/emulator/system/camera/QemuClient.h
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HW_EMULATOR_CAMERA_QEMU_CLIENT_H
+#define HW_EMULATOR_CAMERA_QEMU_CLIENT_H
+
+/*
+ * Contains declaration of classes that encapsulate connection to camera services
+ * in the emulator via qemu pipe.
+ */
+
+#include <hardware/qemud.h>
+
+namespace android {
+
+/****************************************************************************
+ * Qemu query
+ ***************************************************************************/
+
+/* Encapsulates a query to the emulator.
+ * Guest exchanges data with the emulator via queries sent over the qemu pipe.
+ * The queries as well as replies to the queries are all strings (except for the
+ * 'frame' query where reply is a framebuffer).
+ * Each query is formatted as such:
+ *
+ *      "<query name>[ <parameters>]",
+ *
+ * where <query name> is a string representing query name, and <parameters> are
+ * optional parameters for the query. If parameters are present, they must be
+ * separated from the query name with a single space, and they must be formatted
+ * as such:
+ *
+ *      "<name1>=<value1> <name2>=<value2> ... <nameN>=<valueN>"
+ *
+ * I.e.:
+ *  - Every parameter must have a name, and a value.
+ *  - Name and value must be separated with '='.
+ *  - No spaces are allowed around '=' separating name and value.
+ *  - Parameters must be separated with a single space character.
+ *  - No '=' character is allowed in name and in value.
+ *
+ * There are certain restrictions on strings used in the query:
+ *  - Spaces are allowed only as separators.
+ *  - '=' are allowed only to divide parameter names from parameter values.
+ *
+ * Emulator replies to each query in two chunks:
+ * - 8 bytes encoding the payload size as a string containing hexadecimal
+ *   representation of the payload size value. This is done in order to simplify
+ *   dealing with different endianness on the host, and on the guest.
+ * - Payload, whose size is defined by the first chunk.
+ *
+ * Every payload always begins with two characters, encoding the result of the
+ * query:
+ *  - 'ok' Encoding the success
+ *  - 'ko' Encoding a failure.
+ * After that payload may have optional data. If payload has more data following
+ * the query result, there is a ':' character separating them. If payload carries
+ * only the result, it always ends with a zero-terminator. So, payload 'ok'/'ko'
+ * prefix is always 3 bytes long: it either includes a zero-terminator, if there
+ * is no data, or a ':' separator.
+ */
+class QemuQuery {
+public:
+    /* Constructs an uninitialized QemuQuery instance. */
+    QemuQuery();
+
+    /* Constructs and initializes QemuQuery instance for a query.
+     * Param:
+     *  query_string - Query string. This constructor can also be used to
+     *      construct a query that doesn't have parameters. In this case query
+     *      name can be passed as a parameter here.
+     */
+    explicit QemuQuery(const char* query_string);
+
+    /* Constructs and initializes QemuQuery instance for a query with parameters.
+     * Param:
+     *  query_name - Query name.
+     *  query_param - Query parameters. Can be NULL.
+     */
+    QemuQuery(const char* query_name, const char* query_param);
+
+    /* Destructs QemuQuery instance. */
+    ~QemuQuery();
+
+    /****************************************************************************
+     * Public API
+     ***************************************************************************/
+
+    /* Creates new query.
+     * Note: this method will reset this instance prior to creating a new query
+     * in order to discard possible "leftovers" from the previous query.
+     * Param:
+     *  query_name - Query name.
+     *  query_param - Query parameters. Can be NULL.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    status_t createQuery(const char* name, const char* param);
+
+    /* Completes the query after a reply from the emulator.
+     * This method will parse the reply buffer, and calculate the final query
+     * status, which depends not only on the transport success / failure, but
+     * also on 'ok' / 'ko' in the reply buffer.
+     * Param:
+     *  status - Query delivery status. This status doesn't necessarily reflects
+     *      the final query status (which is defined by 'ok'/'ko' prefix in the
+     *      reply buffer). This status simply states whether or not the query has
+     *      been sent, and a reply has been received successfuly. However, if
+     *      this status indicates a failure, it means that the entire query has
+     *      failed.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status on failure. Note that
+     *  status returned here just signals whether or not the method has succeeded.
+     *  Use isQuerySucceeded() / getCompletionStatus() methods of this class to
+     *  check the final query status.
+     */
+    status_t completeQuery(status_t status);
+
+    /* Resets the query from a previous use. */
+    void resetQuery();
+
+    /* Checks if query has succeeded.
+     * Note that this method must be called after completeQuery() method of this
+     * class has been executed.
+     */
+    inline bool isQuerySucceeded() const {
+        return mQueryDeliveryStatus == NO_ERROR && mReplyStatus != 0;
+    }
+
+    /* Gets final completion status of the query.
+     * Note that this method must be called after completeQuery() method of this
+     * class has been executed.
+     * Return:
+     *  NO_ERROR if query has succeeded, or an appropriate error status on query
+     *  failure.
+     */
+    inline status_t getCompletionStatus() const {
+        if (mQueryDeliveryStatus == NO_ERROR) {
+            if (mReplyStatus) {
+                return NO_ERROR;
+            } else {
+                return EINVAL;
+            }
+        } else {
+            return mQueryDeliveryStatus;
+        }
+    }
+
+    /****************************************************************************
+     * Public data memebers
+     ***************************************************************************/
+
+public:
+    /* Query string. */
+    char*       mQuery;
+    /* Query delivery status. */
+    status_t    mQueryDeliveryStatus;
+    /* Reply buffer */
+    char*       mReplyBuffer;
+    /* Reply data (past 'ok'/'ko'). If NULL, there were no data in reply. */
+    char*       mReplyData;
+    /* Reply buffer size. */
+    size_t      mReplySize;
+    /* Reply data size. */
+    size_t      mReplyDataSize;
+    /* Reply status: 1 - ok, 0 - ko. */
+    int         mReplyStatus;
+
+    /****************************************************************************
+     * Private data memebers
+     ***************************************************************************/
+
+protected:
+    /* Preallocated buffer for small queries. */
+    char    mQueryPrealloc[256];
+};
+
+/****************************************************************************
+ * Qemu client base
+ ***************************************************************************/
+
+/* Encapsulates a connection to the 'camera' service in the emulator via qemu
+ * pipe.
+ */
+class QemuClient {
+public:
+    /* Constructs QemuClient instance. */
+    QemuClient();
+
+    /* Destructs QemuClient instance. */
+    virtual ~QemuClient();
+
+    /****************************************************************************
+     * Qemu client API
+     ***************************************************************************/
+
+public:
+    /* Connects to the 'camera' service in the emulator via qemu pipe.
+     * Param:
+     *  param - Parameters to pass to the camera service. There are two types of
+     *      camera services implemented by the emulator. The first one is a
+     *      'camera factory' type of service that provides list of cameras
+     *      connected to the host. Another one is an 'emulated camera' type of
+     *      service that provides interface to a camera connected to the host. At
+     *      the connection time emulator makes distinction between the two by
+     *      looking at connection parameters: no parameters means connection to
+     *      the 'factory' service, while connection with parameters means
+     *      connection to an 'emulated camera' service, where camera is identified
+     *      by one of the connection parameters. So, passing NULL, or an empty
+     *      string to this method will establish a connection with the 'factory'
+     *      service, while not empty string passed here will establish connection
+     *      with an 'emulated camera' service. Parameters defining the emulated
+     *      camera must be formatted as such:
+     *
+     *          "name=<device name> [inp_channel=<input channel #>]",
+     *
+     *      where 'device name' is a required parameter defining name of the
+     *      camera device, and 'input channel' is an optional parameter (positive
+     *      integer), defining the input channel to use on the camera device.
+     *      Note that device name passed here must have been previously obtained
+     *      from the factory service using 'list' query.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status.
+     */
+    virtual status_t connectClient(const char* param);
+
+    /* Disconnects from the service. */
+    virtual void disconnectClient();
+
+    /* Sends data to the service.
+     * Param:
+     *  data, data_size - Data to send.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status on failure.
+     */
+    virtual status_t sendMessage(const void* data, size_t data_size);
+
+    /* Receives data from the service.
+     * This method assumes that data to receive will come in two chunks: 8
+     * characters encoding the payload size in hexadecimal string, followed by
+     * the paylod (if any).
+     * This method will allocate data buffer where to receive the response.
+     * Param:
+     *  data - Upon success contains address of the allocated data buffer with
+     *      the data received from the service. The caller is responsible for
+     *      freeing allocated data buffer.
+     *  data_size - Upon success contains size of the data received from the
+     *      service.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status on failure.
+     */
+    virtual status_t receiveMessage(void** data, size_t* data_size);
+
+    /* Sends a query, and receives a response from the service.
+     * Param:
+     *  query - Query to send to the service. When this method returns, the query
+     *  is completed, and all its relevant data members are properly initialized.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status on failure. Note that
+     *  status returned here is not the final query status. Use isQuerySucceeded(),
+     *  or getCompletionStatus() method on the query object to see if it has
+     *  succeeded. However, if this method returns a failure, it means that the
+     *  query has failed, and there is no guarantee that its data members are
+     *  properly initialized (except for the 'mQueryDeliveryStatus', which is
+     *  always in the proper state).
+     */
+    virtual status_t doQuery(QemuQuery* query);
+
+    /****************************************************************************
+     * Data members
+     ***************************************************************************/
+
+protected:
+    /* Qemu pipe handle. */
+    int     mPipeFD;
+
+private:
+    /* Camera service name. */
+    static const char mCameraServiceName[];
+};
+
+/****************************************************************************
+ * Qemu client for the 'factory' service.
+ ***************************************************************************/
+
+/* Encapsulates QemuClient for the 'factory' service. */
+class FactoryQemuClient : public QemuClient {
+public:
+    /* Constructs FactoryQemuClient instance. */
+    FactoryQemuClient();
+
+    /* Destructs FactoryQemuClient instance. */
+    ~FactoryQemuClient();
+
+    /****************************************************************************
+     * Public API
+     ***************************************************************************/
+
+public:
+    /* Lists camera devices connected to the host.
+     * Param:
+     *  list - Upon success contains a list of cameras connected to the host. The
+     *      list returned here is represented as a string, containing multiple
+     *      lines separated with '\n', where each line represents a camera. Each
+     *      camera line is formatted as such:
+     *
+     *          "name=<device name> channel=<num> pix=<num> framedims=<dimensions>\n"
+     *
+     *      Where:
+     *      - 'name' is the name of the camera device attached to the host. This
+     *        name must be used for subsequent connection to the 'emulated camera'
+     *        service for that camera.
+     *      - 'channel' - input channel number (positive int) to use to communicate
+     *        with the camera.
+     *      - 'pix' - pixel format (a "fourcc" uint), chosen for the video frames
+     *        by the camera service.
+     *      - 'framedims' contains a list of frame dimensions supported by the
+     *        camera for the chosen pixel format. Each etry in the list is in form
+     *        '<width>x<height>', where 'width' and 'height' are numeric values
+     *        for width and height of a supported frame dimension. Entries in
+     *        this list are separated with ',' with no spaces between the entries.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status on failure.
+     */
+    status_t listCameras(char** list);
+
+    /****************************************************************************
+     * Names of the queries available for the emulated camera factory.
+     ***************************************************************************/
+
+private:
+    /* List cameras connected to the host. */
+    static const char mQueryList[];
+};
+
+/****************************************************************************
+ * Qemu client for an 'emulated camera' service.
+ ***************************************************************************/
+
+/* Encapsulates QemuClient for an 'emulated camera' service.
+ */
+class CameraQemuClient : public QemuClient {
+public:
+    /* Constructs CameraQemuClient instance. */
+    CameraQemuClient();
+
+    /* Destructs CameraQemuClient instance. */
+    ~CameraQemuClient();
+
+    /****************************************************************************
+     * Public API
+     ***************************************************************************/
+
+public:
+    /* Queries camera connection.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status on failure.
+     */
+    status_t queryConnect();
+
+    /* Queries camera disconnection.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status on failure.
+     */
+    status_t queryDisconnect();
+
+    /* Queries camera to start capturing video.
+     * Param:
+     *  pixel_format - Pixel format that is used by the client to push video
+     *      frames to the camera framework.
+     *  width, height - Frame dimensions, requested by the framework.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status on failure.
+     */
+    status_t queryStart(uint32_t pixel_format, int width, int height);
+
+    /* Queries camera to stop capturing video.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status on failure.
+     */
+    status_t queryStop();
+
+    /* Queries camera for the next video frame.
+     * Param:
+     *  vframe, vframe_size - Define buffer, allocated to receive a video frame.
+     *      Any of these parameters can be 0, indicating that the caller is
+     *      interested only in preview frame.
+     *  pframe, pframe_size - Define buffer, allocated to receive a preview frame.
+     *      Any of these parameters can be 0, indicating that the caller is
+     *      interested only in video frame.
+     * Return:
+     *  NO_ERROR on success, or an appropriate error status on failure.
+     */
+    status_t queryFrame(void* vframe,
+                        void* pframe,
+                        size_t vframe_size,
+                        size_t pframe_size);
+
+    /****************************************************************************
+     * Names of the queries available for the emulated camera.
+     ***************************************************************************/
+
+private:
+    /* Connect to the camera. */
+    static const char mQueryConnect[];
+    /* Disconnect from the camera. */
+    static const char mQueryDisconnect[];
+    /* Start video capturing. */
+    static const char mQueryStart[];
+    /* Stop video capturing. */
+    static const char mQueryStop[];
+    /* Query frame(s). */
+    static const char mQueryFrame[];
+};
+
+}; /* namespace android */
+
+#endif  /* HW_EMULATOR_CAMERA_QEMU_CLIENT_H */
diff --git a/tools/emulator/system/camera/callback_notifier.cpp b/tools/emulator/system/camera/callback_notifier.cpp
deleted file mode 100644
index 69c94a6..0000000
--- a/tools/emulator/system/camera/callback_notifier.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Contains implementation of a class CallbackNotifier that manages callbacks set
- * via set_callbacks, enable_msg_type, and disable_msg_type camera HAL API.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_CallbackNotifier"
-#include <cutils/log.h>
-#include <media/stagefright/MetadataBufferType.h>
-#include "emulated_camera_device.h"
-#include "callback_notifier.h"
-
-namespace android {
-
-/* Descriptor for video frame metadata. */
-struct VideoFrameMetadata
-{
-    /* Required field that defines metadata buffer type. */
-    MetadataBufferType  type;
-
-    /*
-     * TODO: This is taken from a sample code. It seems to work, but requires
-     * clarifications on what metadata structure should look like!
-     */
-
-    const void*         frame;
-    int                 offset;
-    camera_memory_t*    holder;
-};
-
-/* String representation of camera messages. */
-static const char* _camera_messages[] =
-{
-    "CAMERA_MSG_ERROR",
-    "CAMERA_MSG_SHUTTER",
-    "CAMERA_MSG_FOCUS",
-    "CAMERA_MSG_ZOOM",
-    "CAMERA_MSG_PREVIEW_FRAME",
-    "CAMERA_MSG_VIDEO_FRAME",
-    "CAMERA_MSG_POSTVIEW_FRAME",
-    "CAMERA_MSG_RAW_IMAGE",
-    "CAMERA_MSG_COMPRESSED_IMAGE",
-    "CAMERA_MSG_RAW_IMAGE_NOTIFY",
-    "CAMERA_MSG_PREVIEW_METADATA"
-};
-static const int _camera_messages_num = sizeof(_camera_messages) / sizeof(char*);
-
-/* Builds an array of strings for the given set of messages.
- * Param:
- *  msg - Messages to get strings for,
- *  strings - Array where to save strings
- *  max - Maximum number of entries in the array.
- * Return:
- *  Number of strings saved into the 'strings' array.
- */
-static int _GetMessageStrings(uint32_t msg, const char** strings, int max)
-{
-    int index = 0;
-    int out = 0;
-    while (msg != 0 && out < max && index < _camera_messages_num) {
-        while ((msg & 0x1) == 0 && index < _camera_messages_num) {
-            msg >>= 1;
-            index++;
-        }
-        if ((msg & 0x1) != 0 && index < _camera_messages_num) {
-            strings[out] = _camera_messages[index];
-            out++;
-            msg >>= 1;
-            index++;
-        }
-    }
-
-    return out;
-}
-
-/* Logs messages, enabled by the mask. */
-static void _PrintMessages(uint32_t msg)
-{
-    const char* strs[_camera_messages_num];
-    const int translated = _GetMessageStrings(msg, strs, _camera_messages_num);
-    for (int n = 0; n < translated; n++) {
-        LOGV("    %s", strs[n]);
-    }
-}
-
-CallbackNotifier::CallbackNotifier()
-    : notify_cb_(NULL),
-      data_cb_(NULL),
-      data_cb_timestamp_(NULL),
-      get_memory_(NULL),
-      cb_opaque_(NULL),
-      last_frame_(0),
-      frame_after_(0),
-      message_enabler_(0),
-      video_recording_enabled_(false),
-      store_meta_data_in_buffers_(true)
-{
-}
-
-CallbackNotifier::~CallbackNotifier()
-{
-}
-
-/****************************************************************************
- * Camera API
- ***************************************************************************/
-
-void CallbackNotifier::SetCallbacks(camera_notify_callback notify_cb,
-                                    camera_data_callback data_cb,
-                                    camera_data_timestamp_callback data_cb_timestamp,
-                                    camera_request_memory get_memory,
-                                    void* user)
-{
-    LOGV("%s: %p, %p, %p, %p (%p)",
-         __FUNCTION__, notify_cb, data_cb, data_cb_timestamp, get_memory, user);
-
-    Mutex::Autolock locker(&object_lock_);
-    notify_cb_ = notify_cb;
-    data_cb_ = data_cb;
-    data_cb_timestamp_ = data_cb_timestamp;
-    get_memory_ = get_memory;
-    cb_opaque_ = user;
-}
-
-void CallbackNotifier::EnableMessage(uint msg_type)
-{
-    LOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type);
-    _PrintMessages(msg_type);
-
-    Mutex::Autolock locker(&object_lock_);
-    message_enabler_ |= msg_type;
-    LOGV("**** Currently enabled messages:");
-    _PrintMessages(message_enabler_);
-}
-
-void CallbackNotifier::DisableMessage(uint msg_type)
-{
-    LOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type);
-    _PrintMessages(msg_type);
-
-    Mutex::Autolock locker(&object_lock_);
-    message_enabler_ &= ~msg_type;
-    LOGV("**** Currently enabled messages:");
-    _PrintMessages(message_enabler_);
-}
-
-int CallbackNotifier::IsMessageEnabled(uint msg_type)
-{
-    Mutex::Autolock locker(&object_lock_);
-    return message_enabler_ & ~msg_type;
-}
-
-status_t CallbackNotifier::EnableVideoRecording(int fps)
-{
-    LOGV("%s: FPS = %d", __FUNCTION__, fps);
-
-    Mutex::Autolock locker(&object_lock_);
-    video_recording_enabled_ = true;
-    last_frame_ = 0;
-    frame_after_ = 1000000 / fps;
-
-    return NO_ERROR;
-}
-
-void CallbackNotifier::DisableVideoRecording()
-{
-    LOGV("%s:", __FUNCTION__);
-
-    Mutex::Autolock locker(&object_lock_);
-    video_recording_enabled_ = false;
-    last_frame_ = 0;
-    frame_after_ = 0;
-}
-
-bool CallbackNotifier::IsVideoRecordingEnabled()
-{
-    Mutex::Autolock locker(&object_lock_);
-    return video_recording_enabled_;
-}
-
-void CallbackNotifier::ReleaseRecordingFrame(const void* opaque)
-{
-    LOGV("%s: frame = %p", __FUNCTION__, opaque);
-
-    if (opaque != NULL) {
-        const VideoFrameMetadata* meta =
-            reinterpret_cast<const VideoFrameMetadata*>(opaque);
-        if (meta->type == kMetadataBufferTypeCameraSource &&
-            meta->holder != NULL) {
-            meta->holder->release(meta->holder);
-        }
-    }
-}
-
-status_t CallbackNotifier::StoreMetaDataInBuffers(bool enable)
-{
-    LOGV("%s: %s", __FUNCTION__, enable ? "true" : "false");
-
-    Mutex::Autolock locker(&object_lock_);
-    store_meta_data_in_buffers_ = enable;
-
-    /* Return INVALID_OPERATION means HAL does not support metadata. So HAL will
-     * return actual frame data with CAMERA_MSG_VIDEO_FRRAME. Return
-     * INVALID_OPERATION to mean metadata is not supported. */
-    return INVALID_OPERATION;
-}
-
-/****************************************************************************
- * Public API
- ***************************************************************************/
-
-void CallbackNotifier::Cleanup()
-{
-    Mutex::Autolock locker(&object_lock_);
-    message_enabler_ = 0;
-    notify_cb_ = NULL;
-    data_cb_ = NULL;
-    data_cb_timestamp_ = NULL;
-    get_memory_ = NULL;
-    cb_opaque_ = NULL;
-    last_frame_ = 0;
-    frame_after_ = 0;
-    video_recording_enabled_ = false;
-    store_meta_data_in_buffers_ = true;
-}
-
-void CallbackNotifier::OnNextFrameAvailable(const void* frame,
-                                            nsecs_t timestamp,
-                                            EmulatedCameraDevice* camera_dev)
-{
-    Mutex::Autolock locker(&object_lock_);
-
-    if ((message_enabler_ & CAMERA_MSG_VIDEO_FRAME) != 0 &&
-        data_cb_timestamp_ != NULL && video_recording_enabled_ &&
-        IsTimeForNewVideoFrame()) {
-        /* Ready for new video frame. Allocate frame holder. */
-        camera_memory_t* holder =
-            get_memory_(-1, sizeof(VideoFrameMetadata), 1, NULL);
-        if (NULL != holder && NULL != holder->data) {
-            if (store_meta_data_in_buffers_) {
-                VideoFrameMetadata* meta =
-                    reinterpret_cast<VideoFrameMetadata*>(holder->data);
-                meta->type = kMetadataBufferTypeCameraSource;
-                meta->frame = frame;
-                meta->offset = 0;
-                meta->holder = holder;
-                data_cb_timestamp_(timestamp, CAMERA_MSG_VIDEO_FRAME,
-                                   holder, 0, cb_opaque_);
-                /* Allocated holder will be released by release_recording_frame
-                 * call. */
-            } else {
-                holder->data = const_cast<void*>(frame);
-                data_cb_timestamp_(timestamp, CAMERA_MSG_VIDEO_FRAME,
-                                   holder, 0, cb_opaque_);
-                holder->release(holder);
-            }
-        } else {
-            LOGE("%s: Memory failure", __FUNCTION__);
-        }
-    }
-}
-
-/****************************************************************************
- * Private API
- ***************************************************************************/
-
-bool CallbackNotifier::IsTimeForNewVideoFrame()
-{
-    timeval cur_time;
-    gettimeofday(&cur_time, NULL);
-    const uint64_t cur_mks = cur_time.tv_sec * 1000000LL + cur_time.tv_usec;
-    if ((cur_mks - last_frame_) >= frame_after_) {
-        last_frame_ = cur_mks;
-        return true;
-    }
-    return false;
-}
-
-}; /* namespace android */
diff --git a/tools/emulator/system/camera/converters.cpp b/tools/emulator/system/camera/converters.cpp
deleted file mode 100644
index 37b7caf..0000000
--- a/tools/emulator/system/camera/converters.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Contains implemenation of framebuffer conversion routines.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Converter"
-#include <cutils/log.h>
-#include "converters.h"
-
-namespace android {
-
-void YV12ToRGB565(const void* yv12, void* rgb, int width, int height)
-{
-    const int pix_total = width * height;
-    uint16_t* rgb_buf = reinterpret_cast<uint16_t*>(rgb);
-    const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
-    const uint8_t* Cb_pos = Y + pix_total;
-    const uint8_t* Cr_pos = Cb_pos + pix_total / 4;
-    const uint8_t* Cb = Cb_pos;
-    const uint8_t* Cr = Cr_pos;
-    for (int y = 0; y < height; y++) {
-        for (int x = 0; x < width; x += 2) {
-            const uint8_t nCb = *Cb; Cb++;
-            const uint8_t nCr = *Cr; Cr++;
-            *rgb_buf = YCbCrToRGB565(*Y, nCb, nCr);
-            Y++; rgb_buf++;
-            *rgb_buf = YCbCrToRGB565(*Y, nCb, nCr);
-            Y++; rgb_buf++;
-        }
-        if (y & 0x1) {
-            Cb_pos = Cb;
-            Cr_pos = Cr;
-        } else {
-            Cb = Cb_pos;
-            Cr = Cr_pos;
-        }
-    }
-}
-
-}; /* namespace android */
diff --git a/tools/emulator/system/camera/converters.h b/tools/emulator/system/camera/converters.h
deleted file mode 100644
index 8d7709f..0000000
--- a/tools/emulator/system/camera/converters.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HW_EMULATOR_CAMERA_CONVERTERS_H
-#define HW_EMULATOR_CAMERA_CONVERTERS_H
-
-/*
- * Contains declaration of framebuffer conversion routines.
- */
-
-namespace android {
-
-inline uint8_t clamp(int  x)
-{
-    if (x > 255) return 255;
-    if (x < 0)   return 0;
-    return static_cast<uint8_t>(x);
-}
-
-/*
- * RGB565 color masks
- */
-
-static const int kRed   = 0xf800;
-static const int kGreen = 0x07e0;
-static const int kBlue  = 0x001f;
-
-/*
- * RGB -> YCbCr conversion constants and macros
- */
-
-static const double kR0     = 0.299;
-static const double kR1     = 0.587;
-static const double kR2     = 0.114;
-static const double kR3     = 0.169;
-static const double kR4     = 0.331;
-static const double kR5     = 0.499;
-static const double kR6     = 0.499;
-static const double kR7     = 0.418;
-static const double kR8     = 0.0813;
-
-#define RGB2Y(R,G,B)    static_cast<uint8_t>(kR0*R + kR1*G + kR2*B)
-#define RGB2Cb(R,G,B)   static_cast<uint8_t>(-kR3*R - kR4*G + kR5*B + 128)
-#define RGB2Cr(R,G,B)   static_cast<uint8_t>(kR6*R - kR7*G - kR8*B + 128)
-
-/* Converts RGB565 color to YCbCr */
-inline void RGB565ToYCbCr(uint16_t rgb, uint8_t* y, uint8_t* Cb, uint8_t* Cr)
-{
-    const uint32_t r = (rgb & kRed) >> 11;
-    const uint32_t g = (rgb & kGreen) >> 5;
-    const uint32_t b = rgb & kBlue;
-
-    *y = RGB2Y(r,g,b);
-    *Cb = RGB2Cb(r,g,b);
-    *Cr = RGB2Cr(r,g,b);
-}
-
-/* Gets a 'Y' value for RGB565 color. */
-inline uint8_t RGB565ToY(uint16_t rgb)
-{
-    const uint32_t r = (rgb & kRed) >> 11;
-    const uint32_t g = (rgb & kGreen) >> 5;
-    const uint32_t b = rgb & kBlue;
-
-    return RGB2Y(r,g,b);
-}
-
-/*
- * YCbCr -> RGB conversion constants and macros
- */
-static const double kY0     = 1.402;
-static const double kY1     = 0.344;
-static const double kY2     = 0.714;
-static const double kY3     = 1.772;
-
-#define YCbCr2R(Y, Cb, Cr)  clamp(Y + kY0*(Cr-128))
-#define YCbCr2G(Y, Cb, Cr)  clamp(Y - kY1*(Cb-128) - kY2*(Cr-128))
-#define YCbCr2B(Y, Cb, Cr)  clamp(Y + kY3*(Cb-128))
-
-/* Converts YCbCr color to RGB565. */
-inline uint16_t YCbCrToRGB565(uint8_t y, uint8_t Cb, uint8_t Cr)
-{
-    const uint16_t r = YCbCr2R(y, Cb, Cr) & 0x1f;
-    const uint16_t g = YCbCr2G(y, Cb, Cr) & 0x3f;
-    const uint16_t b = YCbCr2B(y, Cb, Cr) & 0x1f;
-
-    return b | (g << 5) | (r << 11);
-}
-
-/* YCbCr pixel descriptor. */
-struct YCbCrPixel {
-    uint8_t     Y;
-    uint8_t     Cb;
-    uint8_t     Cr;
-
-    inline YCbCrPixel()
-        : Y(0), Cb(0), Cr(0)
-    {
-    }
-
-    inline explicit YCbCrPixel(uint16_t rgb565)
-    {
-        RGB565ToYCbCr(rgb565, &Y, &Cb, &Cr);
-    }
-
-    inline void get(uint8_t* pY, uint8_t* pCb, uint8_t* pCr) const
-    {
-        *pY = Y; *pCb = Cb; *pCr = Cr;
-    }
-};
-
-/* Converts an YV12 framebuffer to RGB565 framebuffer.
- * Param:
- *  yv12 - YV12 framebuffer.
- *  rgb - RGB565 framebuffer.
- *  width, height - Dimensions for both framebuffers.
- */
-void YV12ToRGB565(const void* yv12, void* rgb, int width, int height);
-
-}; /* namespace android */
-
-#endif  /* HW_EMULATOR_CAMERA_CONVERTERS_H */
-
diff --git a/tools/emulator/system/camera/emulated_camera_device.cpp b/tools/emulator/system/camera/emulated_camera_device.cpp
deleted file mode 100644
index 02d18ae..0000000
--- a/tools/emulator/system/camera/emulated_camera_device.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Contains implementation of an abstract class EmulatedCameraDevice that defines
- * functionality expected from an emulated physical camera device:
- *  - Obtaining and setting camera parameters
- *  - Capturing frames
- *  - Streaming video
- *  - etc.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Device"
-#include <cutils/log.h>
-#include <sys/select.h>
-#include "emulated_camera_device.h"
-#include "converters.h"
-
-namespace android {
-
-EmulatedCameraDevice::EmulatedCameraDevice(EmulatedCamera* camera_hal)
-    : object_lock_(),
-      camera_hal_(camera_hal),
-      current_frame_(NULL),
-      state_(ECDS_CONSTRUCTED)
-{
-}
-
-EmulatedCameraDevice::~EmulatedCameraDevice()
-{
-    if (current_frame_ != NULL) {
-        delete[] current_frame_;
-    }
-}
-
-/****************************************************************************
- * Emulated camera device public API
- ***************************************************************************/
-
-status_t EmulatedCameraDevice::Initialize()
-{
-    LOGV("%s", __FUNCTION__);
-
-    if (IsInitialized()) {
-        LOGW("%s: Emulated camera device is already initialized: state_ = %d",
-             __FUNCTION__, state_);
-        return NO_ERROR;
-    }
-
-    /* Instantiate worker thread object. */
-    worker_thread_ = new WorkerThread(this);
-    if (worker_thread() == NULL) {
-        LOGE("%s: Unable to instantiate worker thread object", __FUNCTION__);
-        return ENOMEM;
-    }
-
-    state_ = ECDS_INITIALIZED;
-
-    return NO_ERROR;
-}
-
-status_t EmulatedCameraDevice::StartCapturing(int width,
-                                              int height,
-                                              uint32_t pix_fmt)
-{
-    LOGV("%s", __FUNCTION__);
-
-    /* Validate pixel format, and calculate framebuffer size at the same time. */
-    switch (pix_fmt) {
-        case V4L2_PIX_FMT_YVU420:
-            framebuffer_size_ = (width * height * 12) / 8;
-            break;
-
-        default:
-            LOGE("%s: Unknown pixel format %.4s",
-                 __FUNCTION__, reinterpret_cast<const char*>(&pix_fmt));
-            return EINVAL;
-    }
-
-    /* Cache framebuffer info. */
-    frame_width_ = width;
-    frame_height_ = height;
-    pixel_format_ = pix_fmt;
-    total_pixels_ = width * height;
-
-    /* Allocate framebuffer. */
-    current_frame_ = new uint8_t[GetFrameBufferSize()];
-    if (current_frame_ == NULL) {
-        LOGE("%s: Unable to allocate framebuffer", __FUNCTION__);
-        return ENOMEM;
-    }
-    /* Calculate Cb/Cr panes inside the framebuffer. */
-    frame_Cb_ = current_frame_ + total_pixels_;
-    frame_Cr_ = frame_Cb_ + total_pixels_ / 4;
-
-    /* Start the camera. */
-    const status_t res = StartCamera();
-    if (res == NO_ERROR) {
-        LOGD("Camera device is started:\n"
-             "      Framebuffer dimensions: %dx%d.\n"
-             "      Pixel format: %.4s",
-             frame_width_, frame_height_,
-             reinterpret_cast<const char*>(&pixel_format_));
-    } else {
-        delete[] current_frame_;
-        current_frame_ = NULL;
-    }
-
-    return res;
-}
-
-status_t EmulatedCameraDevice::StopCapturing()
-{
-    LOGV("%s", __FUNCTION__);
-
-    /* Stop the camera. */
-    const status_t res = StopCamera();
-    if (res == NO_ERROR) {
-        /* Release resources allocated for capturing. */
-        if (current_frame_ != NULL) {
-            delete[] current_frame_;
-            current_frame_ = NULL;
-        }
-    }
-
-    return res;
-}
-
-status_t EmulatedCameraDevice::GetCurrentFrame(void* buffer)
-{
-    Mutex::Autolock locker(&object_lock_);
-
-    if (!IsCapturing() || current_frame_ == NULL) {
-        LOGE("%s is called on a device that is not in the capturing state",
-            __FUNCTION__);
-        return EINVAL;
-    }
-
-    memcpy(buffer, current_frame_, GetFrameBufferSize());
-
-    return NO_ERROR;
-}
-
-status_t EmulatedCameraDevice::GetCurrentPreviewFrame(void* buffer)
-{
-    Mutex::Autolock locker(&object_lock_);
-
-    if (!IsCapturing() || current_frame_ == NULL) {
-        LOGE("%s is called on a device that is not in the capturing state",
-            __FUNCTION__);
-        return EINVAL;
-    }
-
-    /* In emulation the framebuffer is never RGB. */
-    switch (pixel_format_) {
-        case V4L2_PIX_FMT_YVU420:
-            YV12ToRGB565(current_frame_, buffer, frame_width_, frame_height_);
-            return NO_ERROR;
-
-        default:
-            LOGE("%s: Unknown pixel format %d", __FUNCTION__, pixel_format_);
-            return EINVAL;
-    }
-}
-
-/****************************************************************************
- * Worker thread management.
- ***************************************************************************/
-
-status_t EmulatedCameraDevice::StartWorkerThread()
-{
-    LOGV("%s", __FUNCTION__);
-
-    if (!IsInitialized()) {
-        LOGE("%s: Emulated camera device is not initialized", __FUNCTION__);
-        return EINVAL;
-    }
-
-    const status_t ret = worker_thread()->Start();
-    LOGE_IF(ret != NO_ERROR, "%s: Unable to start worker thread: %d -> %s",
-            __FUNCTION__, ret, strerror(ret));
-
-    return ret;
-}
-
-status_t EmulatedCameraDevice::StopWorkerThread()
-{
-    LOGV("%s", __FUNCTION__);
-
-    if (!IsInitialized()) {
-        LOGE("%s: Emulated camera device is not initialized", __FUNCTION__);
-        return EINVAL;
-    }
-
-    worker_thread()->Stop();
-
-    return NO_ERROR;
-}
-
-bool EmulatedCameraDevice::InWorkerThread()
-{
-    /* This will end the thread loop, and will terminate the thread. */
-    return false;
-}
-
-/****************************************************************************
- * Worker thread implementation.
- ***************************************************************************/
-
-status_t EmulatedCameraDevice::WorkerThread::readyToRun()
-{
-    LOGV("Starting emulated camera device worker thread...");
-
-    LOGW_IF(thread_control_ >= 0 || control_fd_ >= 0,
-            "%s: Thread control FDs are opened", __FUNCTION__);
-    /* Create a pair of FDs that would be used to control the thread. */
-    int thread_fds[2];
-    if (pipe(thread_fds) == 0) {
-        thread_control_ = thread_fds[1];
-        control_fd_ = thread_fds[0];
-        LOGV("Emulated device's worker thread has been started.");
-        return NO_ERROR;
-    } else {
-        LOGE("%s: Unable to create thread control FDs: %d -> %s",
-             __FUNCTION__, errno, strerror(errno));
-        return errno;
-    }
-}
-
-status_t EmulatedCameraDevice::WorkerThread::Stop()
-{
-    LOGV("Stopping emulated camera device's worker thread...");
-
-    status_t res = EINVAL;
-    if (thread_control_ >= 0) {
-        /* Send "stop" message to the thread loop. */
-        const ControlMessage msg = THREAD_STOP;
-        const int wres =
-            TEMP_FAILURE_RETRY(write(thread_control_, &msg, sizeof(msg)));
-        if (wres == sizeof(msg)) {
-            /* Stop the thread, and wait till it's terminated. */
-            res = requestExitAndWait();
-            if (res == NO_ERROR) {
-                /* Close control FDs. */
-                if (thread_control_ >= 0) {
-                    close(thread_control_);
-                    thread_control_ = -1;
-                }
-                if (control_fd_ >= 0) {
-                    close(control_fd_);
-                    control_fd_ = -1;
-                }
-                LOGV("Emulated camera device's worker thread has been stopped.");
-            } else {
-                LOGE("%s: requestExitAndWait failed: %d -> %s",
-                     __FUNCTION__, res, strerror(res));
-            }
-        } else {
-            LOGE("%s: Unable to send THREAD_STOP: %d -> %s",
-                 __FUNCTION__, errno, strerror(errno));
-            res = errno ? errno : EINVAL;
-        }
-    } else {
-        LOGE("%s: Thread control FDs are not opened", __FUNCTION__);
-    }
-
-    return res;
-}
-
-EmulatedCameraDevice::WorkerThread::SelectRes
-EmulatedCameraDevice::WorkerThread::Select(int fd, int timeout)
-{
-    fd_set fds[1];
-    struct timeval tv, *tvp = NULL;
-
-    const int fd_num = (fd >= 0) ? max(fd, control_fd_) + 1 :
-                                   control_fd_ + 1;
-    FD_ZERO(fds);
-    FD_SET(control_fd_, fds);
-    if (fd >= 0) {
-        FD_SET(fd, fds);
-    }
-    if (timeout) {
-        tv.tv_sec = timeout / 1000000;
-        tv.tv_usec = timeout % 1000000;
-        tvp = &tv;
-    }
-    int res = TEMP_FAILURE_RETRY(select(fd_num, fds, NULL, NULL, tvp));
-    if (res < 0) {
-        LOGE("%s: select returned %d and failed: %d -> %s",
-             __FUNCTION__, res, errno, strerror(errno));
-        return ERROR;
-    } else if (res == 0) {
-        /* Timeout. */
-        return TIMEOUT;
-    } else if (FD_ISSET(control_fd_, fds)) {
-        /* A control event. Lets read the message. */
-        ControlMessage msg;
-        res = TEMP_FAILURE_RETRY(read(control_fd_, &msg, sizeof(msg)));
-        if (res != sizeof(msg)) {
-            LOGE("%s: Unexpected message size %d, or an error %d -> %s",
-                 __FUNCTION__, res, errno, strerror(errno));
-            return ERROR;
-        }
-        /* THREAD_STOP is the only message expected here. */
-        if (msg == THREAD_STOP) {
-            LOGV("%s: THREAD_STOP message is received", __FUNCTION__);
-            return EXIT_THREAD;
-        } else {
-            LOGE("Unknown worker thread message %d", msg);
-            return ERROR;
-        }
-    } else {
-        /* Must be an FD. */
-        LOGW_IF(fd < 0 || !FD_ISSET(fd, fds), "%s: Undefined 'select' result",
-                __FUNCTION__);
-        return READY;
-    }
-}
-
-};  /* namespace android */
diff --git a/tools/emulator/system/camera/emulated_camera_device.h b/tools/emulator/system/camera/emulated_camera_device.h
deleted file mode 100644
index 5b81cdc..0000000
--- a/tools/emulator/system/camera/emulated_camera_device.h
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H
-#define HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H
-
-/*
- * Contains declaration of an abstract class EmulatedCameraDevice that defines
- * functionality expected from an emulated physical camera device:
- *  - Obtaining and setting camera device parameters
- *  - Capturing frames
- *  - Streaming video
- *  - etc.
- */
-
-#include <utils/threads.h>
-#include "emulated_camera_common.h"
-
-namespace android {
-
-class EmulatedCamera;
-
-/* Encapsulates an abstract class EmulatedCameraDevice that defines functionality
- * expected from an emulated physical camera device:
- *  - Obtaining and setting camera device parameters
- *  - Capturing frames
- *  - Streaming video
- *  - etc.
- */
-class EmulatedCameraDevice {
-public:
-    /* Constructs EmulatedCameraDevice instance.
-     * Param:
-     *  camera_hal - Emulated camera that implements the camera HAL API, and
-     *      manages (contains) this object.
-     */
-    explicit EmulatedCameraDevice(EmulatedCamera* camera_hal);
-
-    /* Destructs EmulatedCameraDevice instance. */
-    virtual ~EmulatedCameraDevice();
-
-    /****************************************************************************
-     * Emulated camera device abstract interface
-     ***************************************************************************/
-
-public:
-    /* Connects to the camera device.
-     * This method must be called on an initialized instance of this class.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status.
-     */
-    virtual status_t Connect() = 0;
-
-    /* Disconnects from the camera device.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status. If this method is
-     *  called for already disconnected, or uninitialized instance of this class,
-     *  a successful status must be returned from this method. If this method is
-     *  called for an instance that is in "capturing" state, this method must
-     *  return a failure.
-     */
-    virtual status_t Disconnect() = 0;
-
-protected:
-    /* Starts capturing frames from the camera device.
-     *
-     * Typically, this method initializes the camera device with the settings
-     * requested by the framework through the camera HAL, and starts a worker
-     * thread that will listen to the physical device for available frames. When
-     * new frame becomes available, it will be cached in current_framebuffer_,
-     * and the containing emulated camera object will be notified via call to its
-     * OnNextFrameAvailable method. This method must be called on a connected
-     * instance of this class. If it is called on a disconnected instance, this
-     * method must return a failure.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status.
-     */
-    virtual status_t StartCamera() = 0;
-
-    /* Stops capturing frames from the camera device.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status. If this method is
-     *  called for an object that is not capturing frames, or is disconnected, or
-     *  is uninitialized, a successful status must be returned from this method.
-     */
-    virtual status_t StopCamera() = 0;
-
-    /****************************************************************************
-     * Emulated camera device public API
-     ***************************************************************************/
-
-public:
-    /* Initializes EmulatedCameraDevice instance.
-     * Derived classes should override this method in order to cache static
-     * properties of the physical device (list of supported pixel formats, frame
-     * sizes, etc.) If this method is called on an already initialized instance,
-     * it must return a successful status.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status.
-     */
-    virtual status_t Initialize();
-
-    /* Starts capturing frames from the camera device.
-     *
-     * Typically, this method caches desired frame parameters, and calls
-     * StartCamera method to start capturing video frames from the camera device.
-     * This method must be called on a connected instance of this class. If it is
-     * called on a disconnected instance, this method must return a failure.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status.
-     */
-    virtual status_t StartCapturing(int width, int height, uint32_t pix_fmt);
-
-    /* Stops capturing frames from the camera device.
-     *
-     * Typically, this method calls StopCamera method of this class, and
-     * uninitializes frame properties, saved in StartCapturing method of this
-     * class.
-     * This method must be called on a connected instance of this class. If it is
-     * called on a disconnected instance, this method must return a failure.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status.
-     */
-    virtual status_t StopCapturing();
-
-    /* Gets current fame into provided buffer.
-     * Typically, this method is called by the emulated camera (HAL) in response
-     * to a callback from the emulated camera device that gets invoked when new
-     * captured frame is available.
-     * This method must be called on an instance that is capturing frames from
-     * the physical device. If this method is called on an instance that is not
-     * capturing frames from the physical device, it must return a failure.
-     * Param:
-     *  buffer - A buffer where to return the frame. Note that the buffer must be
-     *      large enough to contain the entire frame, as defined by frame's width,
-     *      height, and pixel format that are current for the camera device.
-     */
-    virtual status_t GetCurrentFrame(void* buffer);
-
-    /* Gets current preview fame into provided buffer.
-     * Param:
-     *  buffer - A buffer where to return the preview frame. Note that the buffer
-     *      must be large enough to contain the entire preview frame, as defined
-     *      by frame's width, height, and preview pixel format. Note also, that
-     *      due to the the limitations of the camera framework in emulator, the
-     *      preview frame is always formatted with RGB565.
-     */
-    virtual status_t GetCurrentPreviewFrame(void* buffer);
-
-    /* Gets width of the frame obtained from the physical device. */
-    inline int GetFrameWidth() const
-    {
-        return frame_width_;
-    }
-
-    /* Gets height of the frame obtained from the physical device. */
-    inline int GetFrameHeight() const
-    {
-        return frame_height_;
-    }
-
-    /* Gets byte size of the current frame buffer. */
-    inline size_t GetFrameBufferSize() const
-    {
-        return framebuffer_size_;
-    }
-
-    /* Gets number of pixels in the current frame buffer. */
-    inline int GetPixelNum() const
-    {
-        return total_pixels_;
-    }
-
-    /* Gets pixel format of the frame that physical device streams.
-     * Throughout camera framework, there are three different forms of pixel
-     * format representation:
-     *  - Original format, as reported by the actual camera device. Values for
-     *    this format are declared in bionic/libc/kernel/common/linux/videodev2.h
-     *  - String representation as defined in CameraParameters::PIXEL_FORMAT_XXX
-     *    strings in frameworks/base/include/camera/CameraParameters.h
-     *  - HAL_PIXEL_FORMAT_XXX format, as defined in system/core/include/system/graphics.h
-     * Since emulated camera device gets its data from the actual device, it gets
-     * pixel format in the original form. And that's the pixel format
-     * representation that will be returned from this method. HAL components will
-     * need to translate value returned from this method to the appropriate form.
-     * This method must be called only on connected instance of this class, since
-     * it's applicable only when physical device is ready to stream frames. If
-     * this method is called on an instance that is not connected, it must return
-     * a failure.
-     * Param:
-     *  pix_fmt - Upon success contains the original pixel format.
-     * Return:
-     *  Current framebuffer's pixel format.
-     */
-    inline uint32_t GetOriginalPixelFormat() const
-    {
-        return pixel_format_;
-    }
-
-    /*
-     * State checkers.
-     */
-
-    inline bool IsInitialized() const {
-        /* Instance is initialized when the worker thread has been successfuly
-         * created (but not necessarily started). */
-        return worker_thread_.get() != NULL && state_ != ECDS_CONSTRUCTED;
-    }
-    inline bool IsConnected() const {
-        /* Instance is connected when it is initialized and its status is either
-         * "connected", or "capturing". */
-        return IsInitialized() &&
-               (state_ == ECDS_CONNECTED || state_ == ECDS_CAPTURING);
-    }
-    inline bool IsCapturing() const {
-        return IsInitialized() && state_ == ECDS_CAPTURING;
-    }
-
-    /****************************************************************************
-     * Worker thread management.
-     * Typicaly when emulated camera device starts capturing frames from the
-     * actual device, it does that in a worker thread created in StartCapturing,
-     * and terminated in StopCapturing. Since this is such a typical scenario,
-     * it makes sence to encapsulate worker thread management in the base class
-     * for all emulated camera devices.
-     ***************************************************************************/
-
-protected:
-    /* Starts the worker thread.
-     * Typically, worker thread is started from StartCamera method of this
-     * class.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status.
-     */
-    virtual status_t StartWorkerThread();
-
-    /* Stops the worker thread.
-     * Note that this method will always wait for the worker thread to terminate.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status.
-     */
-    virtual status_t StopWorkerThread();
-
-    /* Implementation of the worker thread routine.
-     * In the default implementation of the worker thread routine we simply
-     * return 'false' forcing the thread loop to exit, and the thread to
-     * terminate. Derived class should override that method to provide there the
-     * actual frame capturing functionality.
-     * Return:
-     *  true To continue thread loop (this method will be called again), or false
-     *  to exit the thread loop and to terminate the thread.
-     */
-    virtual bool InWorkerThread();
-
-    /* Encapsulates a worker thread used by the emulated camera device.
-     */
-    friend class WorkerThread;
-    class WorkerThread : public Thread {
-
-        /****************************************************************************
-         * Public API
-         ***************************************************************************/
-
-        public:
-            inline explicit WorkerThread(EmulatedCameraDevice* camera_dev)
-                : Thread(true),   // Callbacks may involve Java calls.
-                  camera_dev_(camera_dev),
-                  thread_control_(-1),
-                  control_fd_(-1)
-            {
-            }
-
-            inline ~WorkerThread()
-            {
-                LOGW_IF(thread_control_ >= 0 || control_fd_ >= 0,
-                        "%s: Control FDs are opened in the destructor",
-                        __FUNCTION__);
-                if (thread_control_ >= 0) {
-                    close(thread_control_);
-                }
-                if (control_fd_ >= 0) {
-                    close(control_fd_);
-                }
-            }
-
-            /* Starts the thread */
-            inline status_t Start()
-            {
-                return run(NULL, ANDROID_PRIORITY_URGENT_DISPLAY, 0);
-            }
-
-            /* Overriden base class method.
-             * It is overriden in order to provide one-time initialization just
-             * prior to starting the thread routine.
-             */
-            status_t readyToRun();
-
-            /* Stops the thread. */
-            status_t Stop();
-
-            /* Values returned from the Select method of this class. */
-            enum SelectRes {
-                /* A timeout has occurred. */
-                TIMEOUT,
-                /* Data are available for read on the provided FD. */
-                READY,
-                /* Thread exit request has been received. */
-                EXIT_THREAD,
-                /* An error has occurred. */
-                ERROR
-            };
-
-            /* Select on an FD event, keeping in mind thread exit message.
-             * Param:
-             *  fd - File descriptor on which to wait for an event. This
-             *      parameter may be negative. If it is negative this method will
-             *      only wait on a control message to the thread.
-             *  timeout - Timeout in microseconds. 0 indicates no timeout (wait
-             *      forever).
-             * Return:
-             *  See SelectRes enum comments.
-             */
-            SelectRes Select(int fd, int timeout);
-
-        /****************************************************************************
-         * Private API
-         ***************************************************************************/
-
-        private:
-            /* Implements abstract method of the base Thread class. */
-            inline bool threadLoop()
-            {
-                /* Simply dispatch the call to the containing camera device. */
-                return camera_dev_->InWorkerThread();
-            }
-
-            /* Containing camera device object. */
-            EmulatedCameraDevice*   camera_dev_;
-
-            /* FD that is used to send control messages into the thread. */
-            int                     thread_control_;
-
-            /* FD that thread uses to receive control messages. */
-            int                     control_fd_;
-
-            /* Enumerates control messages that can be sent into the thread. */
-            enum ControlMessage {
-                /* Stop the thread. */
-                THREAD_STOP
-            };
-    };
-
-    /* Worker thread accessor. */
-    inline WorkerThread* worker_thread() const
-    {
-        return worker_thread_.get();
-    }
-
-    /****************************************************************************
-     * Data members
-     ***************************************************************************/
-
-protected:
-    /* Locks this instance for parameters, state, etc. change. */
-    Mutex                       object_lock_;
-
-    /* Worker thread that is used in frame capturing. */
-    sp<WorkerThread>            worker_thread_;
-
-    /* Emulated camera object containing this instance. */
-    EmulatedCamera*             camera_hal_;
-
-    /* Framebuffer containing the current frame. */
-    uint8_t*                    current_frame_;
-
-    /* Cb panel inside the framebuffer. */
-    uint8_t*                    frame_Cb_;
-
-    /* Cr panel inside the framebuffer. */
-    uint8_t*                    frame_Cr_;
-
-    /*
-     * Framebuffer properties.
-     */
-
-    /* Byte size of the framebuffer. */
-    size_t                      framebuffer_size_;
-
-    /* Original pixel format (one of the V4L2_PIX_FMT_XXX values, as defined in
-     * bionic/libc/kernel/common/linux/videodev2.h */
-    uint32_t                    pixel_format_;
-
-    /* Frame width */
-    int                         frame_width_;
-
-    /* Frame height */
-    int                         frame_height_;
-
-    /* Total number of pixels */
-    int                         total_pixels_;
-
-    /* Defines possible states of the emulated camera device object.
-     */
-    enum EmulatedCameraDeviceState {
-        /* Object has been constructed. */
-        ECDS_CONSTRUCTED,
-        /* Object has been initialized. */
-        ECDS_INITIALIZED,
-        /* Object has been connected to the physical device. */
-        ECDS_CONNECTED,
-        /* Frames are being captured. */
-        ECDS_CAPTURING,
-    };
-
-    /* Object state. */
-    EmulatedCameraDeviceState   state_;
-};
-
-}; /* namespace android */
-
-#endif  /* HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H */
diff --git a/tools/emulator/system/camera/emulated_camera_factory.cpp b/tools/emulator/system/camera/emulated_camera_factory.cpp
deleted file mode 100644
index 8a76585..0000000
--- a/tools/emulator/system/camera/emulated_camera_factory.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Contains implementation of a class EmulatedCameraFactory that manages cameras
- * available for emulation.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_Factory"
-#include <cutils/log.h>
-#include "emulated_fake_camera.h"
-#include "emulated_camera_factory.h"
-
-extern camera_module_t HAL_MODULE_INFO_SYM;
-
-/* A global instance of EmulatedCameraFactory is statically instantiated and
- * initialized when camera emulation HAL is loaded.
- */
-android::EmulatedCameraFactory  _emulated_camera_factory;
-
-namespace android {
-
-EmulatedCameraFactory::EmulatedCameraFactory()
-        : emulated_cameras_(NULL),
-          emulated_camera_num_(0),
-          fake_camera_id_(-1),
-          constructed_ok_(false)
-
-{
-    /* Obtain number of 'qemud' cameras from the emulator. */
-    const int qemud_num = GetQemudCameraNumber();
-    if (qemud_num < 0) {
-        return;
-    }
-    LOGI("Emulating %d QEMUD cameras.", qemud_num);
-
-    /* ID fake camera with the number of 'qemud' cameras. */
-    fake_camera_id_ = qemud_num;
-    LOGI("Fake camera ID is %d", fake_camera_id_);
-
-    emulated_camera_num_ = qemud_num + 1;   // Including the 'fake' camera.
-    LOGI("%d cameras are being emulated", emulated_camera_num_);
-
-    /* Allocate the array for emulated camera instances. */
-    emulated_cameras_ = new EmulatedCamera*[emulated_camera_num_];
-    if (emulated_cameras_ == NULL) {
-        LOGE("%s: Unable to allocate emulated camera array for %d entries",
-             __FUNCTION__, emulated_camera_num_);
-        return;
-    }
-
-    /* Setup the 'qemud' cameras. */
-    if (!CreateQemudCameras(qemud_num)) {
-        return;
-    }
-
-    /* Create, and initialize the fake camera */
-    emulated_cameras_[fake_camera_id_] =
-        new EmulatedFakeCamera(fake_camera_id_, &HAL_MODULE_INFO_SYM.common);
-    if (emulated_cameras_[fake_camera_id_] == NULL) {
-        LOGE("%s: Unable to instantiate fake camera class", __FUNCTION__);
-        return;
-    }
-    if (emulated_cameras_[fake_camera_id_]->Initialize() != NO_ERROR) {
-        return;
-    }
-
-    constructed_ok_ = true;
-}
-
-EmulatedCameraFactory::~EmulatedCameraFactory()
-{
-    if (emulated_cameras_ != NULL) {
-        for (int n = 0; n < emulated_camera_num_; n++) {
-            if (emulated_cameras_[n] != NULL) {
-                delete emulated_cameras_[n];
-            }
-        }
-        delete[] emulated_cameras_;
-    }
-}
-
-/****************************************************************************
- * Camera HAL API handlers.
- *
- * Each handler simply verifies existence of an appropriate EmulatedCamera
- * instance, and dispatches the call to that instance.
- *
- ***************************************************************************/
-
-int EmulatedCameraFactory::CameraDeviceOpen(int camera_id, hw_device_t** device)
-{
-    *device = NULL;
-
-    if (!constructed_ok()) {
-        LOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__);
-        return -EINVAL;
-    }
-
-    if (camera_id >= emulated_camera_num()) {
-        LOGE("%s: Camera id %d is out of bounds (%d)",
-             __FUNCTION__, camera_id, emulated_camera_num());
-        return -EINVAL;
-    }
-
-    return emulated_cameras_[camera_id]->Connect(device);
-}
-
-int EmulatedCameraFactory::GetCameraInfo(int camera_id, struct camera_info* info)
-{
-    if (!constructed_ok()) {
-        LOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__);
-        return -EINVAL;
-    }
-
-    if (camera_id >= emulated_camera_num()) {
-        LOGE("%s: Camera id %d is out of bounds (%d)",
-             __FUNCTION__, camera_id, emulated_camera_num());
-        return -EINVAL;
-    }
-
-    return emulated_cameras_[camera_id]->GetCameraInfo(info);
-}
-
-/****************************************************************************
- * Camera HAL API callbacks.
- ***************************************************************************/
-
-int EmulatedCameraFactory::device_open(const hw_module_t* module,
-                                       const char* name,
-                                       hw_device_t** device)
-{
-    /*
-     * Simply verify the parameters, and dispatch the call inside the
-     * EmulatedCameraFactory instance.
-     */
-
-    if (module != &HAL_MODULE_INFO_SYM.common) {
-        LOGE("%s: Invalid module %p expected %p",
-             __FUNCTION__, module, &HAL_MODULE_INFO_SYM.common);
-        return -EINVAL;
-    }
-    if (name == NULL) {
-        LOGE("%s: NULL name is not expected here", __FUNCTION__);
-        return -EINVAL;
-    }
-
-    return _emulated_camera_factory.CameraDeviceOpen(atoi(name), device);
-}
-
-int EmulatedCameraFactory::get_number_of_cameras(void)
-{
-    return _emulated_camera_factory.emulated_camera_num();
-}
-
-int EmulatedCameraFactory::get_camera_info(int camera_id,
-                                           struct camera_info* info)
-{
-    return _emulated_camera_factory.GetCameraInfo(camera_id, info);
-}
-
-/********************************************************************************
- * Internal API
- *******************************************************************************/
-
-int EmulatedCameraFactory::GetQemudCameraNumber()
-{
-    // TODO: Implement!
-    return 0;
-}
-
-bool EmulatedCameraFactory::CreateQemudCameras(int num)
-{
-    // TODO: Implement!
-    return true;
-}
-
-/********************************************************************************
- * Initializer for the static member structure.
- *******************************************************************************/
-
-/* Entry point for camera HAL API. */
-struct hw_module_methods_t EmulatedCameraFactory::camera_module_methods_ = {
-    open: EmulatedCameraFactory::device_open
-};
-
-}; /* namespace android */
diff --git a/tools/emulator/system/camera/emulated_fake_camera_device.cpp b/tools/emulator/system/camera/emulated_fake_camera_device.cpp
deleted file mode 100644
index 9c1698f..0000000
--- a/tools/emulator/system/camera/emulated_fake_camera_device.cpp
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Contains implementation of a class EmulatedFakeCameraDevice that encapsulates
- * fake camera device.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "EmulatedCamera_FakeDevice"
-#include <cutils/log.h>
-#include "emulated_fake_camera.h"
-#include "emulated_fake_camera_device.h"
-
-namespace android {
-
-EmulatedFakeCameraDevice::EmulatedFakeCameraDevice(EmulatedFakeCamera* camera_hal)
-    : EmulatedCameraDevice(camera_hal),
-      last_redrawn_(0),
-      black_YCbCr_(0),
-      white_YCbCr_(0xffff),
-      red_YCbCr_(kRed),
-      green_YCbCr_(kGreen),
-      blue_YCbCr_(kBlue),
-      check_x_(0),
-      check_y_(0),
-      counter_(0)
-{
-}
-
-EmulatedFakeCameraDevice::~EmulatedFakeCameraDevice()
-{
-}
-
-/****************************************************************************
- * Emulated camera device abstract interface implementation.
- ***************************************************************************/
-
-status_t EmulatedFakeCameraDevice::Connect()
-{
-    LOGV("%s", __FUNCTION__);
-
-    Mutex::Autolock locker(&object_lock_);
-    if (!IsInitialized()) {
-        LOGE("%s: Fake camera device is not initialized.", __FUNCTION__);
-        return EINVAL;
-    }
-    if (IsConnected()) {
-        LOGW("%s: Fake camera device is already connected.", __FUNCTION__);
-        return NO_ERROR;
-    }
-
-    state_ = ECDS_CONNECTED;
-
-    return NO_ERROR;
-}
-
-status_t EmulatedFakeCameraDevice::Disconnect()
-{
-    LOGV("%s", __FUNCTION__);
-
-    Mutex::Autolock locker(&object_lock_);
-    if (!IsConnected()) {
-        LOGW("%s: Fake camera device is already disconnected.", __FUNCTION__);
-        return NO_ERROR;
-    }
-    if (IsCapturing()) {
-        LOGE("%s: Cannot disconnect while in the capturing state.", __FUNCTION__);
-        return EINVAL;
-    }
-
-    state_ = ECDS_INITIALIZED;
-
-    return NO_ERROR;
-}
-
-status_t EmulatedFakeCameraDevice::StartCamera()
-{
-    LOGV("%s", __FUNCTION__);
-
-    Mutex::Autolock locker(&object_lock_);
-    if (!IsConnected()) {
-        LOGE("%s: Fake camera device is not connected.", __FUNCTION__);
-        return EINVAL;
-    }
-    if (IsCapturing()) {
-        LOGW("%s: Fake camera device is already capturing.", __FUNCTION__);
-        return NO_ERROR;
-    }
-
-    /* Used in calculating Cb/Cr position when drawing the square. */
-    half_width_ = frame_width_ / 2;
-
-    /* Just start the worker thread: there is no real device to deal with. */
-    const status_t ret = StartWorkerThread();
-    if (ret == NO_ERROR) {
-        state_ = ECDS_CAPTURING;
-    }
-
-    return ret;
-}
-
-status_t EmulatedFakeCameraDevice::StopCamera()
-{
-    LOGV("%s", __FUNCTION__);
-
-    Mutex::Autolock locker(&object_lock_);
-    if (!IsCapturing()) {
-        LOGW("%s: Fake camera device is not capturing.", __FUNCTION__);
-        return NO_ERROR;
-    }
-
-    /* Just stop the worker thread: there is no real device to deal with. */
-    const status_t ret = StopWorkerThread();
-    if (ret == NO_ERROR) {
-        state_ = ECDS_CONNECTED;
-    }
-
-    return ret;
-}
-
-/****************************************************************************
- * Worker thread management overrides.
- ***************************************************************************/
-
-bool EmulatedFakeCameraDevice::InWorkerThread()
-{
-    /* Wait till FPS timeout expires, or thread exit message is received. */
-    WorkerThread::SelectRes res =
-        worker_thread()->Select(-1, 1000000 / emulated_fps_);
-    if (res == WorkerThread::EXIT_THREAD) {
-        LOGV("%s: Worker thread has been terminated.", __FUNCTION__);
-        return false;
-    }
-
-    /* Lets see if we need to generate a new frame. */
-    timeval cur_time;
-    gettimeofday(&cur_time, NULL);
-    const uint64_t cur_mks = cur_time.tv_sec * 1000000LL + cur_time.tv_usec;
-    if ((cur_mks - last_redrawn_) >= redraw_after_) {
-        /*
-         * Time to generate a new frame.
-         */
-
-        /* Draw the checker board. */
-        DrawCheckerboard();
-
-        /* Run the square. */
-        int x = ((counter_ * 3) & 255);
-        if(x > 128) x = 255 - x;
-        int y = ((counter_ * 5) & 255);
-        if(y > 128) y = 255 - y;
-        const int size = frame_width_ / 10;
-        DrawSquare(x * size / 32, y * size / 32, (size * 5) >> 1,
-                   (counter_ & 0x100) ? &red_YCbCr_ : &green_YCbCr_);
-        counter_++;
-        last_redrawn_ = cur_mks;
-    }
-
-    /* Notify the camera HAL about new frame. */
-    camera_hal_->OnNextFrameAvailable(current_frame_,
-                                      systemTime(SYSTEM_TIME_MONOTONIC), this);
-
-    return true;
-}
-
-/****************************************************************************
- * Fake camera device private API
- ***************************************************************************/
-
-void EmulatedFakeCameraDevice::DrawCheckerboard()
-{
-    const int size = frame_width_ / 10;
-    bool black = true;
-
-    if((check_x_ / size) & 1)
-        black = false;
-    if((check_y_ / size) & 1)
-        black = !black;
-
-    int county = check_y_ % size;
-    int checkxremainder = check_x_ % size;
-    uint8_t* Y = current_frame_;
-    uint8_t* Cb_pos = frame_Cb_;
-    uint8_t* Cr_pos = frame_Cr_;
-    uint8_t* Cb = Cb_pos;
-    uint8_t* Cr = Cr_pos;
-
-    for(int y = 0; y < frame_height_; y++) {
-        int countx = checkxremainder;
-        bool current = black;
-        for(int x = 0; x < frame_width_; x += 2) {
-            if (current) {
-                black_YCbCr_.get(Y, Cb, Cr);
-            } else {
-                white_YCbCr_.get(Y, Cb, Cr);
-            }
-            Y[1] = *Y;
-            Y += 2; Cb++; Cr++;
-            countx += 2;
-            if(countx >= size) {
-                countx = 0;
-                current = !current;
-            }
-        }
-        if (y & 0x1) {
-            Cb_pos = Cb;
-            Cr_pos = Cr;
-        } else {
-            Cb = Cb_pos;
-            Cr = Cr_pos;
-        }
-        if(county++ >= size) {
-            county = 0;
-            black = !black;
-        }
-    }
-    check_x_ += 3;
-    check_y_++;
-}
-
-void EmulatedFakeCameraDevice::DrawSquare(int x,
-                                          int y,
-                                          int size,
-                                          const YCbCrPixel* color)
-{
-    const int half_x = x / 2;
-    const int square_xstop = min(frame_width_, x+size);
-    const int square_ystop = min(frame_height_, y+size);
-    uint8_t* Y_pos = current_frame_ + y * frame_width_ + x;
-
-    // Draw the square.
-    for (; y < square_ystop; y++) {
-        const int iCbCr = (y / 2) * half_width_ + half_x;
-        uint8_t* sqCb = frame_Cb_ + iCbCr;
-        uint8_t* sqCr = frame_Cr_ + iCbCr;
-        uint8_t* sqY = Y_pos;
-        for (int i = x; i < square_xstop; i += 2) {
-            color->get(sqY, sqCb, sqCr);
-            sqY[1] = *sqY;
-            sqY += 2; sqCb++; sqCr++;
-        }
-        Y_pos += frame_width_;
-    }
-}
-
-}; /* namespace android */
diff --git a/tools/emulator/system/camera/emulated_fake_camera_device.h b/tools/emulator/system/camera/emulated_fake_camera_device.h
deleted file mode 100644
index 76c34f9..0000000
--- a/tools/emulator/system/camera/emulated_fake_camera_device.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_DEVICE_H
-#define HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_DEVICE_H
-
-/*
- * Contains declaration of a class EmulatedFakeCameraDevice that encapsulates
- * a fake camera device.
- */
-
-#include "converters.h"
-#include "emulated_camera_device.h"
-
-namespace android {
-
-class EmulatedFakeCamera;
-
-/* Encapsulates a fake camera device.
- * Fake camera device emulates a camera device by providing frames containing
- * a black and white checker board, moving diagonally towards the 0,0 corner.
- * There is also a green, or red square that bounces inside the frame, changing
- * its color when bouncing off the 0,0 corner.
- */
-class EmulatedFakeCameraDevice : public EmulatedCameraDevice {
-public:
-    /* Constructs EmulatedFakeCameraDevice instance. */
-    explicit EmulatedFakeCameraDevice(EmulatedFakeCamera* camera_hal);
-
-    /* Destructs EmulatedFakeCameraDevice instance. */
-    ~EmulatedFakeCameraDevice();
-
-    /****************************************************************************
-     * Emulated camera device abstract interface implementation.
-     * See declarations of these methods in EmulatedCameraDevice class for
-     * information on each of these methods.
-     ***************************************************************************/
-
-public:
-    /* Connects to the camera device.
-     * Since there is no real device to connect to, this method does nothing, but
-     * changes the state.
-     */
-    status_t Connect();
-
-    /* Disconnects from the camera device.
-     * Since there is no real device to disconnect from, this method does
-     * nothing, but changes the state.
-     */
-    status_t Disconnect();
-
-protected:
-    /* Starts capturing frames from the camera device.
-     * Since there is no real device to control, this method simply starts the
-     * worker thread, and changes the state.
-     */
-    status_t StartCamera();
-
-    /* Stops capturing frames from the camera device.
-     * Since there is no real device to control, this method simply stops the
-     * worker thread, and changes the state.
-     */
-    status_t StopCamera();
-
-    /****************************************************************************
-     * Worker thread management overrides.
-     * See declarations of these methods in EmulatedCameraDevice class for
-     * information on each of these methods.
-     ***************************************************************************/
-
-protected:
-    /* Implementation of the worker thread routine.
-     * This method simply sleeps for a period of time defined by FPS property of
-     * the fake camera (simulating frame frequency), and then calls emulated
-     * camera's OnNextFrameAvailable method.
-     */
-    bool InWorkerThread();
-
-    /****************************************************************************
-     * Fake camera device private API
-     ***************************************************************************/
-
-private:
-    /* Draws a black and white checker board in the current frame buffer. */
-    void DrawCheckerboard();
-
-    /* Draws a square of the given color in the current frame buffer.
-     * Param:
-     *  x, y - Coordinates of the top left corner of the square in the buffer.
-     *  size - Size of the square's side.
-     *  color - Square's color.
-     */
-    void DrawSquare(int x, int y, int size, const YCbCrPixel* color);
-
-    /****************************************************************************
-     * Fake camera device data members
-     ***************************************************************************/
-
-private:
-    /* Last time (absoulte microsec) when the checker board has been redrawn. */
-    uint64_t    last_redrawn_;
-
-    /*
-     * Pixel colors in YCbCr format used when drawing the checker board.
-     */
-
-    YCbCrPixel  black_YCbCr_;
-    YCbCrPixel  white_YCbCr_;
-    YCbCrPixel  red_YCbCr_;
-    YCbCrPixel  green_YCbCr_;
-    YCbCrPixel  blue_YCbCr_;
-
-    /*
-     * Drawing related stuff
-     */
-
-    int         check_x_;
-    int         check_y_;
-    int         counter_;
-    int         half_width_;
-
-    /* Emulated FPS (frames per second).
-     * We will emulate the "semi-high end" 50 FPS. */
-    static const int        emulated_fps_ = 50;
-
-    /* Defines time (in microseconds) between redrawing the checker board.
-     * We will redraw the checker board every 15 milliseconds. */
-    static const uint32_t   redraw_after_ = 15000;
-};
-
-}; /* namespace android */
-
-#endif  /* HW_EMULATOR_CAMERA_EMULATED_FAKE_CAMERA_DEVICE_H */
diff --git a/tools/emulator/system/camera/media_profiles.xml b/tools/emulator/system/camera/media_profiles.xml
new file mode 100644
index 0000000..ae1ce88
--- /dev/null
+++ b/tools/emulator/system/camera/media_profiles.xml
@@ -0,0 +1,400 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!DOCTYPE MediaSettings [
+<!ELEMENT MediaSettings (CamcorderProfiles,
+                         EncoderOutputFileFormat+,
+                         VideoEncoderCap+,
+                         AudioEncoderCap+,
+                         VideoDecoderCap,
+                         AudioDecoderCap)>
+<!ELEMENT CamcorderProfiles (EncoderProfile+, ImageEncoding+, ImageDecoding, Camera)>
+<!ELEMENT EncoderProfile (Video, Audio)>
+<!ATTLIST EncoderProfile quality (high|low) #REQUIRED>
+<!ATTLIST EncoderProfile fileFormat (mp4|3gp) #REQUIRED>
+<!ATTLIST EncoderProfile duration (30|60) #REQUIRED>
+<!ATTLIST EncoderProfile cameraId (0|1) #REQUIRED>
+<!ELEMENT Video EMPTY>
+<!ATTLIST Video codec (h264|h263|m4v) #REQUIRED>
+<!ATTLIST Video bitRate CDATA #REQUIRED>
+<!ATTLIST Video width CDATA #REQUIRED>
+<!ATTLIST Video height CDATA #REQUIRED>
+<!ATTLIST Video frameRate CDATA #REQUIRED>
+<!ELEMENT Audio EMPTY>
+<!ATTLIST Audio codec (amrnb|amrwb|aac) #REQUIRED>
+<!ATTLIST Audio bitRate CDATA #REQUIRED>
+<!ATTLIST Audio sampleRate CDATA #REQUIRED>
+<!ATTLIST Audio channels (1|2) #REQUIRED>
+<!ELEMENT ImageEncoding EMPTY>
+<!ATTLIST ImageEncoding quality (90|80|70|60|50|40) #REQUIRED>
+<!ELEMENT ImageDecoding EMPTY>
+<!ATTLIST ImageDecoding memCap CDATA #REQUIRED>
+<!ELEMENT Camera EMPTY>
+<!ELEMENT EncoderOutputFileFormat EMPTY>
+<!ATTLIST EncoderOutputFileFormat name (mp4|3gp) #REQUIRED>
+<!ELEMENT VideoEncoderCap EMPTY>
+<!ATTLIST VideoEncoderCap name (h264|h263|m4v|wmv) #REQUIRED>
+<!ATTLIST VideoEncoderCap enabled (true|false) #REQUIRED>
+<!ATTLIST VideoEncoderCap minBitRate CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxBitRate CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap minFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap minFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap minFrameRate CDATA #REQUIRED>
+<!ATTLIST VideoEncoderCap maxFrameRate CDATA #REQUIRED>
+<!ELEMENT AudioEncoderCap EMPTY>
+<!ATTLIST AudioEncoderCap name (amrnb|amrwb|aac|wma) #REQUIRED>
+<!ATTLIST AudioEncoderCap enabled (true|false) #REQUIRED>
+<!ATTLIST AudioEncoderCap minBitRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap maxBitRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap minSampleRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap maxSampleRate CDATA #REQUIRED>
+<!ATTLIST AudioEncoderCap minChannels (1|2) #REQUIRED>
+<!ATTLIST AudioEncoderCap maxChannels (1|2) #REQUIRED>
+<!ELEMENT VideoDecoderCap EMPTY>
+<!ATTLIST VideoDecoderCap name (wmv) #REQUIRED>
+<!ATTLIST VideoDecoderCap enabled (true|false) #REQUIRED>
+<!ELEMENT AudioDecoderCap EMPTY>
+<!ATTLIST AudioDecoderCap name (wma) #REQUIRED>
+<!ATTLIST AudioDecoderCap enabled (true|false) #REQUIRED>
+<!ELEMENT VideoEditorCap EMPTY>
+<!ATTLIST VideoEditorCap maxInputFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEditorCap maxInputFrameHeight CDATA #REQUIRED>
+<!ATTLIST VideoEditorCap maxOutputFrameWidth CDATA #REQUIRED>
+<!ATTLIST VideoEditorCap maxOutputFrameHeight CDATA #REQUIRED>
+<!ELEMENT ExportVideoProfile EMPTY>
+<!ATTLIST ExportVideoProfile name (h264|h263|m4v) #REQUIRED>
+<!ATTLIST ExportVideoProfile profile CDATA #REQUIRED>
+<!ATTLIST ExportVideoProfile level CDATA #REQUIRED>
+]>
+<!--
+     This file is used to declare the multimedia profiles and capabilities
+     on an android-powered device.
+-->
+<MediaSettings>
+    <!-- Each camcorder profile defines a set of predefined configuration parameters -->
+    <CamcorderProfiles cameraId="0">
+
+        <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+            <Video codec="m4v"
+                   bitRate="128000"
+                   width="320"
+                   height="240"
+                   frameRate="15" />
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="192000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+
+    <CamcorderProfiles cameraId="1">
+
+        <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+            <Video codec="m4v"
+                   bitRate="128000"
+                   width="320"
+                   height="240"
+                   frameRate="15" />
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="192000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+
+    <CamcorderProfiles cameraId="2">
+
+        <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+            <Video codec="m4v"
+                   bitRate="128000"
+                   width="320"
+                   height="240"
+                   frameRate="15" />
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="192000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+
+    <CamcorderProfiles cameraId="3">
+
+        <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+            <Video codec="m4v"
+                   bitRate="128000"
+                   width="320"
+                   height="240"
+                   frameRate="15" />
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="192000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+
+    <CamcorderProfiles cameraId="4">
+
+        <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+            <Video codec="m4v"
+                   bitRate="128000"
+                   width="320"
+                   height="240"
+                   frameRate="15" />
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="192000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+
+    <CamcorderProfiles cameraId="5">
+
+        <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+            <Video codec="m4v"
+                   bitRate="128000"
+                   width="320"
+                   height="240"
+                   frameRate="15" />
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="192000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+
+    <CamcorderProfiles cameraId="6">
+
+        <EncoderProfile quality="qvga" fileFormat="mp4" duration="60">
+            <Video codec="m4v"
+                   bitRate="128000"
+                   width="320"
+                   height="240"
+                   frameRate="15" />
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <EncoderProfile quality="timelapseqcif" fileFormat="mp4" duration="30">
+            <Video codec="h264"
+                   bitRate="192000"
+                   width="176"
+                   height="144"
+                   frameRate="30" />
+            <!-- audio setting is ignored -->
+            <Audio codec="amrnb"
+                   bitRate="12200"
+                   sampleRate="8000"
+                   channels="1" />
+        </EncoderProfile>
+
+        <ImageEncoding quality="95" />
+        <ImageEncoding quality="80" />
+        <ImageEncoding quality="70" />
+        <ImageDecoding memCap="20000000" />
+
+    </CamcorderProfiles>
+
+    <EncoderOutputFileFormat name="3gp" />
+    <EncoderOutputFileFormat name="mp4" />
+
+    <!--
+         If a codec is not enabled, it is invisible to the applications
+         In other words, the applications won't be able to use the codec
+         or query the capabilities of the codec at all if it is disabled
+    -->
+    <VideoEncoderCap name="h264" enabled="true"
+        minBitRate="64000" maxBitRate="192000"
+        minFrameWidth="176" maxFrameWidth="320"
+        minFrameHeight="144" maxFrameHeight="240"
+        minFrameRate="15" maxFrameRate="30" />
+
+    <VideoEncoderCap name="h263" enabled="true"
+        minBitRate="64000" maxBitRate="192000"
+        minFrameWidth="176" maxFrameWidth="320"
+        minFrameHeight="144" maxFrameHeight="240"
+        minFrameRate="15" maxFrameRate="30" />
+
+    <VideoEncoderCap name="m4v" enabled="true"
+        minBitRate="64000" maxBitRate="192000"
+        minFrameWidth="176" maxFrameWidth="320"
+        minFrameHeight="144" maxFrameHeight="240"
+        minFrameRate="15" maxFrameRate="30" />
+
+    <AudioEncoderCap name="aac" enabled="true"
+        minBitRate="8000" maxBitRate="96000"
+        minSampleRate="8000" maxSampleRate="48000"
+        minChannels="1" maxChannels="1" />
+
+    <AudioEncoderCap name="amrwb" enabled="true"
+        minBitRate="6600" maxBitRate="23050"
+        minSampleRate="16000" maxSampleRate="16000"
+        minChannels="1" maxChannels="1" />
+
+    <AudioEncoderCap name="amrnb" enabled="true"
+        minBitRate="5525" maxBitRate="12200"
+        minSampleRate="8000" maxSampleRate="8000"
+        minChannels="1" maxChannels="1" />
+
+    <!--
+        FIXME:
+        We do not check decoder capabilities at present
+        At present, we only check whether windows media is visible
+        for TEST applications. For other applications, we do
+        not perform any checks at all.
+    -->
+    <VideoDecoderCap name="wmv" enabled="false"/>
+    <AudioDecoderCap name="wma" enabled="false"/>
+    <VideoEditorCap  maxInputFrameWidth="320"
+        maxInputFrameHeight="240" maxOutputFrameWidth="320"
+        maxOutputFrameHeight="240"/>
+    <!--
+        The VideoEditor Export codec profile and level values
+        correspond to the values in OMX_Video.h.
+        E.g. for h264, profile value 1 means OMX_VIDEO_AVCProfileBaseline
+        and  level 4096 means OMX_VIDEO_AVCLevel41.
+        Please note that the values are in decimal.
+        These values are for video encoder.
+    -->
+    <!--
+      Codec = h.264, Baseline profile, level 4.1
+    -->
+    <ExportVideoProfile name="h264" profile= "1" level="512"/>
+    <!--
+      Codec = h.263, Baseline profile, level 0
+    -->
+    <ExportVideoProfile name="h263" profile= "1" level="1"/>
+    <!--
+      Codec = mpeg4, Simple profile, level 3
+    -->
+    <ExportVideoProfile name="m4v" profile= "1" level="16"/>
+</MediaSettings>