Fix the wrong rotation on naturally landscape devices.

The orientation of on-screen icons and thumbnails are
wrong on devices that are naturally landscape in their
orientation. Display.getRotation should be used to
compensate.

Parameters.setRotation should also be compensated by
camera's orientation.

Change-Id: Ia0684fcd606252c49fa2d701ab07c73f7e29b70b
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index 26b14f9..1c5ebed 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.hardware.Camera.CameraInfo;
 import android.hardware.Camera.Parameters;
 import android.hardware.Camera.PictureCallback;
 import android.hardware.Camera.Size;
@@ -133,8 +134,11 @@
     private Parameters mParameters;
     private Parameters mInitialParams;
 
-    private OrientationEventListener mOrientationListener;
-    private int mLastOrientation = 0;  // No rotation (landscape) by default.
+    private MyOrientationEventListener mOrientationListener;
+    // The device orientation in degrees. Default is unknown.
+    private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
+    // The orientation compensation for icons and thumbnails.
+    private int mOrientationCompensation = 0;
     private ComboPreferences mPreferences;
 
     private static final int IDLE = 1;
@@ -302,24 +306,7 @@
 
         // Create orientation listenter. This should be done first because it
         // takes some time to get first orientation.
-        mOrientationListener = new OrientationEventListener(Camera.this) {
-            @Override
-            public void onOrientationChanged(int orientation) {
-                // We keep the last known orientation. So if the user
-                // first orient the camera then point the camera to
-                if (orientation != ORIENTATION_UNKNOWN) {
-                    orientation += 90;
-                }
-                orientation = ImageManager.roundOrientation(orientation);
-                if (orientation != mLastOrientation) {
-                    mLastOrientation = orientation;
-                    if (!mIsImageCaptureIntent)  {
-                        setOrientationIndicator(mLastOrientation);
-                    }
-                    mHeadUpDisplay.setOrientation(mLastOrientation);
-                }
-            }
-        };
+        mOrientationListener = new MyOrientationEventListener(Camera.this);
         mOrientationListener.enable();
 
         // Initialize location sevice.
@@ -789,8 +776,18 @@
         private void capture() {
             mCaptureOnlyData = null;
 
-            // Set rotation.
-            mParameters.setRotation(mLastOrientation);
+            // Set JPEG rotation to match the orientation of what users see. The
+            // rotation is relative to the orientation of the camera. The value
+            // from OrientationEventListener is relative to the natural
+            // orientation of the device. CameraInfo.mOrientation is the angle
+            // between camera orientation and natural device orientation. The
+            // sum of the two is the value for setRotation.
+            int rotation = 0;
+            if (mOrientation != OrientationEventListener.ORIENTATION_UNKNOWN) {
+                CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
+                rotation = (mOrientation + info.mOrientation) % 360;
+            }
+            mParameters.setRotation(rotation);
 
             // Clear previous GPS location from the parameters.
             mParameters.removeGpsData();
@@ -1000,7 +997,7 @@
                 CameraHolder.instance().getCameraInfo());
         mHeadUpDisplay.initialize(this,
                 settings.getPreferenceGroup(R.xml.camera_preferences),
-                getZoomRatios(), mLastOrientation);
+                getZoomRatios(), mOrientationCompensation);
         if (mParameters.isZoomSupported()) {
             mHeadUpDisplay.setZoomIndex(mZoomValue);
             mHeadUpDisplay.setZoomListener(new ZoomControllerListener() {
@@ -1016,7 +1013,7 @@
     }
 
     private void attachHeadUpDisplay() {
-        mHeadUpDisplay.setOrientation(mLastOrientation);
+        mHeadUpDisplay.setOrientation(mOrientationCompensation);
         FrameLayout frame = (FrameLayout) findViewById(R.id.frame);
         mGLRootView = new GLRootView(this);
         mGLRootView.setContentPane(mHeadUpDisplay);
@@ -1030,6 +1027,36 @@
         mGLRootView = null;
     }
 
+    public static int roundOrientation(int orientation) {
+        return ((orientation + 45) / 90 * 90) % 360;
+    }
+
+    private class MyOrientationEventListener
+            extends OrientationEventListener {
+        public MyOrientationEventListener(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onOrientationChanged(int orientation) {
+            // We keep the last known orientation. So if the user first orient
+            // the camera then point the camera to floor or sky, we still have
+            // the correct orientation.
+            if (orientation == ORIENTATION_UNKNOWN) return;
+            orientation = roundOrientation(orientation);
+            if (orientation != mOrientation) {
+                mOrientation = orientation;
+                mOrientationCompensation = orientation
+                        + Util.getDisplayRotation(Camera.this);
+
+                if (!mIsImageCaptureIntent) {
+                    setOrientationIndicator(mOrientationCompensation);
+                }
+                mHeadUpDisplay.setOrientation(mOrientationCompensation);
+            }
+        }
+    }
+
     private void setOrientationIndicator(int degree) {
         ((RotateImageView) findViewById(
                 R.id.review_thumbnail)).setDegree(degree);
diff --git a/src/com/android/camera/ImageManager.java b/src/com/android/camera/ImageManager.java
index 7251af8..76a6d1d 100644
--- a/src/com/android/camera/ImageManager.java
+++ b/src/com/android/camera/ImageManager.java
@@ -155,30 +155,6 @@
         }
     }
 
-    public static int roundOrientation(int orientationInput) {
-        int orientation = orientationInput;
-
-        if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
-            orientation = 0;
-        }
-
-        orientation = orientation % 360;
-        int retVal;
-        if (orientation < (0 * 90) + 45) {
-            retVal = 0;
-        } else if (orientation < (1 * 90) + 45) {
-            retVal = 90;
-        } else if (orientation < (2 * 90) + 45) {
-            retVal = 180;
-        } else if (orientation < (3 * 90) + 45) {
-            retVal = 270;
-        } else {
-            retVal = 0;
-        }
-
-        return retVal;
-    }
-
     //
     // Stores a bitmap or a jpeg byte array to a file (using the specified
     // directory and filename). Also add an entry to the media store for
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index de99562..c5de1f8 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -280,21 +280,24 @@
         return x;
     }
 
