Reconcile with ics-factoryrom-release

Change-Id: Iaebcfef5371506aec5cd6cda25ce0889005018f9
diff --git a/apps/Fallback/res/values-af/strings.xml b/apps/Fallback/res/values-af/strings.xml
deleted file mode 100644
index 8cf16a7..0000000
--- a/apps/Fallback/res/values-af/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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
deleted file mode 100644
index 0c89122..0000000
--- a/apps/Fallback/res/values-am/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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 cbf35ef..671919b 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
deleted file mode 100644
index 930fe79..0000000
--- a/apps/Fallback/res/values-ms/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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
deleted file mode 100644
index f322c20..0000000
--- a/apps/Fallback/res/values-sw/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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">"Rudi nyuma"</string>
-    <string name="title" msgid="8156274565006125136">"Kitendo kinachohimiliwa"</string>
-    <string name="error" msgid="6539615832923362301">"Kitendo hakijahimiliwa ipasavyo"</string>
-</resources>
diff --git a/apps/Fallback/res/values-zu/strings.xml b/apps/Fallback/res/values-zu/strings.xml
deleted file mode 100644
index 2c85d28..0000000
--- a/apps/Fallback/res/values-zu/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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-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..7e0c2a5 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
@@ -200,18 +199,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..496ee6c 100755
--- a/build/tools/mk_sdk_repo_xml.sh
+++ b/build/tools/mk_sdk_repo_xml.sh
@@ -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,14 +129,24 @@
   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
@@ -168,13 +183,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.
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/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/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/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..356fc97 100644
--- a/sdk/platform_source.properties
+++ b/sdk/platform_source.properties
@@ -1,6 +1,9 @@
-Pkg.Desc=Android SDK Platform 3.2
+Pkg.Desc=Android SDK Platform 4.0
 Pkg.UserSrc=false
-Platform.Version=3.2
+Platform.IncludedAbi=armeabi
+Platform.Version=4.0
 Pkg.Revision=1
-AndroidVersion.ApiLevel=13
+Layoutlib.Api=4
+Layoutlib.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..cd3a0b0
--- /dev/null
+++ b/sdk/support_source.properties
@@ -0,0 +1,4 @@
+Pkg.UserSrc=false
+Pkg.Revision=4
+Extra.OldPaths=compatibility
+
diff --git a/tools/emulator/system/camera/Android.mk b/tools/emulator/system/camera/Android.mk
index 47f425a..2e5c19c 100755
--- a/tools/emulator/system/camera/Android.mk
+++ b/tools/emulator/system/camera/Android.mk
@@ -28,6 +28,16 @@
     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 := \
 	EmulatedCameraHal.cpp \
     EmulatedCameraFactory.cpp \
@@ -40,7 +50,8 @@
 	Converters.cpp \
 	PreviewWindow.cpp \
 	CallbackNotifier.cpp \
-	QemuClient.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
index 188bf3a..cec471f 100755
--- a/tools/emulator/system/camera/CallbackNotifier.cpp
+++ b/tools/emulator/system/camera/CallbackNotifier.cpp
@@ -25,6 +25,7 @@
 #include <media/stagefright/MetadataBufferType.h>
 #include "EmulatedCameraDevice.h"
 #include "CallbackNotifier.h"
+#include "JpegCompressor.h"
 
 namespace android {
 
@@ -92,7 +93,8 @@
       mLastFrameTimestamp(0),
       mFrameRefreshFreq(0),
       mMessageEnabler(0),
-      mVideoRecEnabled(false)
+      mVideoRecEnabled(false),
+      mTakingPicture(false)
 {
 }
 
@@ -213,6 +215,37 @@
             LOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__);
         }
     }
+
+    if (mTakingPicture) {
+        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. TODO: Make sure that frame is NV21! */
+            NV21JpegCompressor compressor;
+            status_t res =
+                compressor.compressRawImage(frame, camera_dev->getFrameWidth(),
+                                            camera_dev->getFrameHeight(), 90);
+            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__);
+            }
+        }
+        if (isMessageEnabled(CAMERA_MSG_SHUTTER)) {
+            mNotifyCB(CAMERA_MSG_SHUTTER, 0, 0, mCBOpaque);
+        }
+        /* This happens just once. */
+        mTakingPicture = false;
+    }
 }
 
 /****************************************************************************
diff --git a/tools/emulator/system/camera/CallbackNotifier.h b/tools/emulator/system/camera/CallbackNotifier.h
index 0a595ef..fe6c03a 100755
--- a/tools/emulator/system/camera/CallbackNotifier.h
+++ b/tools/emulator/system/camera/CallbackNotifier.h
@@ -114,7 +114,7 @@
      */
     inline int isMessageEnabled(uint msg_type)
     {
-        return mMessageEnabler & ~msg_type;
+        return mMessageEnabler & msg_type;
     }
 
     /* Checks id video recording is enabled.
@@ -159,6 +159,15 @@
                               nsecs_t timestamp,
                               EmulatedCameraDevice* camera_dev);
 
+    /* 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;
+    }
+
     /****************************************************************************
      * Private API
      ***************************************************************************/
@@ -199,6 +208,9 @@
 
     /* Video recording status. */
     bool                            mVideoRecEnabled;
+
+    /* Picture taking status. */
+    bool                            mTakingPicture;
 };
 
 }; /* namespace android */
diff --git a/tools/emulator/system/camera/Converters.cpp b/tools/emulator/system/camera/Converters.cpp
index 797d652..22c4bd3 100755
--- a/tools/emulator/system/camera/Converters.cpp
+++ b/tools/emulator/system/camera/Converters.cpp
@@ -25,24 +25,25 @@
 
 namespace android {
 
-void YV12ToRGB565(const void* yv12, void* rgb, int width, int height)
+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 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* U_pos = Y + pix_total;
-    const uint8_t* V_pos = U_pos + pix_total / 4;
-    const uint8_t* U = U_pos;
-    const uint8_t* V = V_pos;
+    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) {
-            const uint8_t nU = *U; U++;
-            const uint8_t nV = *V; V++;
-            *rgb_buf = YUVToRGB565(*Y, nU, nV);
-            Y++; rgb_buf++;
-            *rgb_buf = YUVToRGB565(*Y, nU, nV);
-            Y++; rgb_buf++;
+        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;
@@ -54,24 +55,25 @@
     }
 }
 
