OSDN Git Service

Configure auto-rotation tilt tolerance in config.xml.
authorJeff Brown <jeffbrown@google.com>
Thu, 11 Jun 2015 05:12:54 +0000 (22:12 -0700)
committerJeff Brown <jeffbrown@google.com>
Fri, 12 Jun 2015 01:53:14 +0000 (18:53 -0700)
This allows for the thresholds to be tuned differently for different
products as needed.

Bug: 18276856
Change-Id: I6c87e683dea6a17cf606203a894c8419e20d3658

core/res/res/values/config.xml
core/res/res/values/symbols.xml
services/core/java/com/android/server/policy/WindowOrientationListener.java
tools/orientationplot/README.txt
tools/orientationplot/orientationplot.py

index db1ac44..e7811df 100755 (executable)
          true here reverses that logic. -->
     <bool name="config_reverseDefaultRotation">false</bool>
 
+    <!-- Sets the minimum and maximum tilt tolerance for each possible rotation.
+         This array consists of 4 pairs of values which specify the minimum and maximum
+         tilt angle at which the device will transition into each rotation.
+
+         The tilt angle represents the direction in which the plane of the screen is facing;
+         it is also known as the angle of elevation.
+
+           -90 degree tilt means that the screen is facing straight down
+                           (the device is being held overhead upside-down)
+             0 degree tilt means that the screen is facing outwards
+                           (the device is being held vertically)
+            90 degree tilt means that the screen is facing straight up
+                           (the device is resting on a flat table)
+
+        The default tolerances are set conservatively such that the device is more
+        likely to remain in its natural orientation than rotate into a counterclockwise,
+        clockwise, or reversed posture (with an especially strong bias against the latter)
+        to prevent accidental rotation while carrying the device in hand.
+
+        These thresholds may need to be tuned when the device is intended to be
+        mounted into a dock with a particularly shallow profile wherein rotation
+        would ordinarily have been suppressed.
+
+        It is helpful to consider the desired behavior both when the device is being
+        held at a positive tilt (typical case) vs. a negative tilt (reading overhead in
+        bed) since they are quite different.  In the overhead case, we typically want
+        the device to more strongly prefer to retain its current configuration (in absence
+        of a clear indication that a rotation is desired) since the user's head and neck may
+        be held at an unusual angle.
+    -->
+    <integer-array name="config_autoRotationTiltTolerance">
+        <!-- rotation:   0 (natural)    --> <item>-25</item> <item>70</item>
+        <!-- rotation:  90 (rotate CCW) --> <item>-25</item> <item>65</item>
+        <!-- rotation: 180 (reverse)    --> <item>-25</item> <item>60</item>
+        <!-- rotation: 270 (rotate CW)  --> <item>-25</item> <item>65</item>
+    </integer-array>
+
     <!-- Lid switch behavior -->
 
     <!-- The number of degrees to rotate the display when the keyboard is open.
index b019adb..361c0bd 100755 (executable)
   <java-symbol type="anim" name="voice_activity_open_exit" />
   <java-symbol type="anim" name="voice_activity_open_enter" />
 
+  <java-symbol type="array" name="config_autoRotationTiltTolerance" />
   <java-symbol type="array" name="config_keyboardTapVibePattern" />
   <java-symbol type="array" name="config_longPressVibePattern" />
   <java-symbol type="array" name="config_safeModeDisabledVibePattern" />
