Merge "Adjust boundaries for screen sizes." into gingerbread
diff --git a/api/current.xml b/api/current.xml
index d36fe69..626a5cc 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -6961,6 +6961,17 @@
  visibility="public"
 >
 </field>
+<field name="screenDensity"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843467"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="screenOrientation"
  type="int"
  transient="false"
@@ -6972,6 +6983,17 @@
  visibility="public"
 >
 </field>
+<field name="screenSize"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843466"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="scrollHorizontally"
  type="int"
  transient="false"
@@ -172683,6 +172705,17 @@
  visibility="public"
 >
 </field>
+<field name="DENSITY_XHIGH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="320"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="density"
  type="float"
  transient="false"
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 822f62d..0723f67 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -216,19 +216,21 @@
         fclose(cmdline);
     }
 
-    /* switch to non-root user and group */
-    gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT };
-    if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
-        LOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
-        return -1;
-    }
-    if (setgid(AID_SHELL) != 0) {
-        LOGE("Unable to setgid, aborting: %s\n", strerror(errno));
-        return -1;
-    }
-    if (setuid(AID_SHELL) != 0) {
-        LOGE("Unable to setuid, aborting: %s\n", strerror(errno));
-        return -1;
+    if (getuid() == 0) {
+        /* switch to non-root user and group */
+        gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT };
+        if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+            LOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
+            return -1;
+        }
+        if (setgid(AID_SHELL) != 0) {
+            LOGE("Unable to setgid, aborting: %s\n", strerror(errno));
+            return -1;
+        }
+        if (setuid(AID_SHELL) != 0) {
+            LOGE("Unable to setuid, aborting: %s\n", strerror(errno));
+            return -1;
+        }
     }
 
     char path[PATH_MAX], tmp_path[PATH_MAX];
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 51f4202..ff3656c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1080,6 +1080,16 @@
 
                 XmlUtils.skipCurrentTag(parser);
                 
+            } else if (tagName.equals("uses-gl-texture")) {
+                // Just skip this tag
+                XmlUtils.skipCurrentTag(parser);
+                continue;
+                
+            } else if (tagName.equals("compatible-screens")) {
+                // Just skip this tag
+                XmlUtils.skipCurrentTag(parser);
+                continue;
+                
             } else if (tagName.equals("eat-comment")) {
                 // Just skip this tag
                 XmlUtils.skipCurrentTag(parser);
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 6ff5a40..275e2eb 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -779,9 +779,9 @@
      * Set the clockwise rotation of preview display in degrees. This affects
      * the preview frames and the picture displayed after snapshot. This method
      * is useful for portrait mode applications. Note that preview display of
-     * front-facing cameras is flipped horizontally, that is, the image is
-     * reflected along the central vertical axis of the camera sensor. So the
-     * users can see themselves as looking into a mirror.
+     * front-facing cameras is flipped horizontally before the rotation, that
+     * is, the image is reflected along the central vertical axis of the camera
+     * sensor. So the users can see themselves as looking into a mirror.
      *
      * This does not affect the order of byte array passed in {@link
      * PreviewCallback#onPreviewFrame}, JPEG pictures, or recorded videos. This
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 2b083dc..9645a17 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -452,17 +452,14 @@
         private void dispatchPointer(MotionEvent event) {
             synchronized (mLock) {
                 if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                    if (mPendingMove != null) {
-                        mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
-                        mPendingMove.recycle();
-                    }
                     mPendingMove = event;
                 } else {
                     mPendingMove = null;
                 }
-                Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event);
-                mCaller.sendMessage(msg);
             }
+
+            Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event);
+            mCaller.sendMessage(msg);
         }
 
         void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
