diff options
Diffstat (limited to 'policy/src')
3 files changed, 230 insertions, 1 deletions
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 684fd9f..b883c5f 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -314,6 +314,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mDemoHdmiRotation; boolean mDemoHdmiRotationLock; + boolean mWakeGestureEnabledSetting; + MyWakeGestureListener mWakeGestureListener; + // Default display does not rotate, apps that require non-default orientation will have to // have the orientation emulated. private boolean mForceDefaultOrientation = false; @@ -573,6 +576,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.WAKE_GESTURE_ENABLED), false, this, + UserHandle.USER_ALL); resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.ACCELEROMETER_ROTATION), false, this, UserHandle.USER_ALL); @@ -603,6 +609,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + class MyWakeGestureListener extends WakeGestureListener { + MyWakeGestureListener(Context context, Handler handler) { + super(context, handler); + } + + @Override + public void onWakeUp() { + synchronized (mLock) { + if (shouldEnableWakeGestureLp()) { + mPowerManager.wakeUp(SystemClock.uptimeMillis()); + } + } + } + } + class MyOrientationListener extends WindowOrientationListener { MyOrientationListener(Context context, Handler handler) { super(context, handler); @@ -906,6 +927,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mHandler = new PolicyHandler(); + mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler); mOrientationListener = new MyOrientationListener(mContext, mHandler); try { mOrientationListener.setCurrentRotation(windowManager.getRotation()); @@ -1192,6 +1214,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT, UserHandle.USER_CURRENT); + // Configure wake gesture. + boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver, + Settings.Secure.WAKE_GESTURE_ENABLED, 0, + UserHandle.USER_CURRENT) != 0; + if (mWakeGestureEnabledSetting != wakeGestureEnabledSetting) { + mWakeGestureEnabledSetting = wakeGestureEnabledSetting; + updateWakeGestureListenerLp(); + } + // Configure rotation lock. int userRotation = Settings.System.getIntForUser(resolver, Settings.System.USER_ROTATION, Surface.ROTATION_0, @@ -1239,6 +1270,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private void updateWakeGestureListenerLp() { + if (shouldEnableWakeGestureLp()) { + mWakeGestureListener.requestWakeUpTrigger(); + } else { + mWakeGestureListener.cancelWakeUpTrigger(); + } + } + + private boolean shouldEnableWakeGestureLp() { + return mWakeGestureEnabledSetting && !mScreenOnEarly + && (!mLidControlsSleep || mLidState != LID_CLOSED) + && mWakeGestureListener.isSupported(); + } + private void enablePointerLocation() { if (mPointerLocationView == null) { mPointerLocationView = new PointerLocationView(mContext); @@ -4461,6 +4506,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardDelegate.onScreenTurnedOff(why); } synchronized (mLock) { + updateWakeGestureListenerLp(); updateOrientationListenerLp(); updateLockScreenTimeout(); } @@ -4482,6 +4528,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { mScreenOnEarly = true; + updateWakeGestureListenerLp(); updateOrientationListenerLp(); updateLockScreenTimeout(); } @@ -5056,6 +5103,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager.GO_TO_SLEEP_REASON_USER, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); } + + synchronized (mLock) { + updateWakeGestureListenerLp(); + } } void updateRotation(boolean alwaysSendConfiguration) { @@ -5516,6 +5567,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu); } + pw.print(prefix); pw.print("mWakeGestureEnabledSetting="); + pw.println(mWakeGestureEnabledSetting); + pw.print(prefix); pw.print("mSupportAutoRotation="); pw.println(mSupportAutoRotation); pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode); pw.print(" mDockMode="); pw.print(mDockMode); @@ -5657,9 +5711,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation); pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock); pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation); + mGlobalKeyManager.dump(prefix, pw); mStatusBarController.dump(pw, prefix); mNavigationBarController.dump(pw, prefix); PolicyControl.dump(prefix, pw); + + if (mWakeGestureListener != null) { + mWakeGestureListener.dump(pw, prefix); + } + if (mOrientationListener != null) { + mOrientationListener.dump(pw, prefix); + } } } diff --git a/policy/src/com/android/internal/policy/impl/WakeGestureListener.java b/policy/src/com/android/internal/policy/impl/WakeGestureListener.java new file mode 100644 index 0000000..9396c2c --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/WakeGestureListener.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014 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. + */ + +package com.android.internal.policy.impl; + +import android.os.Handler; +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorManager; +import android.hardware.TriggerEvent; +import android.hardware.TriggerEventListener; + +import java.io.PrintWriter; + +/** + * Watches for wake gesture sensor events then invokes the listener. + */ +public abstract class WakeGestureListener { + private static final String TAG = "WakeGestureListener"; + + private final SensorManager mSensorManager; + private final Handler mHandler; + + private final Object mLock = new Object(); + + private boolean mTriggerRequested; + private Sensor mSensor; + + public WakeGestureListener(Context context, Handler handler) { + mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); + mHandler = handler; + + mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_WAKE_GESTURE); + } + + public abstract void onWakeUp(); + + public boolean isSupported() { + synchronized (mLock) { + return mSensor != null; + } + } + + public void requestWakeUpTrigger() { + synchronized (mLock) { + if (mSensor != null && !mTriggerRequested) { + mTriggerRequested = true; + mSensorManager.requestTriggerSensor(mListener, mSensor); + } + } + } + + public void cancelWakeUpTrigger() { + synchronized (mLock) { + if (mSensor != null && mTriggerRequested) { + mTriggerRequested = false; + mSensorManager.cancelTriggerSensor(mListener, mSensor); + } + } + } + + public void dump(PrintWriter pw, String prefix) { + synchronized (mLock) { + pw.println(prefix + TAG); + prefix += " "; + pw.println(prefix + "mTriggerRequested=" + mTriggerRequested); + pw.println(prefix + "mSensor=" + mSensor); + } + } + + private final TriggerEventListener mListener = new TriggerEventListener() { + @Override + public void onTrigger(TriggerEvent event) { + synchronized (mLock) { + mTriggerRequested = false; + mHandler.post(mWakeUpRunnable); + } + } + }; + + private final Runnable mWakeUpRunnable = new Runnable() { + @Override + public void run() { + onWakeUp(); + } + }; +} diff --git a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java b/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java index 0c77556..2cc33b5 100644 --- a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java +++ b/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java @@ -26,6 +26,9 @@ import android.os.SystemProperties; import android.util.FloatMath; import android.util.Log; import android.util.Slog; +import android.util.TimeUtils; + +import java.io.PrintWriter; /** * A special helper class used by the WindowManager @@ -181,6 +184,19 @@ public abstract class WindowOrientationListener { */ public abstract void onProposedRotationChanged(int rotation); + public void dump(PrintWriter pw, String prefix) { + synchronized (mLock) { + pw.println(prefix + TAG); + prefix += " "; + pw.println(prefix + "mEnabled=" + mEnabled); + pw.println(prefix + "mCurrentRotation=" + mCurrentRotation); + pw.println(prefix + "mSensor=" + mSensor); + pw.println(prefix + "mRate=" + mRate); + + mSensorEventListener.dumpLocked(pw, prefix); + } + } + /** * This class filters the raw accelerometer data and tries to detect actual changes in * orientation. This is a very ill-defined problem so there are a lot of tweakable parameters, @@ -342,6 +358,14 @@ public abstract class WindowOrientationListener { /* 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 @@ -364,12 +388,18 @@ public abstract class WindowOrientationListener { // Timestamp when the device last appeared to be flat for sure (the flat delay elapsed). private long mFlatTimestampNanos; + private boolean mFlat; // Timestamp when the device last appeared to be swinging. private long mSwingTimestampNanos; + private boolean mSwinging; // Timestamp when the device last appeared to be undergoing external acceleration. private long mAccelerationTimestampNanos; + private boolean mAccelerating; + + // Whether we are locked into an overhead usage mode. + private boolean mOverhead; // History of observed tilt angles. private static final int TILT_HISTORY_SIZE = 40; @@ -381,6 +411,19 @@ public abstract class WindowOrientationListener { return mProposedRotation; } + public void dumpLocked(PrintWriter pw, String prefix) { + pw.println(prefix + "mProposedRotation=" + mProposedRotation); + pw.println(prefix + "mPredictedRotation=" + mPredictedRotation); + pw.println(prefix + "mLastFilteredX=" + mLastFilteredX); + pw.println(prefix + "mLastFilteredY=" + mLastFilteredY); + pw.println(prefix + "mLastFilteredZ=" + mLastFilteredZ); + pw.println(prefix + "mTiltHistory={last: " + getLastTiltLocked() + "}"); + pw.println(prefix + "mFlat=" + mFlat); + pw.println(prefix + "mSwinging=" + mSwinging); + pw.println(prefix + "mAccelerating=" + mAccelerating); + pw.println(prefix + "mOverhead=" + mOverhead); + } + @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @@ -478,7 +521,18 @@ public abstract class WindowOrientationListener { // If the tilt angle is too close to horizontal then we cannot determine // the orientation angle of the screen. - if (Math.abs(tiltAngle) > MAX_TILT) { + if (tiltAngle <= TILT_OVERHEAD_ENTER) { + mOverhead = true; + } else if (tiltAngle >= TILT_OVERHEAD_EXIT) { + mOverhead = false; + } + if (mOverhead) { + if (LOG) { + Slog.v(TAG, "Ignoring sensor data, device is overhead: " + + "tiltAngle=" + tiltAngle); + } + clearPredictedRotationLocked(); + } else if (Math.abs(tiltAngle) > MAX_TILT) { if (LOG) { Slog.v(TAG, "Ignoring sensor data, tilt angle too high: " + "tiltAngle=" + tiltAngle); @@ -526,6 +580,9 @@ public abstract class WindowOrientationListener { } } } + mFlat = isFlat; + mSwinging = isSwinging; + mAccelerating = isAccelerating; // Determine new proposed rotation. oldProposedRotation = mProposedRotation; @@ -543,6 +600,7 @@ public abstract class WindowOrientationListener { + ", isAccelerating=" + isAccelerating + ", isFlat=" + isFlat + ", isSwinging=" + isSwinging + + ", isOverhead=" + mOverhead + ", timeUntilSettledMS=" + remainingMS(now, mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) + ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now, @@ -660,8 +718,12 @@ public abstract class WindowOrientationListener { mLastFilteredTimestampNanos = Long.MIN_VALUE; mProposedRotation = -1; mFlatTimestampNanos = Long.MIN_VALUE; + mFlat = false; mSwingTimestampNanos = Long.MIN_VALUE; + mSwinging = false; mAccelerationTimestampNanos = Long.MIN_VALUE; + mAccelerating = false; + mOverhead = false; clearPredictedRotationLocked(); clearTiltHistoryLocked(); } @@ -726,6 +788,11 @@ public abstract class WindowOrientationListener { return mTiltHistoryTimestampNanos[index] != Long.MIN_VALUE ? index : -1; } + private float getLastTiltLocked() { + int index = nextTiltHistoryIndexLocked(mTiltHistoryIndex); + return index >= 0 ? mTiltHistory[index] : Float.NaN; + } + private float remainingMS(long now, long until) { return now >= until ? 0 : (until - now) * 0.000001f; } |