index c8fd82e..147efdd 100644 (file)
@@ -24,10 +24,10 @@ import android.hardware.SensorManager;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.util.Log;
 import android.util.Slog;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 
 /**
  * A special helper class used by the WindowManager
@@ -40,8 +40,6 @@ import java.io.PrintWriter;
  *
  * You can also visualize the behavior of the WindowOrientationListener.
  * Refer to frameworks/base/tools/orientationplot/README.txt for details.
- *
- * @hide
  */
 public abstract class WindowOrientationListener {
     private static final String TAG = "WindowOrientationListener";
@@ -90,7 +88,7 @@ public abstract class WindowOrientationListener {
                 ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
         if (mSensor != null) {
             // Create listener only if sensors do exist
-            mSensorEventListener = new SensorEventListenerImpl();
+            mSensorEventListener = new SensorEventListenerImpl(context);
         }
     }
 
@@ -101,12 +99,12 @@ public abstract class WindowOrientationListener {
     public void enable() {
         synchronized (mLock) {
             if (mSensor == null) {
-                Log.w(TAG, "Cannot detect sensors. Not enabled");
+                Slog.w(TAG, "Cannot detect sensors. Not enabled");
                 return;
             }
             if (mEnabled == false) {
                 if (LOG) {
-                    Log.d(TAG, "WindowOrientationListener enabled");
+                    Slog.d(TAG, "WindowOrientationListener enabled");
                 }
                 mSensorEventListener.resetLocked();
                 mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
@@ -121,12 +119,12 @@ public abstract class WindowOrientationListener {
     public void disable() {
         synchronized (mLock) {
             if (mSensor == null) {
-                Log.w(TAG, "Cannot detect sensors. Invalid disable");
+                Slog.w(TAG, "Cannot detect sensors. Invalid disable");
                 return;
             }
             if (mEnabled == true) {
                 if (LOG) {
-                    Log.d(TAG, "WindowOrientationListener disabled");
+                    Slog.d(TAG, "WindowOrientationListener disabled");
                 }
                 mSensorManager.unregisterListener(mSensorEventListener);
                 mEnabled = false;
@@ -296,7 +294,7 @@ public abstract class WindowOrientationListener {
         // If the tilt angle remains greater than the specified angle for a minimum of
         // the specified time, then the device is deemed to be lying flat
         // (just chillin' on a table).
-        private static final float FLAT_ANGLE = 75;
+        private static final float FLAT_ANGLE = 80;
         private static final long FLAT_TIME_NANOS = 1000 * NANOS_PER_MS;
 
         // If the tilt angle has increased by at least delta degrees within the specified amount
@@ -361,8 +359,24 @@ public abstract class WindowOrientationListener {
             SensorManager.STANDARD_GRAVITY + ACCELERATION_TOLERANCE;
 
         // Maximum absolute tilt angle at which to consider orientation data.  Beyond this (i.e.
-        // when screen is facing the sky or ground), we completely ignore orientation data.
-        private static final int MAX_TILT = 75;
+        // when screen is facing the sky or ground), we completely ignore orientation data
+        // because it's too unstable.
+        private static final int MAX_TILT = 80;
+
+        // The tilt angle below which we conclude that the user is holding the device
+        // overhead reading in bed and lock into that state.
+        private static final int TILT_OVERHEAD_ENTER = -40;
+
+        // The tilt angle above which we conclude that the user would like a rotation
+        // change to occur and unlock from the overhead state.
+        private static final int TILT_OVERHEAD_EXIT = -15;
+
+        // The gap angle in degrees between adjacent orientation angles for hysteresis.
+        // This creates a "dead zone" between the current orientation and a proposed
+        // adjacent orientation.  No orientation proposal is made when the orientation
+        // angle is within the gap between the current orientation and the adjacent
+        // orientation.
+        private static final int ADJACENT_ORIENTATION_ANGLE_GAP = 45;
 
         // The tilt angle range in degrees for each orientation.
         // Beyond these tilt angles, we don't even consider transitioning into the
@@ -375,28 +389,13 @@ public abstract class WindowOrientationListener {
         // facing up (resting on a table).
         // The ideal tilt angle is 0 (when the device is vertical) so the limits establish
         // how close to vertical the device must be in order to change orientation.
-        private final int[][] TILT_TOLERANCE = new int[][] {
-            /* ROTATION_0   */ { -25, 70 },
+        private final int[][] mTiltToleranceConfig = new int[][] {
+            /* ROTATION_0   */ { -25, 70 }, // note: these are overridden by config.xml
             /* ROTATION_90  */ { -25, 65 },
             /* ROTATION_180 */ { -25, 60 },
             /* ROTATION_270 */ { -25, 65 }
         };
 
-        // The tilt angle below which we conclude that the user is holding the device
-        // overhead reading in bed and lock into that state.
-        private final int TILT_OVERHEAD_ENTER = -40;
-
-        // The tilt angle above which we conclude that the user would like a rotation
-        // change to occur and unlock from the overhead state.
-        private final int TILT_OVERHEAD_EXIT = -15;
-
-        // The gap angle in degrees between adjacent orientation angles for hysteresis.
-        // This creates a "dead zone" between the current orientation and a proposed
-        // adjacent orientation.  No orientation proposal is made when the orientation
-        // angle is within the gap between the current orientation and the adjacent
-        // orientation.
-        private static final int ADJACENT_ORIENTATION_ANGLE_GAP = 45;
-
         // Timestamp and value of the last accelerometer sample.
         private long mLastFilteredTimestampNanos;
         private float mLastFilteredX, mLastFilteredY, mLastFilteredZ;
@@ -430,11 +429,32 @@ public abstract class WindowOrientationListener {
         private boolean mOverhead;
 
         // History of observed tilt angles.
-        private static final int TILT_HISTORY_SIZE = 40;
+        private static final int TILT_HISTORY_SIZE = 200;
         private float[] mTiltHistory = new float[TILT_HISTORY_SIZE];
         private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE];
         private int mTiltHistoryIndex;
 
+        public SensorEventListenerImpl(Context context) {
+            // Load tilt tolerance configuration.
+            int[] tiltTolerance = context.getResources().getIntArray(
+                    com.android.internal.R.array.config_autoRotationTiltTolerance);
+            if (tiltTolerance.length == 8) {
+                for (int i = 0; i < 4; i++) {
+                    int min = tiltTolerance[i * 2];
+                    int max = tiltTolerance[i * 2 + 1];
+                    if (min >= -90 && min <= max && max <= 90) {
+                        mTiltToleranceConfig[i][0] = min;
+                        mTiltToleranceConfig[i][1] = max;
+                    } else {
+                        Slog.wtf(TAG, "config_autoRotationTiltTolerance contains invalid range: "
+                                + "min=" + min + ", max=" + max);
+                    }
+                }
+            } else {
+                Slog.wtf(TAG, "config_autoRotationTiltTolerance should have exactly 8 elements");
+            }
+        }
+
         public int getProposedRotationLocked() {
             return mProposedRotation;
         }
@@ -451,6 +471,18 @@ public abstract class WindowOrientationListener {
             pw.println(prefix + "mAccelerating=" + mAccelerating);
             pw.println(prefix + "mOverhead=" + mOverhead);
             pw.println(prefix + "mTouched=" + mTouched);
+            pw.print(prefix + "mTiltToleranceConfig=[");
+            for (int i = 0; i < 4; i++) {
+                if (i != 0) {
+                    pw.print(", ");
+                }
+                pw.print("[");
+                pw.print(mTiltToleranceConfig[i][0]);
+                pw.print(", ");
+                pw.print(mTiltToleranceConfig[i][1]);
+                pw.print("]");
+            }
+            pw.println("]");
         }
 
         @Override
@@ -658,8 +690,8 @@ public abstract class WindowOrientationListener {
          * Returns true if the tilt angle is acceptable for a given predicted rotation.
          */
         private boolean isTiltAngleAcceptableLocked(int rotation, int tiltAngle) {
-            return tiltAngle >= TILT_TOLERANCE[rotation][0]
-                    && tiltAngle <= TILT_TOLERANCE[rotation][1];
+            return tiltAngle >= mTiltToleranceConfig[rotation][0]
+                    && tiltAngle <= mTiltToleranceConfig[rotation][1];
         }
 
         /**
index d53f65e..958207d 100644 (file)
@@ -9,6 +9,8 @@ PREREQUISITES
 2. numpy
 3. matplotlib
 
+eg. sudo apt-get install python-numpy python-matplotlib
+
 
 USAGE
 -----
index 6fc3922..77ed074 100755 (executable)
@@ -440,7 +440,7 @@ class Plotter:
 # Notice
 print "Window Orientation Listener plotting tool"
 print "-----------------------------------------\n"
-print "Please turn on the Window Orientation Listener logging in Development Settings."
+print "Please turn on the Window Orientation Listener logging.  See README.txt."
 
 # Start adb.
 print "Starting adb logcat.\n"