am 89230e3b: am 458fc5f5: Merge "Fix issue #3041660: Camera image flips upside down when rotating device" into gingerbread

Merge commit '89230e3b7b9ec455373e3f60b62ff65589a9c57d'

* commit '89230e3b7b9ec455373e3f60b62ff65589a9c57d':
  Fix issue #3041660: Camera image flips upside down when rotating device
diff --git a/api/current.xml b/api/current.xml
index c6fc34e..07724ab 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -55076,6 +55076,17 @@
  visibility="public"
 >
 </field>
+<field name="SCREEN_ORIENTATION_FULL_SENSOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SCREEN_ORIENTATION_LANDSCAPE"
  type="int"
  transient="false"
@@ -55109,6 +55120,28 @@
  visibility="public"
 >
 </field>
+<field name="SCREEN_ORIENTATION_REVERSE_LANDSCAPE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCREEN_ORIENTATION_REVERSE_PORTRAIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SCREEN_ORIENTATION_SENSOR"
  type="int"
  transient="false"
@@ -55120,6 +55153,28 @@
  visibility="public"
 >
 </field>
+<field name="SCREEN_ORIENTATION_SENSOR_LANDSCAPE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCREEN_ORIENTATION_SENSOR_PORTRAIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SCREEN_ORIENTATION_UNSPECIFIED"
  type="int"
  transient="false"
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e21cb97..e688c86 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -216,10 +216,41 @@
     public static final int SCREEN_ORIENTATION_SENSOR = 4;
   
     /**
-     * Constant corresponding to <code>sensor</code> in
+     * Constant corresponding to <code>nosensor</code> in
      * the {@link android.R.attr#screenOrientation} attribute.
      */
     public static final int SCREEN_ORIENTATION_NOSENSOR = 5;
+
+    /**
+     * Constant corresponding to <code>sensorLandscape</code> in
+     * the {@link android.R.attr#screenOrientation} attribute.
+     */
+    public static final int SCREEN_ORIENTATION_SENSOR_LANDSCAPE = 6;
+
+    /**
+     * Constant corresponding to <code>sensorPortrait</code> in
+     * the {@link android.R.attr#screenOrientation} attribute.
+     */
+    public static final int SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7;
+
+    /**
+     * Constant corresponding to <code>reverseLandscape</code> in
+     * the {@link android.R.attr#screenOrientation} attribute.
+     */
+    public static final int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8;
+
+    /**
+     * Constant corresponding to <code>reversePortrait</code> in
+     * the {@link android.R.attr#screenOrientation} attribute.
+     */
+    public static final int SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9;
+
+    /**
+     * Constant corresponding to <code>fullSensor</code> in
+     * the {@link android.R.attr#screenOrientation} attribute.
+     */
+    public static final int SCREEN_ORIENTATION_FULL_SENSOR = 10;
+
     /**
      * The preferred screen orientation this activity would like to run in.
      * From the {@link android.R.attr#screenOrientation} attribute, one of
@@ -229,7 +260,12 @@
      * {@link #SCREEN_ORIENTATION_USER},
      * {@link #SCREEN_ORIENTATION_BEHIND},
      * {@link #SCREEN_ORIENTATION_SENSOR},
-     * {@link #SCREEN_ORIENTATION_NOSENSOR}.
+     * {@link #SCREEN_ORIENTATION_NOSENSOR},
+     * {@link #SCREEN_ORIENTATION_SENSOR_LANDSCAPE},
+     * {@link #SCREEN_ORIENTATION_SENSOR_PORTRAIT},
+     * {@link #SCREEN_ORIENTATION_REVERSE_LANDSCAPE},
+     * {@link #SCREEN_ORIENTATION_REVERSE_PORTRAIT},
+     * {@link #SCREEN_ORIENTATION_FULL_SENSOR}.
      */
     public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
     
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 8ffa158..3e2e92b 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -28,6 +28,11 @@
  * A special helper class used by the WindowManager
  *  for receiving notifications from the SensorManager when
  * the orientation of the device has changed.
+ *
+ * NOTE: If changing anything here, please run the API demo
+ * "App/Activity/Screen Orientation" to ensure that all orientation
+ * modes still work correctly.
+ *
  * @hide
  */
 public abstract class WindowOrientationListener {
@@ -103,6 +108,10 @@
         }
     }
 