@@ -905,14 +902,22 @@
                     mEngine.doOffsetsChanged();
                 } break;
                 case MSG_TOUCH_EVENT: {
+                    boolean skip = false;
                     MotionEvent ev = (MotionEvent)message.obj;
-                    synchronized (mEngine.mLock) {
-                        if (mEngine.mPendingMove == ev) {
-                            mEngine.mPendingMove = null;
+                    if (ev.getAction() == MotionEvent.ACTION_MOVE) {
+                        synchronized (mEngine.mLock) {
+                            if (mEngine.mPendingMove == ev) {
+                                mEngine.mPendingMove = null;
+                            } else {
+                                // this is not the motion event we are looking for....
+                                skip = true;
+                            }
                         }
                     }
-                    if (DEBUG) Log.v(TAG, "Delivering touch event: " + ev);
-                    mEngine.onTouchEvent(ev);
+                    if (!skip) {
+                        if (DEBUG) Log.v(TAG, "Delivering touch event: " + ev);
+                        mEngine.onTouchEvent(ev);
+                    }
                     ev.recycle();
                 } break;
                 default :
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 76d8106..63baf14 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -45,6 +45,11 @@
     public static final int DENSITY_HIGH = 240;
 
     /**
+     * Standard quantized DPI for extra-high-density screens.
+     */
+    public static final int DENSITY_XHIGH = 320;
+
+    /**
      * The reference density used throughout the system.
      */
     public static final int DENSITY_DEFAULT = DENSITY_MEDIUM;
diff --git a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
index 98dcb8b..5ab9217 100644
--- a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
+++ b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.app;
 
+import com.android.internal.os.storage.ExternalStorageFormatter;
+
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -23,10 +25,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
-import android.os.storage.IMountService;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.Environment;
 import android.util.Log;
 
 /**
@@ -95,14 +93,9 @@
     public void onClick(DialogInterface dialog, int which) {
 
         if (which == POSITIVE_BUTTON) {
-            IMountService mountService = IMountService.Stub.asInterface(ServiceManager
-                .getService("mount"));
-            if (mountService != null) {
-                try {
-                    mountService.formatVolume(Environment.getExternalStorageDirectory().toString());
-                } catch (RemoteException e) {
-                }
-            }
+            Intent intent = new Intent(ExternalStorageFormatter.FORMAT_ONLY);
+            intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
+            startService(intent);
         }
 
         // No matter what, finish the activity
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 6aa77f6..63d3578 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -35,8 +35,8 @@
 #include "android_view_InputChannel.h"
 #include "android_view_KeyEvent.h"
 
-//#define LOG_TRACE(...)
-#define LOG_TRACE(...) LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define LOG_TRACE(...)
+//#define LOG_TRACE(...) LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 
 namespace android
 {
@@ -46,6 +46,7 @@
 
     jmethodID dispatchUnhandledKeyEvent;
     jmethodID preDispatchKeyEvent;
+    jmethodID finish;
     jmethodID setWindowFlags;
     jmethodID setWindowFormat;
     jmethodID showIme;
@@ -62,6 +63,7 @@
 
 enum {
     CMD_DEF_KEY = 1,
+    CMD_FINISH,
     CMD_SET_WINDOW_FORMAT,
     CMD_SET_WINDOW_FLAGS,
     CMD_SHOW_SOFT_INPUT,
@@ -512,6 +514,11 @@
     sp<Looper> looper;
 };
 
+void android_NativeActivity_finish(ANativeActivity* activity) {
+    NativeCode* code = static_cast<NativeCode*>(activity);
+    write_work(code->mainWorkWrite, CMD_FINISH, 0);
+}
+
 void android_NativeActivity_setWindowFormat(
         ANativeActivity* activity, int32_t format) {
     NativeCode* code = static_cast<NativeCode*>(activity);
@@ -538,6 +545,16 @@
 
 // ------------------------------------------------------------------------
 
+static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+   if (env->ExceptionCheck()) {
+       LOGE("An exception was thrown by callback '%s'.", methodName);
+       LOGE_EX(env);
+       env->ExceptionClear();
+       return true;
+   }
+   return false;
+}
+
 /*
  * Callback for handling native events on the application's main thread.
  */
@@ -562,6 +579,7 @@
                         code->env, keyEvent);
                 code->env->CallVoidMethod(code->clazz,
                         gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
+                checkAndClearExceptionFromCallback(code->env, "dispatchUnhandledKeyEvent");
                 code->nativeInputQueue->finishEvent(keyEvent, true);
             }
             int seq;
@@ -570,23 +588,32 @@
                         code->env, keyEvent);
                 code->env->CallVoidMethod(code->clazz,
                         gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq);
+                checkAndClearExceptionFromCallback(code->env, "preDispatchKeyEvent");
             }
         } break;
+        case CMD_FINISH: {
+            code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.finish);
+            checkAndClearExceptionFromCallback(code->env, "finish");
+        } break;
         case CMD_SET_WINDOW_FORMAT: {
             code->env->CallVoidMethod(code->clazz,
                     gNativeActivityClassInfo.setWindowFormat, work.arg1);
+            checkAndClearExceptionFromCallback(code->env, "setWindowFormat");
         } break;
         case CMD_SET_WINDOW_FLAGS: {
             code->env->CallVoidMethod(code->clazz,
                     gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);
+            checkAndClearExceptionFromCallback(code->env, "setWindowFlags");
         } break;
         case CMD_SHOW_SOFT_INPUT: {
             code->env->CallVoidMethod(code->clazz,
                     gNativeActivityClassInfo.showIme, work.arg1);
+            checkAndClearExceptionFromCallback(code->env, "showIme");
         } break;
         case CMD_HIDE_SOFT_INPUT: {
             code->env->CallVoidMethod(code->clazz,
                     gNativeActivityClassInfo.hideIme, work.arg1);
+            checkAndClearExceptionFromCallback(code->env, "hideIme");
         } break;
         default:
             LOGW("Unknown work command: %d", work.cmd);
@@ -1018,6 +1045,9 @@
             gNativeActivityClassInfo.clazz,
             "preDispatchKeyEvent", "(Landroid/view/KeyEvent;I)V");
 