-void YV12ToRGB32(const void* yv12, void* rgb, int width, int height)
+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 int pix_total = width * height;
-    uint32_t* rgb_buf = reinterpret_cast<uint32_t*>(rgb);
-    const uint8_t* Y = reinterpret_cast<const uint8_t*>(yv12);
-    const uint8_t* U_pos = Y + pix_total;
-    const uint8_t* V_pos = U_pos + pix_total / 4;
-    const uint8_t* U = U_pos;
-    const uint8_t* V = V_pos;
+    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) {
-            const uint8_t nU = *U; U++;
-            const uint8_t nV = *V; V++;
-            *rgb_buf = YUVToRGB32(*Y, nU, nV);
-            Y++; rgb_buf++;
-            *rgb_buf = YUVToRGB32(*Y, nU, nV);
-            Y++; rgb_buf++;
+        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;
@@ -83,4 +85,106 @@
     }
 }
 
+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* 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)
+{
+#if 1
+    _YUV420SToRGB565(Y, U, V, 2, rgb, width, height);
+#else
+    for (int y = 0; y < height; y++) {
+        for (int x = 0; x < width; x += 2, U += 2, V += 2) {
+            const uint8_t nU = *U;
+            const uint8_t nV = *V;
+            *rgb = YUVToRGB565(*Y, nU, nV);
+            Y++; rgb++;
+            *rgb = YUVToRGB565(*Y, nU, nV);
+            Y++; rgb++;
+        }
+    }
+#endif
+}
+
+/* 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)
+{
+#if 1
+    _YUV420SToRGB32(Y, U, V, 2, rgb, width, height);
+#else
+    for (int y = 0; y < height; y++) {
+        for (int x = 0; x < width; x += 2, U += 2, V += 2) {
+            const uint8_t nU = *U;
+            const uint8_t nV = *V;
+            *rgb = YUVToRGB32(*Y, nU, nV);
+            Y++; rgb++;
+            *rgb = YUVToRGB32(*Y, nU, nV);
+            Y++; rgb++;
+        }
+    }
+#endif
+}
+
+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
index 5cdcea2..5001948 100755
--- a/tools/emulator/system/camera/Converters.h
+++ b/tools/emulator/system/camera/Converters.h
@@ -269,6 +269,38 @@
  */
 void YV12ToRGB32(const void* yv12, 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/EmulatedCamera.cpp b/tools/emulator/system/camera/EmulatedCamera.cpp
index 12b9792..909760b 100755
--- a/tools/emulator/system/camera/EmulatedCamera.cpp
+++ b/tools/emulator/system/camera/EmulatedCamera.cpp
@@ -125,8 +125,8 @@
     mParameters.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
                     CameraParameters::PIXEL_FORMAT_YUV420P);
     mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
-                    CameraParameters::PIXEL_FORMAT_YUV420P);
-    mParameters.setPictureFormat(CameraParameters::PIXEL_FORMAT_YUV420P);
+                    CameraParameters::PIXEL_FORMAT_JPEG);
+    mParameters.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
 
     /*
      * Not supported features
@@ -302,22 +302,71 @@
 {
     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;
+    }
+
     /*
-     * 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.setTakingPicture(true);
+    res = camera_dev->startDeliveringFrames(true);
+    if (res != NO_ERROR) {
+        mCallbackNotifier.setTakingPicture(false);
+        if (preview_on) {
+            doStartPreview();
+        }
+    }
+    return res;
 }
 
 status_t EmulatedCamera::cancelPicture()
@@ -455,16 +504,67 @@
     LOGV("%s", __FUNCTION__);
 
     status_t res = mPreviewWindow.startPreview();
+    if (res != NO_ERROR) {
+        return res;
+    }
+    if (getCameraDevice()->isStarted()) {
+        return NO_ERROR;
+    }
 
-    /* Start the camera. */
-    if (res == NO_ERROR && !getCameraDevice()->isCapturing()) {
-        res = startCamera();
+    EmulatedCameraDevice* camera_dev = getCameraDevice();
+
+    /* 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. */
             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_YVU420;
+    } 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", width, height, 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;
 }
 
@@ -474,8 +574,9 @@
 
     status_t res = NO_ERROR;
     /* Stop the camera. */
-    if (getCameraDevice()->isCapturing()) {
-        res = stopCamera();
+    if (getCameraDevice()->isStarted()) {
+        getCameraDevice()->stopDeliveringFrames();
+        res = getCameraDevice()->stopDevice();
     }
 
     if (res == NO_ERROR) {
@@ -486,76 +587,6 @@
     return NO_ERROR;
 }
 
-status_t EmulatedCamera::startCamera()
-{
-    LOGV("%s", __FUNCTION__);
-
-    status_t res = EINVAL;
-    EmulatedCameraDevice* camera_dev = getCameraDevice();
-    if (camera_dev != NULL) {
-        if (!camera_dev->isConnected()) {
-            res = camera_dev->connectDevice();
-            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 (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__);
-                return EINVAL;
-            }
-            uint32_t org_fmt;
-            if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
-                org_fmt = V4L2_PIX_FMT_YVU420;
-            } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) {
-                org_fmt = V4L2_PIX_FMT_RGB32;
-            } 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()
-{
-    LOGV("%s", __FUNCTION__);
-
-    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.
  ***************************************************************************/
@@ -573,8 +604,9 @@
     /* Stop and disconnect the camera device. */
     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;
             }
diff --git a/tools/emulator/system/camera/EmulatedCamera.h b/tools/emulator/system/camera/EmulatedCamera.h
index 77d16c9..8b04de2 100755
--- a/tools/emulator/system/camera/EmulatedCamera.h
+++ b/tools/emulator/system/camera/EmulatedCamera.h
@@ -290,18 +290,6 @@
      */
     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();
-
     /****************************************************************************
      * Private API.
      ***************************************************************************/
diff --git a/tools/emulator/system/camera/EmulatedCameraDevice.cpp b/tools/emulator/system/camera/EmulatedCameraDevice.cpp
index fb9c1da..bfb2c34 100755
--- a/tools/emulator/system/camera/EmulatedCameraDevice.cpp
+++ b/tools/emulator/system/camera/EmulatedCameraDevice.cpp
@@ -72,16 +72,78 @@
     return NO_ERROR;
 }
 
-status_t EmulatedCameraDevice::startCapturing(int width,
-                                              int height,
-                                              uint32_t pix_fmt)
+status_t EmulatedCameraDevice::startDeliveringFrames(bool one_burst)
 {
     LOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock locker(&mObjectLock);
+    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_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_NV21:
+        case V4L2_PIX_FMT_NV12:
             mFrameBufferSize = (width * height * 12) / 8;
             break;
 
@@ -103,78 +165,20 @@
         LOGE("%s: Unable to allocate framebuffer", __FUNCTION__);
         return ENOMEM;
     }