+    public static int getDisplayRotation(Activity activity) {
+        int rotation = activity.getWindowManager().getDefaultDisplay()
+                .getRotation();
+        switch (rotation) {
+            case Surface.ROTATION_0: return 0;
+            case Surface.ROTATION_90: return 90;
+            case Surface.ROTATION_180: return 180;
+            case Surface.ROTATION_270: return 270;
+        }
+        return 0;
+    }
+
     public static void setCameraDisplayOrientation(Activity activity,
             int cameraId, android.hardware.Camera camera) {
         android.hardware.Camera.CameraInfo info =
                 new android.hardware.Camera.CameraInfo();
         android.hardware.Camera.getCameraInfo(cameraId, info);
-        int rotation = activity.getWindowManager().getDefaultDisplay()
-                .getRotation();
-        int degrees = 0;
-        switch (rotation) {
-            case Surface.ROTATION_0: degrees = 0; break;
-            case Surface.ROTATION_90: degrees = 90; break;
-            case Surface.ROTATION_180: degrees = 180; break;
-            case Surface.ROTATION_270: degrees = 270; break;
-        }
-
+        int degrees = getDisplayRotation(activity);
         int result = (info.mOrientation - degrees + 360) % 360;
         camera.setDisplayOrientation(result);
     }
diff --git a/tests/src/com/android/camera/UnitTests.java b/tests/src/com/android/camera/UnitTests.java
index aeed001..4fc0e7d 100644
--- a/tests/src/com/android/camera/UnitTests.java
+++ b/tests/src/com/android/camera/UnitTests.java
@@ -28,8 +28,8 @@
 
     public static Test suite() {
         return new UnitTestSuiteBuilder(UnitTests.class)
-                .includeAllPackagesUnderHere()
-                .excludePackages("com.android.camera.stress")
+                .includePackages("com.android.camera.unittest",
+                                 "com.android.camera.gallery")
                 .named("Camera Unit Tests")
                 .build();
     }
diff --git a/tests/src/com/android/camera/unittest/CameraTest.java b/tests/src/com/android/camera/unittest/CameraTest.java
new file mode 100644
index 0000000..0e851e4
--- /dev/null
+++ b/tests/src/com/android/camera/unittest/CameraTest.java
@@ -0,0 +1,26 @@
+package com.android.camera.unittest;
+
+import com.android.camera.Camera;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+@SmallTest
+public class CameraTest extends TestCase {
+    public void testRoundOrientation() {
+        assertEquals(0, Camera.roundOrientation(0));
+        assertEquals(0, Camera.roundOrientation(0 + 44));
+        assertEquals(90, Camera.roundOrientation(0 + 45));
+        assertEquals(90, Camera.roundOrientation(90));
+        assertEquals(90, Camera.roundOrientation(90 + 44));
+        assertEquals(180, Camera.roundOrientation(90 + 45));
+        assertEquals(180, Camera.roundOrientation(180));
+        assertEquals(180, Camera.roundOrientation(180 + 44));
+        assertEquals(270, Camera.roundOrientation(180 + 45));
+        assertEquals(270, Camera.roundOrientation(270));
+        assertEquals(270, Camera.roundOrientation(270 + 44));
+        assertEquals(0, Camera.roundOrientation(270 + 45));
+        assertEquals(0, Camera.roundOrientation(359));
+    }
+}