+    GET_METHOD_ID(gNativeActivityClassInfo.finish,
+            gNativeActivityClassInfo.clazz,
+            "finish", "()V");
     GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags,
             gNativeActivityClassInfo.clazz,
             "setWindowFlags", "(II)V");
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 298463a..46a16fc 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1425,6 +1425,38 @@
         <attr name="functionalTest" />
     </declare-styleable>
     
+    <!-- Attributes that can be supplied in an AndroidManifest.xml
+         <code>screen</code> tag, a child of <code>compatible-screens</code>,
+         which is itseld a child of the root
+         {@link #AndroidManifest manifest} tag. -->
+    <declare-styleable name="AndroidManifestCompatibleScreensScreen">
+        <!-- Specifies a compatible screen size, as per the device
+             configuration screen size bins. -->
+        <attr name="screenSize">
+            <!-- A small screen configuration, at least 240x320db. -->
+            <enum name="small" value="200" />
+            <!-- A normal screen configuration, at least 320x480db. -->
+            <enum name="normal" value="300" />
+            <!-- A large screen configuration, at least 400x530db. -->
+            <enum name="large" value="400" />
+            <!-- An extra large screen configuration, at least 600x800db. -->
+            <enum name="xlarge" value="500" />
+        </attr>
+        <!-- Specifies a compatible screen density, as per the device
+             configuration screen density bins. -->
+        <attr name="screenDensity" format="integer">
+            <!-- A low density screen, approximately 120dpi. -->
+            <enum name="ldpi" value="120" />
+            <!-- A medium density screen, approximately 160dpi. -->
+            <enum name="mdpi" value="160" />
+            <!-- A high density screen, approximately 240dpi. -->
+            <enum name="hdpi" value="240" />
+            <!-- An extra high density screen, approximately 320dpi. -->
+            <enum name="xhdpi" value="320" />
+        </attr>
+    </declare-styleable>
+    
+    
     <!-- Declaration of an {@link android.content.Intent} object in XML.  May
          also include zero or more {@link #IntentCategory <category> and
          {@link #Extra <extra>} tags. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5531d47..4005e96 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1260,6 +1260,8 @@
   <public type="attr" name="textSelectHandle" id="0x010102c7" />
   <public type="attr" name="textSelectHandleWindowStyle" id="0x010102c8" />
   <public type="attr" name="popupAnimationStyle" id="0x010102c9" />
+  <public type="attr" name="screenSize" id="0x010102ca" />
+  <public type="attr" name="screenDensity" id="0x010102cb" />
 
   <!-- presence drawables for videochat or audiochat capable contacts -->
   <public type="drawable" name="presence_video_away" id="0x010800ac" />
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index b49e02a..5dbec59 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -26,6 +26,9 @@
 
 namespace android {
 
+extern void android_NativeActivity_finish(
+        ANativeActivity* activity);
+
 extern void android_NativeActivity_setWindowFormat(
         ANativeActivity* activity, int32_t format);
 
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 964700b..e6d84ba 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -83,6 +83,18 @@
 enum {
     CAMERA_CMD_START_SMOOTH_ZOOM     = 1,
     CAMERA_CMD_STOP_SMOOTH_ZOOM      = 2,
+    // Set the clockwise rotation of preview display (setPreviewDisplay) in
+    // degrees. This affects the preview frames and the picture displayed after
+    // snapshot. This method is useful for portrait mode applications. Note that
+    // preview display of front-facing cameras is flipped horizontally before
+    // the rotation, that is, the image is reflected along the central vertical
+    // axis of the camera sensor. So the users can see themselves as looking
+    // into a mirror.
+    //
+    // This does not affect the order of byte array of CAMERA_MSG_PREVIEW_FRAME,
+    // CAMERA_MSG_VIDEO_FRAME, CAMERA_MSG_POSTVIEW_FRAME, CAMERA_MSG_RAW_IMAGE,
+    // or CAMERA_MSG_COMPRESSED_IMAGE. This is not allowed to be set during
+    // preview.
     CAMERA_CMD_SET_DISPLAY_ORIENTATION = 3,
 };
 
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 944731d..5c618fb 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -818,7 +818,7 @@
         }
         
         // See if this device has a gamepad.
-        for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES); i++) {
+        for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
             if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
                 device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
                 break;
diff --git a/native/android/native_activity.cpp b/native/android/native_activity.cpp
index 0c6823a..056255f 100644
--- a/native/android/native_activity.cpp
+++ b/native/android/native_activity.cpp
@@ -21,6 +21,10 @@
 
 using namespace android;
 
+void ANativeActivity_finish(ANativeActivity* activity) {
+    android_NativeActivity_finish(activity);
+}
+
 void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format) {
 	android_NativeActivity_setWindowFormat(activity, format);
 }
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index d74e1ce..a8f11c9 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -227,6 +227,12 @@
  */
 extern ANativeActivity_createFunc ANativeActivity_onCreate;
 
+/**
+ * Finish the given activity.  Its finish() method will be called, causing it
+ * to be stopped and destroyed.
+ */
+void ANativeActivity_finish(ANativeActivity* activity);
+
 void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format);
 
 void ANativeActivity_setWindowFlags(ANativeActivity* activity,
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 1ea8d06..ba33e17 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -996,8 +996,8 @@
         { EGL_GREEN_SIZE,       8 },
         { EGL_RED_SIZE,         8 },
         { EGL_DEPTH_SIZE,       0 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
         { EGL_CONFIG_ID,        2 },
+        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
 };
 
@@ -1033,8 +1033,8 @@
         { EGL_GREEN_SIZE,       0 },
         { EGL_RED_SIZE,         0 },
         { EGL_DEPTH_SIZE,      16 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
         { EGL_CONFIG_ID,        5 },
+        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
         { EGL_SURFACE_TYPE,     EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
 };
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 58209fd..121819a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -150,7 +150,10 @@
         LOGE("Fail to open camera hardware (id=%d)", cameraId);
         return NULL;
     }
-    client = new Client(this, cameraClient, hardware, cameraId, callingPid);
+    CameraInfo info;
+    HAL_getCameraInfo(cameraId, &info);
+    client = new Client(this, cameraClient, hardware, cameraId, info.facing,
+                        info.orientation, callingPid);
     mClient[cameraId] = client;
     LOG1("CameraService::connect X");
     return client;
@@ -292,7 +295,7 @@
 CameraService::Client::Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
         const sp<CameraHardwareInterface>& hardware,
-        int cameraId, int clientPid) {
+        int cameraId, int cameraFacing, int cameraOrientation, int clientPid) {
     int callingPid = getCallingPid();
     LOG1("Client::Client E (pid %d)", callingPid);
 
@@ -300,6 +303,8 @@
     mCameraClient = cameraClient;
     mHardware = hardware;
     mCameraId = cameraId;
+    mCameraFacing = cameraFacing;
+    mCameraOrientation = cameraOrientation;
     mClientPid = clientPid;
     mUseOverlay = mHardware->useOverlay();
     mMsgEnabled = 0;
@@ -318,7 +323,7 @@
 
     // Callback is disabled by default
     mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
-    mOrientation = 0;
+    mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
     mOrientationChanged = false;
     cameraService->setCameraBusy(cameraId);
     cameraService->loadSound();
@@ -823,22 +828,10 @@
         if (mHardware->previewEnabled()) {
             return INVALID_OPERATION;
         }
-        switch (arg1) {
-            case 0:
-                orientation = ISurface::BufferHeap::ROT_0;
-                break;
-            case 90:
-                orientation = ISurface::BufferHeap::ROT_90;
-                break;
-            case 180:
-                orientation = ISurface::BufferHeap::ROT_180;
-                break;
-            case 270:
-                orientation = ISurface::BufferHeap::ROT_270;
-                break;
-            default:
-                return BAD_VALUE;
-        }
+        // Mirror the preview if the camera is front-facing.
+        orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT);
+        if (orientation == -1) return BAD_VALUE;
+
         if (mOrientation != orientation) {
             mOrientation = orientation;
             if (mOverlayRef != 0) mOrientationChanged = true;
@@ -1204,6 +1197,31 @@
     client->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
 }
 