+    public void setAllow180Rotation(boolean allowed) {
+        mSensorEventListener.setAllow180Rotation(allowed);
+    }
+
     public int getCurrentRotation(int lastRotation) {
         if (mEnabled) {
             return mSensorEventListener.getCurrentRotation(lastRotation);
@@ -151,19 +160,20 @@
         private static final int ROTATION_0 = 0;
         private static final int ROTATION_90 = 1;
         private static final int ROTATION_270 = 2;
+        private static final int ROTATION_180 = 3;
 
         // Mapping our internal aliases into actual Surface rotation values
         private static final int[] INTERNAL_TO_SURFACE_ROTATION = new int[] {
-            Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_270};
+            Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_270,
+            Surface.ROTATION_180};
 
         // Mapping Surface rotation values to internal aliases.
-        // We have no constant for Surface.ROTATION_180.  That should never happen, but if it
-        // does, we'll arbitrarily choose a mapping.
         private static final int[] SURFACE_TO_INTERNAL_ROTATION = new int[] {
-            ROTATION_0, ROTATION_90, ROTATION_90, ROTATION_270};
+            ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270};
 
         // Threshold ranges of orientation angle to transition into other orientation states.
-        // The first list is for transitions from ROTATION_0, the next for ROTATION_90, etc.
+        // The first list is for transitions from ROTATION_0, ROTATION_90, ROTATION_270,
+        // and then ROTATION_180.
         // ROTATE_TO defines the orientation each threshold range transitions to, and must be kept
         // in sync with this.
         // We generally transition about the halfway point between two states with a swing of 30
@@ -172,13 +182,32 @@
                 {{60, 180}, {180, 300}},
                 {{0, 30}, {195, 315}, {315, 360}},
                 {{0, 45}, {45, 165}, {330, 360}},
-        };
 
+                // Handle situation where we are currently doing 180 rotation
+                // but that is no longer allowed.
+                {{0, 45}, {45, 135}, {135, 225}, {225, 315}, {315, 360}},
+        };
         // See THRESHOLDS
         private static final int[][] ROTATE_TO = new int[][] {
                 {ROTATION_90, ROTATION_270},
                 {ROTATION_0, ROTATION_270, ROTATION_0},
                 {ROTATION_0, ROTATION_90, ROTATION_0},
+                {ROTATION_0, ROTATION_90, ROTATION_0, ROTATION_270, ROTATION_0},
+        };
+
+        // Thresholds that allow all 4 orientations.
+        private static final int[][][] THRESHOLDS_WITH_180 = new int[][][] {
+            {{60, 165}, {165, 195}, {195, 300}},
+            {{0, 30}, {165, 195}, {195, 315}, {315, 360}},
+            {{0, 45}, {45, 165}, {165, 195}, {330, 360}},
+            {{0, 45}, {45, 135}, {225, 315}, {315, 360}},
+        };
+        // See THRESHOLDS_WITH_180
+        private static final int[][] ROTATE_TO_WITH_180 = new int[][] {
+            {ROTATION_90, ROTATION_180, ROTATION_270},
+            {ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0},
+            {ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0},
+            {ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_0},
         };
 
         // Maximum absolute tilt angle at which to consider orientation data.  Beyond this (i.e.
@@ -188,7 +217,7 @@
         // Additional limits on tilt angle to transition to each new orientation.  We ignore all
         // data with tilt beyond MAX_TILT, but we can set stricter limits on transitions to a
         // particular orientation here.
-        private static final int[] MAX_TRANSITION_TILT = new int[] {MAX_TILT, 65, 65};
+        private static final int[] MAX_TRANSITION_TILT = new int[] {MAX_TILT, 65, 65, 40};
 
         // Between this tilt angle and MAX_TILT, we'll allow orientation changes, but we'll filter
         // with a higher time constant, making us less sensitive to change.  This primarily helps
@@ -228,6 +257,8 @@
         private static final float ACCELERATING_LOWPASS_ALPHA =
             computeLowpassAlpha(ACCELERATING_TIME_CONSTANT_MS);
 
+        private boolean mAllow180Rotation = false;
+
         private WindowOrientationListener mOrientationListener;
         private int mRotation = ROTATION_0; // Current orientation state
         private float mTiltAngle = 0; // low-pass filtered
@@ -249,6 +280,10 @@
             return (float) SAMPLING_PERIOD_MS / (timeConstantMs + SAMPLING_PERIOD_MS);
         }
 