-    /* Calculate U/V panes inside the framebuffer. */
-    mFrameU = mCurrentFrame + mTotalPixels;
-    mFrameV = mFrameU + mTotalPixels / 4;
-
-    /* Start the camera. */
-    const status_t res = startDevice();
-    if (res == NO_ERROR) {
-        LOGD("Camera device is started:\n"
-             "      Framebuffer dimensions: %dx%d.\n"
-             "      Pixel format: %.4s",
-             mFrameWidth, mFrameHeight,
-             reinterpret_cast<const char*>(&mPixelFormat));
-    } else {
-        delete[] mCurrentFrame;
-        mCurrentFrame = NULL;
-    }
-
-    return res;
-}
-
-status_t EmulatedCameraDevice::stopCapturing()
-{
-    LOGV("%s", __FUNCTION__);
-
-    Mutex::Autolock locker(&mObjectLock);
-    /* Stop the camera. */
-    const status_t res = stopDevice();
-    if (res == NO_ERROR) {
-        /* Release resources allocated for capturing. */
-        if (mCurrentFrame != NULL) {
-            delete[] mCurrentFrame;
-            mCurrentFrame = NULL;
-        }
-    }
-
-    return res;
-}
-
-status_t EmulatedCameraDevice::getCurrentFrame(void* buffer)
-{
-    Mutex::Autolock locker(&mObjectLock);
-
-    if (!isCapturing() || mCurrentFrame == NULL) {
-        LOGE("%s is called on a device that is not in the capturing state",
-            __FUNCTION__);
-        return EINVAL;
-    }
-
-    memcpy(buffer, mCurrentFrame, mFrameBufferSize);
-
+    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;
 }
 
-status_t EmulatedCameraDevice::getCurrentPreviewFrame(void* buffer)
+void EmulatedCameraDevice::commonStopDevice()
 {
-    Mutex::Autolock locker(&mObjectLock);
+    mFrameWidth = mFrameHeight = mTotalPixels = 0;
+    mPixelFormat = 0;
 
-    if (!isCapturing() || mCurrentFrame == 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 (mPixelFormat) {
-        case V4L2_PIX_FMT_YVU420:
-            YV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight);
-            return NO_ERROR;
-
-        default:
-            LOGE("%s: Unknown pixel format %d", __FUNCTION__, mPixelFormat);
-            return EINVAL;
+    if (mCurrentFrame != NULL) {
+        delete[] mCurrentFrame;
+        mCurrentFrame = NULL;
     }
 }
 
@@ -182,7 +186,7 @@
  * Worker thread management.
  ***************************************************************************/
 
-status_t EmulatedCameraDevice::startWorkerThread()
+status_t EmulatedCameraDevice::startWorkerThread(bool one_burst)
 {
     LOGV("%s", __FUNCTION__);
 
@@ -191,11 +195,9 @@
         return EINVAL;
     }
 
-    const status_t ret = getWorkerThread()->startThread();
-    LOGE_IF(ret != NO_ERROR, "%s: Unable to start worker thread: %d -> %s",
-            __FUNCTION__, ret, strerror(ret));
-
-    return ret;
+    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()
@@ -207,14 +209,15 @@
         return EINVAL;
     }
 
-    getWorkerThread()->stopThread();
-
-    return NO_ERROR;
+    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. */
+    /* This will end the thread loop, and will terminate the thread. Derived
+     * classes must override this method. */
     return false;
 }
 
@@ -268,10 +271,10 @@
                 LOGV("Emulated camera device's worker thread has been stopped.");
             } else {
                 LOGE("%s: requestExitAndWait failed: %d -> %s",
-                     __FUNCTION__, res, strerror(res));
+                     __FUNCTION__, res, strerror(-res));
             }
         } else {
-            LOGE("%s: Unable to send THREAD_STOP: %d -> %s",
+            LOGE("%s: Unable to send THREAD_STOP message: %d -> %s",
                  __FUNCTION__, errno, strerror(errno));
             res = errno ? errno : EINVAL;
         }
diff --git a/tools/emulator/system/camera/EmulatedCameraDevice.h b/tools/emulator/system/camera/EmulatedCameraDevice.h
index b73b863..88e2dd2 100755
--- a/tools/emulator/system/camera/EmulatedCameraDevice.h
+++ b/tools/emulator/system/camera/EmulatedCameraDevice.h
@@ -69,28 +69,30 @@
      *  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
+     *  called for an instance that is in the "started" state, this method must
      *  return a failure.
      */
     virtual status_t disconnectDevice() = 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.
+    /* 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() = 0;
+    virtual status_t startDevice(int width, int height, uint32_t pix_fmt) = 0;
 
-    /* Stops capturing frames from the camera device.
+    /* 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,
@@ -114,79 +116,95 @@
      */
     virtual status_t Initialize();
 
-    /* Starts capturing frames from the camera device.
-     *
-     * Typically, this method caches desired frame parameters, and calls
-     * startDevice 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.
+    /* 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 startCapturing(int width, int height, uint32_t pix_fmt);
+    virtual status_t startDeliveringFrames(bool one_burst);
 
-    /* Stops capturing frames from the camera device.
-     *
-     * Typically, this method calls stopDevice 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.
+    /* 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 stopCapturing();
+    virtual status_t stopDeliveringFrames();
 
-    /* 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.
+    /* 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 - 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 RGBA8888.
+     *  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. */
+    /* 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. */
+    /* 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. */
+    /* 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. */
+    /* 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 physical device streams.
+    /* 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
@@ -198,17 +216,17 @@
      * 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.
+     * 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.
+     *  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;
     }
 
@@ -222,16 +240,32 @@
         return mWorkerThread.get() != NULL && mState != ECDS_CONSTRUCTED;
     }
     inline bool isConnected() const {
-        /* Instance is connected when it is initialized and its status is either
-         * "connected", or "capturing". */
-        return isInitialized() &&
-               (mState == ECDS_CONNECTED || mState == ECDS_CAPTURING);
+        /* Instance is connected when its status is either"connected", or
+         * "started". */
+        return mState == ECDS_CONNECTED || mState == ECDS_STARTED;
     }
-    inline bool isCapturing() const {
-        return isInitialized() && mState == ECDS_CAPTURING;
+    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,
@@ -242,15 +276,22 @@
 
 protected:
     /* Starts the worker thread.
-     * Typically, worker thread is started from StartCamera method of this
-     * class.
+     * 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();
+    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.
      */
@@ -260,7 +301,7 @@
      * 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.
+     * 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.
@@ -298,9 +339,19 @@
                 }
             }
 
-            /* Starts the thread */
-            inline status_t startThread()
+            /* 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);
             }
 
@@ -343,10 +394,15 @@
 
         private:
             /* Implements abstract method of the base Thread class. */