+int CameraService::Client::getOrientation(int degrees, bool mirror) {
+    if (!mirror) {
+        if (degrees == 0) return 0;
+        else if (degrees == 90) return HAL_TRANSFORM_ROT_90;
+        else if (degrees == 180) return HAL_TRANSFORM_ROT_180;
+        else if (degrees == 270) return HAL_TRANSFORM_ROT_270;
+    } else {  // mirror (horizontal flip)
+        // Now overlay does ROT_90 before FLIP_V or FLIP_H. It should be FLIP_V
+        // or FLIP_H first.
+        // TODO: change this after overlay is fixed.
+        if (degrees == 0) {           // FLIP_H and ROT_0
+            return HAL_TRANSFORM_FLIP_H;
+        } else if (degrees == 90) {   // FLIP_H and ROT_90
+            return HAL_TRANSFORM_ROT_90 | HAL_TRANSFORM_FLIP_V;
+        } else if (degrees == 180) {  // FLIP_H and ROT_180
+            return HAL_TRANSFORM_FLIP_V;
+        } else if (degrees == 270) {  // FLIP_H and ROT_270
+            return HAL_TRANSFORM_ROT_90 | HAL_TRANSFORM_FLIP_H;
+        }
+    }
+    LOGE("Invalid setDisplayOrientation degrees=%d", degrees);
+    return -1;
+}
+
+
 // ----------------------------------------------------------------------------
 
 static const int kDumpLockRetries = 50;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8f0ed75..0dec2ab 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -108,6 +108,8 @@
                                        const sp<ICameraClient>& cameraClient,
                                        const sp<CameraHardwareInterface>& hardware,
                                        int cameraId,
+                                       int cameraFacing,
+                                       int mCameraOrientation,
                                        int clientPid);
                                 ~Client();
 
@@ -153,10 +155,14 @@
                                     const sp<IMemoryHeap>& heap,
                                     size_t offset, size_t size);
 