+        void setAllow180Rotation(boolean allowed) {
+            mAllow180Rotation = allowed;
+        }
+
         int getCurrentRotation(int lastRotation) {
             if (mTiltDistrust > 0) {
                 // we really don't know the current orientation, so trust what's currently displayed
@@ -259,7 +294,9 @@
 
         private void calculateNewRotation(float orientation, float tiltAngle) {
             if (localLOGV) Log.i(TAG, orientation + ", " + tiltAngle + ", " + mRotation);
-            int thresholdRanges[][] = THRESHOLDS[mRotation];
+            final boolean allow180Rotation = mAllow180Rotation;
+            int thresholdRanges[][] = allow180Rotation
+                    ? THRESHOLDS_WITH_180[mRotation] : THRESHOLDS[mRotation];
             int row = -1;
             for (int i = 0; i < thresholdRanges.length; i++) {
                 if (orientation >= thresholdRanges[i][0] && orientation < thresholdRanges[i][1]) {
@@ -269,13 +306,15 @@
             }
             if (row == -1) return; // no matching transition
 
-            int rotation = ROTATE_TO[mRotation][row];
+            int rotation = allow180Rotation
+                    ? ROTATE_TO_WITH_180[mRotation][row] : ROTATE_TO[mRotation][row];
             if (tiltAngle > MAX_TRANSITION_TILT[rotation]) {
                 // tilted too far flat to go to this rotation
                 return;
             }
 
-            if (localLOGV) Log.i(TAG, " new rotation = " + rotation);
+            if (localLOGV) Log.i(TAG, "orientation " + orientation + " gives new rotation = "
+                    + rotation);
             mRotation = rotation;
             mOrientationListener.onOrientationChanged(INTERNAL_TO_SURFACE_ROTATION[mRotation]);
         }
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 8cf65ae..949d960 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -497,10 +497,10 @@
              orientation will changed based on how the user rotates the device -->
         <enum name="unspecified" value="-1" />
         <!-- Would like to have the screen in a landscape orientation: that
-             is, with the display wider than it is tall. -->
+             is, with the display wider than it is tall, ignoring sensor data. -->
         <enum name="landscape" value="0" />
         <!-- Would like to have the screen in a portrait orientation: that
-             is, with the display taller than it is wide. -->
+             is, with the display taller than it is wide, ignoring sensor data. -->
         <enum name="portrait" value="1" />
         <!-- Use the user's current preferred orientation of the handset. -->
         <enum name="user" value="2" />
@@ -513,6 +513,24 @@
         <!-- Always ignore orientation determined by orientation sensor:
              the display will not rotate when the user moves the device. -->
         <enum name="nosensor" value="5" />
+        <!-- Would like to have the screen in landscape orientation, but can
+             use the sensor to change which direction the screen is facing. -->
+        <enum name="sensorLandscape" value="6" />
+        <!-- Would like to have the screen in portrait orientation, but can
+             use the sensor to change which direction the screen is facing. -->
+        <enum name="sensorPortait" value="7" />
+        <!-- Would like to have the screen in landscape orientation, turned in
+             the opposite direction from normal landscape. -->
+        <enum name="reverseLandscape" value="8" />
+        <!-- Would like to have the screen in portrait orientation, turned in
+             the opposite direction from normal portrait. -->
+        <enum name="reversePortait" value="9" />
+        <!-- Orientation is determined by a physical orientation sensor:
+             the display will rotate based on how the user moves the device.
+             This allows any of the 4 possible rotations, regardless of what
+             the device will normally do (for example some devices won't
+             normally use 180 degree rotation). -->
+        <enum name="fullSensor" value="10" />
     </attr>
     
     <!-- Specify one or more configuration changes that the activity will
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index c70f5d4..33685ba 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -296,7 +296,8 @@
 
     int mLandscapeRotation = -1; // default landscape rotation
     int mSeascapeRotation = -1; // "other" landscape rotation, 180 degrees from mLandscapeRotation
-    int mPortraitRotation = -1;
+    int mPortraitRotation = -1; // default portrait rotation
+    int mUpsideDownRotation = -1; // "other" portrait rotation
 
     // Nothing to see here, move along...
     int mFancyRotationAnimation;
@@ -364,26 +365,25 @@
 
     boolean useSensorForOrientationLp(int appOrientation) {
         // The app says use the sensor.
-        if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
+        if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
+                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
+                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
             return true;
         }
         // The user preference says we can rotate, and the app is willing to rotate.
-        // Note we include SCREEN_ORIENTATION_LANDSCAPE since we can use the sensor to choose
-        // between the two possible landscape rotations.
         if (mAccelerometerDefault != 0 &&
                 (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
-                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
-                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)) {
+                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
             return true;
         }
-        // We're in a dock that has a rotation affinity, an the app is willing to rotate.
+        // We're in a dock that has a rotation affinity, and the app is willing to rotate.
         if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR)
                 || (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) {
             // Note we override the nosensor flag here.
             if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
                     || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
-                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
-                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
+                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
                 return true;
             }
         }
@@ -397,7 +397,10 @@
      * screen is switched off.
      */
     boolean needSensorRunningLp() {
-        if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
+        if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
+                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
+                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
             // If the application has explicitly requested to follow the
             // orientation, then we need to turn the sensor or.
             return true;
@@ -2133,21 +2136,42 @@
             if (d.getWidth() > d.getHeight()) {
                 mPortraitRotation = Surface.ROTATION_90;
                 mLandscapeRotation = Surface.ROTATION_0;
+                mUpsideDownRotation = Surface.ROTATION_270;
                 mSeascapeRotation = Surface.ROTATION_180;
             } else {
                 mPortraitRotation = Surface.ROTATION_0;
                 mLandscapeRotation = Surface.ROTATION_90;
+                mUpsideDownRotation = Surface.ROTATION_180;
                 mSeascapeRotation = Surface.ROTATION_270;
             }
         }
 
         synchronized (mLock) {
-            if (orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
-                //always return portrait if orientation set to portrait
-                return mPortraitRotation;
-            } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
-                return getCurrentLandscapeRotation(lastRotation);
+            switch (orientation) {
+                case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
+                    //always return portrait if orientation set to portrait
+                    return mPortraitRotation;
+                case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
+                    //always return landscape if orientation set to landscape
+                    return mLandscapeRotation;
+                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+                    //always return portrait if orientation set to portrait
+                    return mUpsideDownRotation;
+                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+                    //always return seascape if orientation set to reverse landscape
+                    return mSeascapeRotation;
+                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+                    //return either landscape rotation based on the sensor
+                    mOrientationListener.setAllow180Rotation(false);
+                    return getCurrentLandscapeRotation(lastRotation);
+                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+                    mOrientationListener.setAllow180Rotation(true);
+                    return getCurrentPortraitRotation(lastRotation);
             }
+
+            mOrientationListener.setAllow180Rotation(
+                    orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
+
             // case for nosensor meaning ignore sensor and consider only lid
             // or orientation sensor disabled
             //or case.unspecified
@@ -2167,18 +2191,15 @@
     }
 
     private int getCurrentLandscapeRotation(int lastRotation) {
-        // landscape-only apps can take either landscape rotation
-        if (useSensorForOrientationLp(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)) {
-            int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
-            if (isLandscapeOrSeascape(sensorRotation)) {
-                return sensorRotation;
-            }
+        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
+        if (isLandscapeOrSeascape(sensorRotation)) {
+            return sensorRotation;
         }
         // try to preserve the old rotation if it was landscape
         if (isLandscapeOrSeascape(lastRotation)) {
             return lastRotation;
         }
-        // default to one of the two landscape rotations
+        // default to one of the primary landscape rotation
         return mLandscapeRotation;
     }
 
@@ -2186,6 +2207,23 @@
         return sensorRotation == mLandscapeRotation || sensorRotation == mSeascapeRotation;
     }
 
+    private int getCurrentPortraitRotation(int lastRotation) {
+        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
+        if (isAnyPortrait(sensorRotation)) {
+            return sensorRotation;
+        }
+        // try to preserve the old rotation if it was portrait
+        if (isAnyPortrait(lastRotation)) {
+            return lastRotation;
+        }
+        // default to one of the primary portrait rotations
+        return mPortraitRotation;
+    }
+
+    private boolean isAnyPortrait(int sensorRotation) {
+        return sensorRotation == mPortraitRotation || sensorRotation == mUpsideDownRotation;
+    }
+
     public boolean detectSafeMode() {
         try {
             int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index ba3897d..30aed69 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -3387,11 +3387,8 @@
             }
             // If this application has requested an explicit orientation,
             // then use it.
-            if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
-                    or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
-                    or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
-                    or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
-                    or == ActivityInfo.SCREEN_ORIENTATION_USER) {
+            if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
+                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
                 return or;
             }
             findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);