-            inline bool threadLoop()
+            bool threadLoop()
             {
                 /* Simply dispatch the call to the containing camera device. */
-                return mCameraDevice->inWorkerThread();
+                if (mCameraDevice->inWorkerThread()) {
+                    /* Respect "one burst" parameter (see startThread). */
+                    return !mOneBurst;
+                } else {
+                    return false;
+                }
             }
 
             /* Containing camera device object. */
@@ -358,6 +414,10 @@
             /* 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. */
@@ -391,12 +451,6 @@
     /* Framebuffer containing the current frame. */
     uint8_t*                    mCurrentFrame;
 
-    /* U panel inside the framebuffer. */
-    uint8_t*                    mFrameU;
-
-    /* V panel inside the framebuffer. */
-    uint8_t*                    mFrameV;
-
     /*
      * Framebuffer properties.
      */
@@ -426,8 +480,8 @@
         ECDS_INITIALIZED,
         /* Object has been connected to the physical device. */
         ECDS_CONNECTED,
-        /* Frames are being captured. */
-        ECDS_CAPTURING,
+        /* Camera device has been started. */
+        ECDS_STARTED,
     };
 
     /* Object state. */
diff --git a/tools/emulator/system/camera/EmulatedCameraFactory.cpp b/tools/emulator/system/camera/EmulatedCameraFactory.cpp
index d6ba9b4..5c5c5de 100755
--- a/tools/emulator/system/camera/EmulatedCameraFactory.cpp
+++ b/tools/emulator/system/camera/EmulatedCameraFactory.cpp
@@ -22,6 +22,7 @@
 #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"