+        int                     getOrientation(int orientation, bool mirror);
+
         // these are initialized in the constructor.
         sp<CameraService>               mCameraService;  // immutable after constructor
         sp<ICameraClient>               mCameraClient;
         int                             mCameraId;       // immutable after constructor
+        int                             mCameraFacing;   // immutable after constructor
+        int                             mCameraOrientation;  // immutable after constructor
         pid_t                           mClientPid;
         sp<CameraHardwareInterface>     mHardware;       // cleared after disconnect()
         bool                            mUseOverlay;     // immutable after constructor
diff --git a/tests/DpiTest/AndroidManifest.xml b/tests/DpiTest/AndroidManifest.xml
index 68ecc6e..a4d8c79 100644
--- a/tests/DpiTest/AndroidManifest.xml
+++ b/tests/DpiTest/AndroidManifest.xml
@@ -18,6 +18,12 @@
     package="com.google.android.test.dpi">
     <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="3" />
     <supports-screens android:smallScreens="true" />
+    <compatible-screens>
+        <screen android:screenSize="small" android:screenDensity="ldpi" />
+        <screen android:screenSize="small" android:screenDensity="xhdpi" />
+        <screen android:screenSize="large" android:screenDensity="hdpi" />
+        <screen android:screenSize="xlarge" android:screenDensity="mdpi" />
+    </compatible-screens>
     <application android:label="DpiTest">
         <activity android:name="DpiTestActivity">
             <intent-filter>
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 873ebac..ad0465d 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -332,13 +332,15 @@
     REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
     TARGET_SDK_VERSION_ATTR = 0x01010270,
     TEST_ONLY_ATTR = 0x01010272,
-    DENSITY_ATTR = 0x0101026c,
+    ANY_DENSITY_ATTR = 0x0101026c,
     GL_ES_VERSION_ATTR = 0x01010281,
     SMALL_SCREEN_ATTR = 0x01010284,
     NORMAL_SCREEN_ATTR = 0x01010285,
     LARGE_SCREEN_ATTR = 0x01010286,
     XLARGE_SCREEN_ATTR = 0x010102bf,
     REQUIRED_ATTR = 0x0101028e,
+    SCREEN_SIZE_ATTR = 0x010102ca,
+    SCREEN_DENSITY_ATTR = 0x010102cb,
 };
 
 const char *getComponentName(String8 &pkgName, String8 &componentName) {
@@ -355,6 +357,42 @@
     return retStr.string();
 }
 
+static void printCompatibleScreens(ResXMLTree& tree) {
+    size_t len;
+    ResXMLTree::event_code_t code;
+    int depth = 0;
+    bool first = true;
+    printf("compatible-screens:");
+    while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+        if (code == ResXMLTree::END_TAG) {
+            depth--;
+            if (depth < 0) {
+                break;
+            }
+            continue;
+        }
+        if (code != ResXMLTree::START_TAG) {
+            continue;
+        }
+        depth++;
+        String8 tag(tree.getElementName(&len));
+        if (tag == "screen") {
+            int32_t screenSize = getIntegerAttribute(tree,
+                    SCREEN_SIZE_ATTR, NULL, -1);
+            int32_t screenDensity = getIntegerAttribute(tree,
+                    SCREEN_DENSITY_ATTR, NULL, -1);
+            if (screenSize > 0 && screenDensity > 0) {
+                if (!first) {
+                    printf(",");
+                }
+                first = false;
+                printf("'%d/%d'", screenSize, screenDensity);
+            }
+        }
+    }
+    printf("\n");
+}
+
 /*
  * Handle the "dump" command, to extract select data from an archive.
  */
@@ -572,6 +610,7 @@
             int normalScreen = 1;
             int largeScreen = 1;
             int xlargeScreen = 1;
+            int anyDensity = 1;
             String8 pkg;
             String8 activityName;
             String8 activityLabel;
@@ -739,14 +778,6 @@
                             printf(" reqFiveWayNav='%d'", reqFiveWayNav);
                         }
                         printf("\n");
-                    } else if (tag == "supports-density") {
-                        int32_t dens = getIntegerAttribute(tree, DENSITY_ATTR, &error);
-                        if (error != "") {
-                            fprintf(stderr, "ERROR getting 'android:density' attribute: %s\n",
-                                    error.string());
-                            goto bail;
-                        }
-                        printf("supports-density:'%d'\n", dens);
                     } else if (tag == "supports-screens") {
                         smallScreen = getIntegerAttribute(tree,
                                 SMALL_SCREEN_ATTR, NULL, 1);
@@ -756,6 +787,8 @@
                                 LARGE_SCREEN_ATTR, NULL, 1);
                         xlargeScreen = getIntegerAttribute(tree,
                                 XLARGE_SCREEN_ATTR, NULL, 1);
+                        anyDensity = getIntegerAttribute(tree,
+                                ANY_DENSITY_ATTR, NULL, 1);
                     } else if (tag == "uses-feature") {
                         String8 name = getAttribute(tree, NAME_ATTR, &error);
 
@@ -880,6 +913,9 @@
                                     error.string());
                                 goto bail;
                         }