@@ -43,9 +44,8 @@
           mConstructedOK(false)
 
 {
-    /* If qemu camera emulation is on, try to connect to the factory service in
-     * the emulator. */
-    if (isQemuCameraEmulationOn() && mQemuClient.connectClient(NULL) == NO_ERROR) {
+    /* 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();
@@ -82,6 +82,8 @@
             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",
@@ -121,7 +123,7 @@
         return -EINVAL;
     }
 
-    if (camera_id >= getEmulatedCameraNum()) {
+    if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) {
         LOGE("%s: Camera id %d is out of bounds (%d)",
              __FUNCTION__, camera_id, getEmulatedCameraNum());
         return -EINVAL;
@@ -139,7 +141,7 @@
         return -EINVAL;
     }
 
-    if (camera_id >= getEmulatedCameraNum()) {
+    if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) {
         LOGE("%s: Camera id %d is out of bounds (%d)",
              __FUNCTION__, camera_id, getEmulatedCameraNum());
         return -EINVAL;
@@ -197,6 +199,8 @@
 static const char lListNameToken[]    = "name=";
 /* Frame dimensions token. */
 static const char lListDimsToken[]    = "framedims=";
+/* Facing direction token. */
+static const char lListDirToken[]     = "dir=";
 
 void EmulatedCameraFactory::createQemuCameras()
 {
@@ -252,13 +256,15 @@
             next_entry++;   // Start of the next entry.
         }
 
-        /* Find 'name', and 'framedims' tokens that are required here. */
+        /* Find 'name', 'framedims', and 'dir' tokens that are required here. */
         char* name_start = strstr(cur_entry, lListNameToken);
         char* dim_start = strstr(cur_entry, lListDimsToken);
-        if (name_start != NULL && dim_start != NULL) {
+        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, ' ');
@@ -269,12 +275,16 @@
             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);
+                res = qemu_cam->Initialize(name_start, dim_start, dir_start);
                 if (res == NO_ERROR) {
                     mEmulatedCameras[index] = qemu_cam;
                     index++;
@@ -295,16 +305,17 @@
     mEmulatedCameraNum = index;
 }
 
-bool EmulatedCameraFactory::isQemuCameraEmulationOn()
-{
-    /* TODO: Have a boot property that controls that! */
-    return true;
-}
-
 bool EmulatedCameraFactory::isFakeCameraEmulationOn()
 {
-    /* TODO: Have a boot property that controls that! */
-    return true;
+    /* 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;
+    }
 }
 
 /********************************************************************************
diff --git a/tools/emulator/system/camera/EmulatedCameraFactory.h b/tools/emulator/system/camera/EmulatedCameraFactory.h
index 1e40d82..19745a3 100755
--- a/tools/emulator/system/camera/EmulatedCameraFactory.h
+++ b/tools/emulator/system/camera/EmulatedCameraFactory.h
@@ -94,11 +94,6 @@
      ***************************************************************************/
 
 public:
-    /* Gets fake camera facing. */
-    int getFakeCameraFacing() {
-        /* TODO: Have a boot property that controls that. */
-        return CAMERA_FACING_BACK;
-    }
 
     /* Gets fake camera orientation. */
     int getFakeCameraOrientation() {
@@ -106,12 +101,6 @@
         return 90;
     }
 
-    /* Gets qemu camera facing. */
-    int getQemuCameraFacing() {
-        /* TODO: Have a boot property that controls that. */
-        return CAMERA_FACING_FRONT;
-    }
-
     /* Gets qemu camera orientation. */
     int getQemuCameraOrientation() {
         /* TODO: Have a boot property that controls that. */
@@ -142,9 +131,6 @@
      */
     void createQemuCameras();
 
-    /* Checks if qemu camera emulation is on. */
-    bool isQemuCameraEmulationOn();
-
     /* Checks if fake camera emulation is on. */
     bool isFakeCameraEmulationOn();
 
diff --git a/tools/emulator/system/camera/EmulatedFakeCamera.cpp b/tools/emulator/system/camera/EmulatedFakeCamera.cpp
index 84828cf..d82fd78 100755
--- a/tools/emulator/system/camera/EmulatedFakeCamera.cpp
+++ b/tools/emulator/system/camera/EmulatedFakeCamera.cpp
@@ -22,6 +22,7 @@
 #define LOG_NDEBUG 0
 #define LOG_TAG "EmulatedCamera_FakeCamera"
 #include <cutils/log.h>
+#include <cutils/properties.h>
 #include "EmulatedFakeCamera.h"
 #include "EmulatedCameraFactory.h"
 
@@ -48,11 +49,13 @@
         return res;
     }
 
-    const char* facing = EmulatedCamera::FACING_BACK;
-    if (gEmulatedCameraFactory.getFakeCameraOrientation() == CAMERA_FACING_FRONT) {
-        facing = EmulatedCamera::FACING_FRONT;
-    }
+    /* 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());
diff --git a/tools/emulator/system/camera/EmulatedFakeCamera.h b/tools/emulator/system/camera/EmulatedFakeCamera.h
index f8a8099..3debe9e 100755
--- a/tools/emulator/system/camera/EmulatedFakeCamera.h
+++ b/tools/emulator/system/camera/EmulatedFakeCamera.h
@@ -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();
 
     /****************************************************************************
diff --git a/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp b/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp
index a6c97c6..1aac442 100755
--- a/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp
+++ b/tools/emulator/system/camera/EmulatedFakeCameraDevice.cpp
@@ -34,9 +34,15 @@
       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
 {
 }
 
@@ -62,6 +68,7 @@
         return NO_ERROR;
     }
 
+    /* There is no device to connect to. */
     mState = ECDS_CONNECTED;
 
     return NO_ERROR;
@@ -76,57 +83,92 @@
         LOGW("%s: Fake camera device is already disconnected.", __FUNCTION__);
         return NO_ERROR;
     }
-    if (isCapturing()) {
-        LOGE("%s: Cannot disconnect while in the capturing state.", __FUNCTION__);
+    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()
+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 (isCapturing()) {
-        LOGW("%s: Fake camera device is already capturing.", __FUNCTION__);
-        return NO_ERROR;
+    if (isStarted()) {
+        LOGE("%s: Fake camera device is already started.", __FUNCTION__);
+        return EINVAL;
     }
 
-    /* Used in calculating U/V position when drawing the square. */
-    mHalfWidth = mFrameWidth / 2;
+    /* 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:
+                mFrameU = mCurrentFrame + mTotalPixels;
+                mFrameV = mFrameU + mTotalPixels / 4;
+                mUVStep = 1;
+                mUVTotalNum = mTotalPixels / 4;
+                break;
 
-    /* Just start the worker thread: there is no real device to deal with. */
-    const status_t ret = startWorkerThread();
-    if (ret == NO_ERROR) {
-        mState = ECDS_CAPTURING;
+            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 ret;
+    return res;
 }
 
 status_t EmulatedFakeCameraDevice::stopDevice()
 {
     LOGV("%s", __FUNCTION__);
 
-    if (!isCapturing()) {
-        LOGW("%s: Fake camera device is not capturing.", __FUNCTION__);
+    Mutex::Autolock locker(&mObjectLock);
+    if (!isStarted()) {
+        LOGW("%s: Fake camera device is not started.", __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) {
-        mState = ECDS_CONNECTED;
-    }
+    mFrameU = mFrameV = NULL;
+    EmulatedCameraDevice::commonStopDevice();
+    mState = ECDS_CONNECTED;
 
-    return ret;
+    return NO_ERROR;
 }
 
 /****************************************************************************
@@ -144,23 +186,31 @@
     }
 
     /* Lets see if we need to generate a new frame. */
-    if ((systemTime(SYSTEM_TIME_MONOTONIC) - mCurFrameTimestamp) >= mRedrawAfter) {
+    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();
 
-        /* Run the square. */
-        int x = ((mCcounter * 3) & 255);
-        if(x > 128) x = 255 - x;
-        int y = ((mCcounter * 5) & 255);
-        if(y > 128) y = 255 - y;
-        const int size = mFrameWidth / 10;
-        drawSquare(x * size / 32, y * size / 32, (size * 5) >> 1,
-                   (mCcounter & 0x100) ? &mRedYUV : &mGreenYUV);
-        mCcounter++;
+#endif  // EFCD_ROTATE_FRAME
+
+        mLastRedrawn = systemTime(SYSTEM_TIME_MONOTONIC);
     }
 
     /* Timestamp the current frame, and notify the camera HAL about new frame. */
@@ -202,7 +252,7 @@
                 mWhiteYUV.get(Y, U, V);
             }
             Y[1] = *Y;
-            Y += 2; U++; V++;
+            Y += 2; U += mUVStep; V += mUVStep;
             countx += 2;
             if(countx >= size) {
                 countx = 0;
@@ -223,6 +273,16 @@
     }
     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,
@@ -230,24 +290,115 @@
                                           int size,
                                           const YUVPixel* color)
 {
-    const int half_x = x / 2;
-    const int square_xstop = min(mFrameWidth, x+size);
-    const int square_ystop = min(mFrameHeight, y+size);
+    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) * mHalfWidth + half_x;
+        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++; sqV++;
+            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
index c9f13ea..f54127e 100755
--- a/tools/emulator/system/camera/EmulatedFakeCameraDevice.h
+++ b/tools/emulator/system/camera/EmulatedFakeCameraDevice.h
@@ -25,6 +25,15 @@
 #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;
@@ -62,19 +71,15 @@
      */
     status_t disconnectDevice();
 
-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 startDevice();
+    /* Starts the camera device. */
+    status_t startDevice(int width, int height, uint32_t pix_fmt);
 
-    /* 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.
-     */
+    /* 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
@@ -83,8 +88,8 @@
 
 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
+     * 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();
@@ -105,6 +110,12 @@
      */
     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
      ***************************************************************************/
@@ -120,14 +131,37 @@
     YUVPixel    mGreenYUV;
     YUVPixel    mBlueYUV;
 
+    /* Last time the frame has been redrawn. */
+    nsecs_t     mLastRedrawn;
+
     /*
-     * Drawing related stuff
+     * 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;
-    int         mHalfWidth;
 
     /* Emulated FPS (frames per second).
      * We will emulate 50 FPS. */
@@ -136,6 +170,25 @@
     /* 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 */
diff --git a/tools/emulator/system/camera/EmulatedQemuCamera.cpp b/tools/emulator/system/camera/EmulatedQemuCamera.cpp
index 5c98ae6..611b6b5 100755
--- a/tools/emulator/system/camera/EmulatedQemuCamera.cpp
+++ b/tools/emulator/system/camera/EmulatedQemuCamera.cpp
@@ -42,8 +42,11 @@
  ***************************************************************************/
 
 status_t EmulatedQemuCamera::Initialize(const char* device_name,
-                                        const char* frame_dims)
+                                        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;
 
@@ -63,11 +66,7 @@
      * Set customizable parameters.
      */
 
-    const char* facing = EmulatedCamera::FACING_FRONT;
-    if (gEmulatedCameraFactory.getQemuCameraOrientation() == CAMERA_FACING_BACK) {
-        facing = EmulatedCamera::FACING_BACK;
-    }
-    mParameters.set(EmulatedCamera::FACING_KEY, facing);
+    mParameters.set(EmulatedCamera::FACING_KEY, facing_dir);
     mParameters.set(EmulatedCamera::ORIENTATION_KEY,
                     gEmulatedCameraFactory.getQemuCameraOrientation());
     mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, frame_dims);
@@ -84,7 +83,7 @@
     if (c == NULL) {
         strncpy(first_dim, frame_dims, sizeof(first_dim));
         first_dim[sizeof(first_dim)-1] = '\0';
-    } else if ((c - frame_dims) < sizeof(first_dim)) {
+    } 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 {
diff --git a/tools/emulator/system/camera/EmulatedQemuCamera.h b/tools/emulator/system/camera/EmulatedQemuCamera.h
index f00076b..1b826c7 100755
--- a/tools/emulator/system/camera/EmulatedQemuCamera.h
+++ b/tools/emulator/system/camera/EmulatedQemuCamera.h
@@ -42,12 +42,10 @@
      **************************************************************************/
 
 public:
-    /* Initializes EmulatedQemuCamera instance.
-     * The contained EmulatedQemuCameraDevice will be initialized in this method.
-     * Return:
-     *  NO_ERROR on success, or an appropriate error status.
-     */
-     status_t Initialize(const char* device_name, const char* frame_dims);
+    /* Initializes EmulatedQemuCamera instance. */
+     status_t Initialize(const char* device_name,
+                         const char* frame_dims,
+                         const char* facing_dir);
 
     /***************************************************************************
      * EmulatedCamera abstract API implementation.
diff --git a/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp b/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp
index 1342b95..5117a84 100755
--- a/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp
+++ b/tools/emulator/system/camera/EmulatedQemuCameraDevice.cpp
@@ -82,16 +82,20 @@
         return EINVAL;
     }
     if (isConnected()) {
-        LOGW("%s: Qemu camera device is already connected.", __FUNCTION__);
+        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", __FUNCTION__);
+        LOGV("%s: Connected to device '%s'",
+             __FUNCTION__, (const char*)mDeviceName);
         mState = ECDS_CONNECTED;
     } else {
-        LOGE("%s: Connection failed", __FUNCTION__);
+        LOGE("%s: Connection to device '%s' failed",
+             __FUNCTION__, (const char*)mDeviceName);
     }
 
     return res;
@@ -103,62 +107,76 @@
 
     Mutex::Autolock locker(&mObjectLock);
     if (!isConnected()) {
-        LOGW("%s: Qemu camera device is already disconnected.", __FUNCTION__);
+        LOGW("%s: Qemu camera device '%s' is already disconnected.",
+             __FUNCTION__, (const char*)mDeviceName);
         return NO_ERROR;
     }
-    if (isCapturing()) {
-        LOGE("%s: Cannot disconnect while in the capturing state.", __FUNCTION__);
+    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", __FUNCTION__);
+        LOGV("%s: Disonnected from device '%s'",
+             __FUNCTION__, (const char*)mDeviceName);
         mState = ECDS_INITIALIZED;
     } else {
-        LOGE("%s: Disconnection failed", __FUNCTION__);
+        LOGE("%s: Disconnection from device '%s' failed",
+             __FUNCTION__, (const char*)mDeviceName);
     }
 
     return res;
 }
 
-status_t EmulatedQemuCameraDevice::startDevice()
+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 is not connected.", __FUNCTION__);
+        LOGE("%s: Qemu camera device '%s' is not connected.",
+             __FUNCTION__, (const char*)mDeviceName);
         return EINVAL;
     }
-    if (isCapturing()) {
-        LOGW("%s: Qemu camera device is already capturing.", __FUNCTION__);
+    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 uint16_t[mTotalPixels * 4];
+    mPreviewFrame = new uint32_t[mTotalPixels];
     if (mPreviewFrame == NULL) {
         LOGE("%s: Unable to allocate %d bytes for preview frame",
-             __FUNCTION__, mTotalPixels * 4);
+             __FUNCTION__, mTotalPixels);
         return ENOMEM;
     }
-    memset(mPreviewFrame, 0, mTotalPixels * 4);
 
     /* Start the actual camera device. */
-    status_t res =
-        mQemuClient.queryStart(mPixelFormat, mFrameWidth, mFrameHeight);
+    res = mQemuClient.queryStart(mPixelFormat, mFrameWidth, mFrameHeight);
     if (res == NO_ERROR) {
-        /* Start the worker thread. */
-        res = startWorkerThread();
-        if (res == NO_ERROR) {
-            mState = ECDS_CAPTURING;
-        } else {
-            mQemuClient.queryStop();
-        }
+        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: Start failed", __FUNCTION__);
+        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;
@@ -168,28 +186,27 @@
 {
     LOGV("%s", __FUNCTION__);
 
-    if (!isCapturing()) {
-        LOGW("%s: Qemu camera device is not capturing.", __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 worker thread first. */
-    status_t res = stopWorkerThread();
+    /* Stop the actual camera device. */
+    status_t res = mQemuClient.queryStop();
     if (res == NO_ERROR) {
-        /* Stop the actual camera device. */
-        res = mQemuClient.queryStop();
-        if (res == NO_ERROR) {
-            if (mPreviewFrame == NULL) {
-                delete[] mPreviewFrame;
-                mPreviewFrame = NULL;
-            }
-            mState = ECDS_CONNECTED;
-            LOGV("%s: Stopped", __FUNCTION__);
-        } else {
-            LOGE("%s: Stop failed", __FUNCTION__);
+        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 worker thread", __FUNCTION__);
+        LOGE("%s: Unable to stop device '%s'",
+             __FUNCTION__, (const char*)mDeviceName);
     }
 
     return res;
diff --git a/tools/emulator/system/camera/EmulatedQemuCameraDevice.h b/tools/emulator/system/camera/EmulatedQemuCameraDevice.h
index 2030869..8ef562b 100755
--- a/tools/emulator/system/camera/EmulatedQemuCameraDevice.h
+++ b/tools/emulator/system/camera/EmulatedQemuCameraDevice.h
@@ -67,15 +67,16 @@
     /* Disconnects from the camera device. */
     status_t disconnectDevice();
 
-protected:
     /* Starts capturing frames from the camera device. */
-    status_t startDevice();
+    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:
@@ -108,7 +109,7 @@
     String8             mDeviceName;
 
     /* Current preview framebuffer. */
-    uint16_t*           mPreviewFrame;
+    uint32_t*           mPreviewFrame;
 
     /* Emulated FPS (frames per second).
      * We will emulate 50 FPS. */
diff --git a/tools/emulator/system/camera/JpegCompressor.cpp b/tools/emulator/system/camera/JpegCompressor.cpp
new file mode 100644
index 0000000..d8976c2
--- /dev/null
+++ b/tools/emulator/system/camera/JpegCompressor.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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] = mStrides[2] = width / 4;
+    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/PreviewWindow.cpp b/tools/emulator/system/camera/PreviewWindow.cpp
index c96a807..c4f6f80 100755
--- a/tools/emulator/system/camera/PreviewWindow.cpp
+++ b/tools/emulator/system/camera/PreviewWindow.cpp
@@ -180,6 +180,10 @@
     grbuffer_mapper.unlock(*buffer);
 }
 
+/***************************************************************************
+ * Private API
+ **************************************************************************/
+
 bool PreviewWindow::adjustPreviewDimensions(EmulatedCameraDevice* camera_dev)
 {
     /* Match the cached frame dimensions against the actual ones. */
diff --git a/tools/emulator/system/camera/QemuClient.cpp b/tools/emulator/system/camera/QemuClient.cpp
index 49307bb..fd49585 100755
--- a/tools/emulator/system/camera/QemuClient.cpp
+++ b/tools/emulator/system/camera/QemuClient.cpp
@@ -19,7 +19,7 @@
  * services in the emulator via qemu pipe.
  */
 
-#define LOG_NDEBUG 0
+#define LOG_NDEBUG 1
 #define LOG_TAG "EmulatedCamera_QemuClient"
 #include <cutils/log.h>
 #include "EmulatedCamera.h"
@@ -40,7 +40,7 @@
 
 QemuQuery::QemuQuery()
     : mQuery(mQueryPrealloc),
-      mQueryStatus(NO_ERROR),
+      mQueryDeliveryStatus(NO_ERROR),
       mReplyBuffer(NULL),
       mReplyData(NULL),
       mReplySize(0),
@@ -52,26 +52,26 @@
 
 QemuQuery::QemuQuery(const char* query_string)
     : mQuery(mQueryPrealloc),
-      mQueryStatus(NO_ERROR),
+      mQueryDeliveryStatus(NO_ERROR),
       mReplyBuffer(NULL),
       mReplyData(NULL),
       mReplySize(0),
       mReplyDataSize(0),
       mReplyStatus(0)
 {
-    mQueryStatus = QemuQuery::createQuery(query_string, NULL);
+    mQueryDeliveryStatus = QemuQuery::createQuery(query_string, NULL);
 }
 
 QemuQuery::QemuQuery(const char* query_name, const char* query_param)
     : mQuery(mQueryPrealloc),
-      mQueryStatus(NO_ERROR),
+      mQueryDeliveryStatus(NO_ERROR),
       mReplyBuffer(NULL),
       mReplyData(NULL),
       mReplySize(0),
       mReplyDataSize(0),
       mReplyStatus(0)
 {
-    mQueryStatus = QemuQuery::createQuery(query_name, query_param);
+    mQueryDeliveryStatus = QemuQuery::createQuery(query_name, query_param);
 }
 
 QemuQuery::~QemuQuery()
@@ -88,6 +88,7 @@
     if (name == NULL || *name == '\0') {
         LOGE("%s: NULL or an empty string is passed as query name.",
              __FUNCTION__);
+        mQueryDeliveryStatus = EINVAL;
         return EINVAL;
     }
 
@@ -101,7 +102,7 @@
         if (mQuery == NULL) {
             LOGE("%s: Unable to allocate %d bytes for query buffer",
                  __FUNCTION__, required);
-            mQueryStatus = ENOMEM;
+            mQueryDeliveryStatus = ENOMEM;
             return ENOMEM;
         }
     }
@@ -119,9 +120,9 @@
 status_t QemuQuery::completeQuery(status_t status)
 {
     /* Save query completion status. */
-    mQueryStatus = status;
-    if (mQueryStatus != NO_ERROR) {
-        return mQueryStatus;
+    mQueryDeliveryStatus = status;
+    if (mQueryDeliveryStatus != NO_ERROR) {
+        return mQueryDeliveryStatus;
     }
 
     /* Make sure reply buffer contains at least 'ok', or 'ko'.
@@ -131,7 +132,7 @@
      * zero-terminated, and the terminator will be inculded in the reply. */
     if (mReplyBuffer == NULL || mReplySize < 3) {
         LOGE("%s: Invalid reply to the query", __FUNCTION__);
-        mQueryStatus = EINVAL;
+        mQueryDeliveryStatus = EINVAL;
         return EINVAL;
     }
 
@@ -142,7 +143,7 @@
         mReplyStatus = 0;
     } else {
         LOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
-        mQueryStatus = EINVAL;
+        mQueryDeliveryStatus = EINVAL;
         return EINVAL;
     }
 
@@ -152,7 +153,7 @@
          * with a ':' */
         if (mReplyBuffer[2] != ':') {
             LOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
-            mQueryStatus = EINVAL;
+            mQueryDeliveryStatus = EINVAL;
             return EINVAL;
         }
         mReplyData = mReplyBuffer + 3;
@@ -162,7 +163,7 @@
          * zero-terminator. */
         if (mReplyBuffer[2] != '\0') {
             LOGE("%s: Invalid query reply: '%s'", __FUNCTION__, mReplyBuffer);
-            mQueryStatus = EINVAL;
+            mQueryDeliveryStatus = EINVAL;
             return EINVAL;
         }
     }
@@ -176,14 +177,13 @@
         delete[] mQuery;
     }
     mQuery = mQueryPrealloc;
-    mQueryStatus = NO_ERROR;
+    mQueryDeliveryStatus = NO_ERROR;
     if (mReplyBuffer != NULL) {
         free(mReplyBuffer);
         mReplyBuffer = NULL;
     }
     mReplyData = NULL;
-    mReplySize = 0;
-    mReplyDataSize = 0;
+    mReplySize = mReplyDataSize = 0;
     mReplyStatus = 0;
 }
 
@@ -270,9 +270,9 @@
     if (written == data_size) {
         return NO_ERROR;
     } else {
-        LOGE("%s: Error sending data via qemu pipe: %s",
+        LOGE("%s: Error sending data via qemu pipe: '%s'",
              __FUNCTION__, strerror(errno));
-        return errno != NO_ERROR ? errno : EIO;
+        return errno ? errno : EIO;
     }
 }
 
@@ -331,9 +331,9 @@
 status_t QemuClient::doQuery(QemuQuery* query)
 {
     /* Make sure that query has been successfuly constructed. */
-    if (query->mQueryStatus != NO_ERROR) {
+    if (query->mQueryDeliveryStatus != NO_ERROR) {
         LOGE("%s: Query is invalid", __FUNCTION__);
-        return query->mQueryStatus;
+        return query->mQueryDeliveryStatus;
     }
 
     LOGQ("Send query '%s'", query->mQuery);
@@ -357,7 +357,11 @@
     }
 
     /* Complete the query, and return its completion handling status. */
-    return query->completeQuery(res);
+    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;
 }
 
 /****************************************************************************
@@ -385,8 +389,9 @@
     LOGV("%s", __FUNCTION__);
 
     QemuQuery query(mQueryList);
-    doQuery(&query);
-    if (!query.isQuerySucceeded()) {
+    if (doQuery(&query) || !query.isQuerySucceeded()) {
+        LOGE("%s: List cameras query failed: %s", __FUNCTION__,
+             query.mReplyData ? query.mReplyData : "No error message");
         return query.getCompletionStatus();
     }
 
@@ -445,9 +450,9 @@
     QemuQuery query(mQueryConnect);
     doQuery(&query);
     const status_t res = query.getCompletionStatus();
-    LOGE_IF(res != NO_ERROR, "%s failed: %s",
+    LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
             __FUNCTION__, query.mReplyData ? query.mReplyData :
-                                              "No error message");
+                                             "No error message");
     return res;
 }
 
@@ -458,9 +463,9 @@
     QemuQuery query(mQueryDisconnect);
     doQuery(&query);
     const status_t res = query.getCompletionStatus();
-    LOGE_IF(res != NO_ERROR, "%s failed: %s",
+    LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
             __FUNCTION__, query.mReplyData ? query.mReplyData :
-                                              "No error message");
+                                             "No error message");
     return res;
 }
 
@@ -476,9 +481,9 @@
     QemuQuery query(query_str);
     doQuery(&query);
     const status_t res = query.getCompletionStatus();
-    LOGE_IF(res != NO_ERROR, "%s failed: %s",
+    LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
             __FUNCTION__, query.mReplyData ? query.mReplyData :
-                                              "No error message");
+                                             "No error message");
     return res;
 }
 
@@ -489,9 +494,9 @@
     QemuQuery query(mQueryStop);
     doQuery(&query);
     const status_t res = query.getCompletionStatus();
-    LOGE_IF(res != NO_ERROR, "%s failed: %s",
+    LOGE_IF(res != NO_ERROR, "%s: Query failed: %s",
             __FUNCTION__, query.mReplyData ? query.mReplyData :
-                                              "No error message");
+                                             "No error message");
     return res;
 }
 
@@ -500,6 +505,8 @@
                                       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,
@@ -507,39 +514,41 @@
     QemuQuery query(query_str);
     doQuery(&query);
     const status_t res = query.getCompletionStatus();
-    LOGE_IF(res != NO_ERROR, "%s failed: %s",
-            __FUNCTION__, query.mReplyData ? query.mReplyData :
+    if( res != NO_ERROR) {
+        LOGE("%s: Query failed: %s",
+             __FUNCTION__, query.mReplyData ? query.mReplyData :
                                               "No error message");
-    if (res == NO_ERROR) {
-        /* 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 video frame (%d bytes)",
-                     __FUNCTION__, query.mReplyDataSize - cur_offset, vframe_size);
-                return EINVAL;
-            }
+        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 preview frame (%d bytes)",
-                     __FUNCTION__, query.mReplyDataSize - cur_offset, pframe_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 res;
+    return NO_ERROR;
 }
 
 }; /* namespace android */
diff --git a/tools/emulator/system/camera/QemuClient.h b/tools/emulator/system/camera/QemuClient.h
index 9614a4d..c0b8e61 100755
--- a/tools/emulator/system/camera/QemuClient.h
+++ b/tools/emulator/system/camera/QemuClient.h
@@ -57,7 +57,9 @@
  *  - '=' are allowed only to divide parameter names from parameter values.
  *
  * Emulator replies to each query in two chunks:
- * - 4 bytes encoding the payload size
+ * - 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
@@ -66,7 +68,9 @@
  *  - '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.
+ * 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:
@@ -81,7 +85,7 @@
      */
     explicit QemuQuery(const char* query_string);
 
-    /* Constructs and initializes QemuQuery instance for a query.
+    /* Constructs and initializes QemuQuery instance for a query with parameters.
      * Param:
      *  query_name - Query name.
      *  query_param - Query parameters. Can be NULL.
@@ -96,7 +100,8 @@
      ***************************************************************************/
 
     /* Creates new query.
-     * This method will reset this instance prior to creating a 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.
@@ -108,19 +113,19 @@
     /* 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 query reply.
+     * 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' 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 status indicates a
-     *  failure, the entire query has failed. If status indicates a success, the
-     *  reply will be checked here to calculate the final query status.
+     *      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 to check the final
-     *  query status.
+     *  Use isQuerySucceeded() / getCompletionStatus() methods of this class to
+     *  check the final query status.
      */
     status_t completeQuery(status_t status);
 
@@ -132,19 +137,26 @@
      * class has been executed.
      */
     inline bool isQuerySucceeded() const {
-        return mQueryStatus == NO_ERROR && mReplyStatus != 0;
+        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.
-     *  NO_ERROR on success, or an appropriate error status on failure.
+     * Return:
+     *  NO_ERROR if query has succeeded, or an appropriate error status on query
+     *  failure.
      */
     inline status_t getCompletionStatus() const {
-        if (isQuerySucceeded()) {
-            return NO_ERROR;
+        if (mQueryDeliveryStatus == NO_ERROR) {
+            if (mReplyStatus) {
+                return NO_ERROR;
+            } else {
+                return EINVAL;
+            }
+        } else {
+            return mQueryDeliveryStatus;
         }
-        return (mQueryStatus != NO_ERROR) ? mQueryStatus : EINVAL;
     }
 
     /****************************************************************************
@@ -154,8 +166,8 @@
 public:
     /* Query string. */
     char*       mQuery;
-    /* Query status. */
-    status_t    mQueryStatus;
+    /* Query delivery status. */
+    status_t    mQueryDeliveryStatus;
     /* Reply buffer */
     char*       mReplyBuffer;
     /* Reply data (past 'ok'/'ko'). If NULL, there were no data in reply. */
@@ -208,7 +220,7 @@
      *      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 connection with a 'factory'
+     *      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:
@@ -216,10 +228,10 @@
      *          "name=<device name> [inp_channel=<input channel #>]",
      *
      *      where 'device name' is a required parameter defining name of the
-     *      camera device, 'input channel' is an optional parameter (positive
-     *      integer), defining input channel to use on the camera device. Note
-     *      that device name passed here must have been previously obtained from
-     *      the factory service.
+     *      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.
      */
@@ -259,11 +271,11 @@
      * 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 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 'mQueryStatus', which is always in the
-     *  proper state).
+     *  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);
 
@@ -300,25 +312,26 @@
 public:
     /* Lists camera devices connected to the host.
      * Param:
-     *  list - Upon success contains list of cameras connected to the host. The
+     *  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
+     *      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 camera device attached to the host. This name
-     *        must be used for subsequent connection to the 'emulated camera'
+     *      - '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" int), chosen for the video frames.
+     *      - '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. 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
-     *        ','.
+     *        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.
      */