+                    } else if (tag == "compatible-screens") {
+                        printCompatibleScreens(tree);
+                        depth--;
                     }
                 } else if (depth == 3 && withinApplication) {
                     withinActivity = false;
@@ -1106,6 +1142,9 @@
                 // Introduced in Honeycomb.
                 xlargeScreen = targetSdk >= 10 ? -1 : 0;
             }
+            if (anyDensity > 0) {
+                anyDensity = targetSdk >= 4 ? -1 : 0;
+            }
             printf("supports-screens:");
             if (smallScreen != 0) printf(" 'small'");
             if (normalScreen != 0) printf(" 'normal'");
@@ -1113,6 +1152,8 @@
             if (xlargeScreen != 0) printf(" 'xlarge'");
             printf("\n");
 
+            printf("supports-any-density: '%s'\n", anyDensity ? "true" : "false");
+
             printf("locales:");
             Vector<String8> locales;
             res.getLocales(&locales);
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 9da560a..0c8a725 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -768,7 +768,7 @@
     LOGD("latency: output %d, input %d", track.latency(), record.latency());
 
     // Initialize echo canceler.
-    EchoSuppressor echo(sampleRate, sampleCount, sampleCount * 2 +
+    EchoSuppressor echo(sampleCount,
         (track.latency() + record.latency()) * sampleRate / 1000);
 
     // Give device socket a reasonable buffer size.
diff --git a/voip/jni/rtp/EchoSuppressor.cpp b/voip/jni/rtp/EchoSuppressor.cpp
index ad63cd6..d5cff6e8 100644
--- a/voip/jni/rtp/EchoSuppressor.cpp
+++ b/voip/jni/rtp/EchoSuppressor.cpp
@@ -24,146 +24,163 @@
 
 #include "EchoSuppressor.h"
 
-EchoSuppressor::EchoSuppressor(int sampleRate, int sampleCount, int tailLength)
+// It is very difficult to do echo cancellation at this level due to the lack of
+// the timing information of the samples being played and recorded. Therefore,
+// for the first release only echo suppression is implemented.
+
+// The algorithm is derived from the "previous works" summarized in
+//   A new class of doubletalk detectors based on cross-correlation,
+//   J Benesty, DR Morgan, JH Cho, IEEE Trans. on Speech and Audio Processing.
+// The method proposed in that paper is not used because of its high complexity.
+
+// It is well known that cross-correlation can be computed using convolution,
+// but unfortunately not every mobile processor has a (fast enough) FPU. Thus
+// we use integer arithmetic as much as possible and do lots of bookkeeping.
+// Again, parameters and thresholds are chosen by experiments.
+
+EchoSuppressor::EchoSuppressor(int sampleCount, int tailLength)
 {
-    int scale = 1;
-    while (tailLength > 200 * scale) {
-        scale <<= 1;
-    }
-    if (scale > sampleCount) {
-        scale = sampleCount;
+    tailLength += sampleCount * 4;
+
+    int shift = 0;
+    while ((sampleCount >> shift) > 1 && (tailLength >> shift) > 256) {
+        ++shift;
     }
 
-    mScale = scale;
+    mShift = shift + 4;
+    mScale = 1 << shift;
     mSampleCount = sampleCount;
-    mWindowSize = sampleCount / scale;
-    mTailLength = (tailLength + scale - 1) / scale;
-    mRecordLength = (sampleRate + sampleCount - 1) / sampleCount;
+    mWindowSize = sampleCount >> shift;
+    mTailLength = tailLength >> shift;
+    mRecordLength = tailLength * 2 / sampleCount;
     mRecordOffset = 0;
 
-    mXs = new float[mTailLength + mWindowSize];
-    memset(mXs, 0, sizeof(float) * (mTailLength + mWindowSize));
-    mXYs = new float[mTailLength];
-    memset(mXYs, 0, sizeof(float) * mTailLength);
-    mXXs = new float[mTailLength];
-    memset(mXYs, 0, sizeof(float) * mTailLength);
-    mYY = 0;
+    mXs = new uint16_t[mTailLength + mWindowSize];
+    memset(mXs, 0, sizeof(*mXs) * (mTailLength + mWindowSize));
+    mXSums = new uint32_t[mTailLength];
+    memset(mXSums, 0, sizeof(*mXSums) * mTailLength);
+    mX2Sums = new uint32_t[mTailLength];
+    memset(mX2Sums, 0, sizeof(*mX2Sums) * mTailLength);
+    mXRecords = new uint16_t[mRecordLength * mWindowSize];
+    memset(mXRecords, 0, sizeof(*mXRecords) * mRecordLength * mWindowSize);
 
-    mXYRecords = new float[mRecordLength * mTailLength];
-    memset(mXYRecords, 0, sizeof(float) * mRecordLength * mTailLength);
-    mXXRecords = new float[mRecordLength * mWindowSize];
-    memset(mXXRecords, 0, sizeof(float) * mRecordLength * mWindowSize);
-    mYYRecords = new float[mRecordLength];
-    memset(mYYRecords, 0, sizeof(float) * mRecordLength);
+    mYSum = 0;
+    mY2Sum = 0;
+    mYRecords = new uint32_t[mRecordLength];
+    memset(mYRecords, 0, sizeof(*mYRecords) * mRecordLength);
+    mY2Records = new uint32_t[mRecordLength];
+    memset(mY2Records, 0, sizeof(*mY2Records) * mRecordLength);
+
+    mXYSums = new uint32_t[mTailLength];
+    memset(mXYSums, 0, sizeof(*mXYSums) * mTailLength);
+    mXYRecords = new uint32_t[mRecordLength * mTailLength];
+    memset(mXYRecords, 0, sizeof(*mXYRecords) * mRecordLength * mTailLength);
 
     mLastX = 0;
     mLastY = 0;
+    mWeight = 1.0f / (mRecordLength * mWindowSize);
 }
 
 EchoSuppressor::~EchoSuppressor()
 {
     delete [] mXs;
-    delete [] mXYs;
-    delete [] mXXs;
+    delete [] mXSums;
+    delete [] mX2Sums;
+    delete [] mXRecords;
+    delete [] mYRecords;
+    delete [] mY2Records;
+    delete [] mXYSums;
     delete [] mXYRecords;
-    delete [] mXXRecords;
-    delete [] mYYRecords;
 }
 
 void EchoSuppressor::run(int16_t *playbacked, int16_t *recorded)
 {
-    float *records;
-
     // Update Xs.
-    for (int i = 0; i < mTailLength; ++i) {
-        mXs[i] = mXs[mWindowSize + i];
+    for (int i = mTailLength - 1; i >= 0; --i) {
+        mXs[i + mWindowSize] = mXs[i];
     }
-    for (int i = 0, j = 0; i < mWindowSize; ++i, j += mScale) {
-        float sum = 0;
+    for (int i = mWindowSize - 1, j = 0; i >= 0; --i, j += mScale) {
+        uint32_t sum = 0;
         for (int k = 0; k < mScale; ++k) {
-            float x = playbacked[j + k] >> 8;
+            int32_t x = playbacked[j + k] << 15;
             mLastX += x;
-            sum += (mLastX >= 0) ? mLastX : -mLastX;
-            mLastX = 0.005f * mLastX - x;
+            sum += ((mLastX >= 0) ? mLastX : -mLastX) >> 15;
+            mLastX -= (mLastX >> 10) + x;
         }
-        mXs[mTailLength - 1 + i] = sum;
+        mXs[i] = sum >> mShift;
     }
 
-    // Update XXs and XXRecords.
-    for (int i = 0; i < mTailLength - mWindowSize; ++i) {
-        mXXs[i] = mXXs[mWindowSize + i];
+    // Update XSums, X2Sums, and XRecords.
+    for (int i = mTailLength - mWindowSize - 1; i >= 0; --i) {
+        mXSums[i + mWindowSize] = mXSums[i];
+        mX2Sums[i + mWindowSize] = mX2Sums[i];
     }
-    records = &mXXRecords[mRecordOffset * mWindowSize];
-    for (int i = 0, j = mTailLength - mWindowSize; i < mWindowSize; ++i, ++j) {
-        float xx = mXs[mTailLength - 1 + i] * mXs[mTailLength - 1 + i];
-        mXXs[j] = mXXs[j - 1] + xx - records[i];
-        records[i] = xx;
-        if (mXXs[j] < 0) {
-            mXXs[j] = 0;
-        }
+    uint16_t *xRecords = &mXRecords[mRecordOffset * mWindowSize];
+    for (int i = mWindowSize - 1; i >= 0; --i) {
+        uint16_t x = mXs[i];
+        mXSums[i] = mXSums[i + 1] + x - xRecords[i];
+        mX2Sums[i] = mX2Sums[i + 1] + x * x - xRecords[i] * xRecords[i];
+        xRecords[i] = x;
     }
 
     // Compute Ys.
-    float ys[mWindowSize];
-    for (int i = 0, j = 0; i < mWindowSize; ++i, j += mScale) {
-        float sum = 0;
+    uint16_t ys[mWindowSize];
+    for (int i = mWindowSize - 1, j = 0; i >= 0; --i, j += mScale) {
+        uint32_t sum = 0;
         for (int k = 0; k < mScale; ++k) {
-            float y = recorded[j + k] >> 8;
+            int32_t y = recorded[j + k] << 15;
             mLastY += y;
-            sum += (mLastY >= 0) ? mLastY : -mLastY;
-            mLastY = 0.005f * mLastY - y;
+            sum += ((mLastY >= 0) ? mLastY : -mLastY) >> 15;
+            mLastY -= (mLastY >> 10) + y;
         }
-        ys[i] = sum;
+        ys[i] = sum >> mShift;
     }
 
-    // Update YY and YYRecords.
-    float yy = 0;
-    for (int i = 0; i < mWindowSize; ++i) {
-        yy += ys[i] * ys[i];
+    // Update YSum, Y2Sum, YRecords, and Y2Records.
+    uint32_t ySum = 0;
+    uint32_t y2Sum = 0;
+    for (int i = mWindowSize - 1; i >= 0; --i) {
+        ySum += ys[i];
+        y2Sum += ys[i] * ys[i];
     }
-    mYY += yy - mYYRecords[mRecordOffset];
-    mYYRecords[mRecordOffset] = yy;
-    if (mYY < 0) {
-        mYY = 0;
+    mYSum += ySum - mYRecords[mRecordOffset];
+    mY2Sum += y2Sum - mY2Records[mRecordOffset];
+    mYRecords[mRecordOffset] = ySum;
+    mY2Records[mRecordOffset] = y2Sum;
+
+    // Update XYSums and XYRecords.
+    uint32_t *xyRecords = &mXYRecords[mRecordOffset * mTailLength];
+    for (int i = mTailLength - 1; i >= 0; --i) {
+        uint32_t xySum = 0;
+        for (int j = mWindowSize - 1; j >= 0; --j) {
+            xySum += mXs[i + j] * ys[j];
+        }
+        mXYSums[i] += xySum - xyRecords[i];
+        xyRecords[i] = xySum;
     }
 
-    // Update XYs and XYRecords.
-    records = &mXYRecords[mRecordOffset * mTailLength];
-    for (int i = 0; i < mTailLength; ++i) {
-        float xy = 0;
-        for (int j = 0;j < mWindowSize; ++j) {
-            xy += mXs[i + j] * ys[j];
-        }
-        mXYs[i] += xy - records[i];
-        records[i] = xy;
-        if (mXYs[i] < 0) {
-            mXYs[i] = 0;
-        }
-    }
-
-    // Computes correlations from XYs, XXs, and YY.
-    float weight = 1.0f / (mYY + 1);
-    float correlation = 0;
+    // Compute correlations.
+    float corr2 = 0.0f;
     int latency = 0;
-    for (int i = 0; i < mTailLength; ++i) {
-        float c = mXYs[i] * mXYs[i] * weight / (mXXs[i] + 1);
-        if (c > correlation) {
-            correlation = c;
+    float varY = mY2Sum - mWeight * mYSum * mYSum;
+    for (int i = mTailLength - 1; i >= 0; --i) {
+        float varX = mX2Sums[i] - mWeight * mXSums[i] * mXSums[i];
+        float cov = mXYSums[i] - mWeight * mXSums[i] * mYSum;
+        float c2 = cov * cov / (varX * varY + 1);
+        if (c2 > corr2) {
+            corr2 = c2;
             latency = i;
         }
     }
+    //LOGI("correlation^2 = %.10f, latency = %d", corr2, latency * mScale);
 
-    correlation = sqrtf(correlation);
-    if (correlation > 0.3f) {
-        float factor = 1.0f - correlation;
-        factor *= factor;
-        factor /= 2.0; // suppress harder
+    // Do echo suppression.
+    if (corr2 > 0.1f) {
+        int factor = (corr2 > 1.0f) ? 0 : (1.0f - sqrtf(corr2)) * 4096;
         for (int i = 0; i < mSampleCount; ++i) {
-            recorded[i] *= factor;
+            recorded[i] = recorded[i] * factor >> 16;
         }
     }
-    //LOGI("latency %5d, correlation %.10f", latency, correlation);
-
 
     // Increase RecordOffset.
     ++mRecordOffset;
diff --git a/voip/jni/rtp/EchoSuppressor.h b/voip/jni/rtp/EchoSuppressor.h
index 85decf5..2f3b593 100644
--- a/voip/jni/rtp/EchoSuppressor.h
+++ b/voip/jni/rtp/EchoSuppressor.h
@@ -23,11 +23,12 @@
 {
 public:
     // The sampleCount must be power of 2.
-    EchoSuppressor(int sampleRate, int sampleCount, int tailLength);
+    EchoSuppressor(int sampleCount, int tailLength);
     ~EchoSuppressor();
     void run(int16_t *playbacked, int16_t *recorded);
 
 private:
+    int mShift;
     int mScale;
     int mSampleCount;
     int mWindowSize;
@@ -35,17 +36,23 @@
     int mRecordLength;
     int mRecordOffset;
 
-    float *mXs;
-    float *mXYs;
-    float *mXXs;
-    float mYY;
+    uint16_t *mXs;
+    uint32_t *mXSums;
+    uint32_t *mX2Sums;
+    uint16_t *mXRecords;
 
-    float *mXYRecords;
-    float *mXXRecords;
-    float *mYYRecords;
+    uint32_t mYSum;
+    uint32_t mY2Sum;
+    uint32_t *mYRecords;
+    uint32_t *mY2Records;
 
-    float mLastX;
-    float mLastY;
+    uint32_t *mXYSums;
+    uint32_t *mXYRecords;
+
+    int32_t mLastX;
+    int32_t mLastY;
+
+    float mWeight;
 };
 
 #endif