Send power hint on fling gestures.

Use the existing PointerEventListener infrastructure to listen for
gestures that look like flings and hint to the power system when they
happen. Since we don't actually have a bound for the fling like a
regular application would, limit them to five seconds and refresh
every time a new fling is seen until the five second time period is
up.

bug 24059298

Change-Id: I5757a1e88f2ab2ef08cccefa8221d809ae71bb6f
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index e742f98..17bce30 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -53,6 +53,15 @@
      */
     public static final int WAKEFULNESS_DOZING = 3;
 
+
+    /**
+     * Power hint: The user is interacting with the device. The corresponding data field must be
+     * the expected duration of the fling, or 0 if unknown.
+     *
+     * This must be kept in sync with the values in hardware/libhardware/include/hardware/power.h
+     */
+    public static final int POWER_HINT_INTERACTION = 2;
+
     public static String wakefulnessToString(int wakefulness) {
         switch (wakefulness) {
             case WAKEFULNESS_ASLEEP:
@@ -142,4 +151,6 @@
     public abstract void updateUidProcState(int uid, int procState);
 
     public abstract void uidGone(int uid);
+
+    public abstract void powerHint(int hintId, int data);
 }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index bb0731a..31286b6 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -65,6 +65,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.PowerManager;
+import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -267,6 +268,7 @@
     PowerManager mPowerManager;
     ActivityManagerInternal mActivityManagerInternal;
     DreamManagerInternal mDreamManagerInternal;
+    PowerManagerInternal mPowerManagerInternal;
     IStatusBarService mStatusBarService;
     boolean mPreloadedRecentApps;
     final Object mServiceAquireLock = new Object();
@@ -1330,6 +1332,7 @@
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
+        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
 
         // Init display burn-in protection
@@ -1506,6 +1509,13 @@
                         }
                     }
                     @Override
+                    public void onFling(int duration) {
+                        if (mPowerManagerInternal != null) {
+                            mPowerManagerInternal.powerHint(
+                                    PowerManagerInternal.POWER_HINT_INTERACTION, duration);
+                        }
+                    }
+                    @Override
                     public void onDebug() {
                         // no-op
                     }
@@ -6074,6 +6084,7 @@
             mKeyguardDelegate.bindService(mContext);
             mKeyguardDelegate.onBootCompleted();
         }
+        mSystemGestures.systemReady();
     }
 
     /** {@inheritDoc} */
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index 627b328..e4bd21d 100644
--- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -17,9 +17,14 @@
 package com.android.server.policy;
 
 import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
 import android.util.Slog;
+import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.WindowManagerPolicy.PointerEventListener;
+import android.widget.OverScroller;
 
 /*
  * Listens for system-wide input gestures, firing callbacks when detected.
@@ -31,12 +36,14 @@
     private static final long SWIPE_TIMEOUT_MS = 500;
     private static final int MAX_TRACKED_POINTERS = 32;  // max per input system
     private static final int UNTRACKED_POINTER = -1;
+    private static final int MAX_FLING_TIME_MILLIS = 5000;
 
     private static final int SWIPE_NONE = 0;
     private static final int SWIPE_FROM_TOP = 1;
     private static final int SWIPE_FROM_BOTTOM = 2;
     private static final int SWIPE_FROM_RIGHT = 3;
 
+    private final Context mContext;
     private final int mSwipeStartThreshold;
     private final int mSwipeDistanceThreshold;
     private final Callbacks mCallbacks;
@@ -45,13 +52,18 @@
     private final float[] mDownY = new float[MAX_TRACKED_POINTERS];
     private final long[] mDownTime = new long[MAX_TRACKED_POINTERS];
 
+    private GestureDetector mGestureDetector;
+    private OverScroller mOverscroller;
+
     int screenHeight;
     int screenWidth;
     private int mDownPointers;
     private boolean mSwipeFireable;
     private boolean mDebugFireable;
+    private long mLastFlingTime;
 
     public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
+        mContext = context;
         mCallbacks = checkNull("callbacks", callbacks);
         mSwipeStartThreshold = checkNull("context", context).getResources()
                 .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
@@ -67,8 +79,17 @@
         return arg;
     }
 
+    public void systemReady() {
+        Handler h = new Handler(Looper.myLooper());
+        mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), h);
+        mOverscroller = new OverScroller(mContext);
+    }
+
     @Override
     public void onPointerEvent(MotionEvent event) {
+        if (mGestureDetector != null) {
+            mGestureDetector.onTouchEvent(event);
+        }
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 mSwipeFireable = true;
@@ -190,10 +211,40 @@
         return SWIPE_NONE;
     }
 
+    private final class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener {
+        @Override
+        public boolean onSingleTapUp(MotionEvent e) {
+            if (!mOverscroller.isFinished()) {
+                mOverscroller.forceFinished(true);
+            }
+            return true;
+        }
+        @Override
+        public boolean onFling(MotionEvent down, MotionEvent up,
+                float velocityX, float velocityY) {
+            mOverscroller.computeScrollOffset();
+            long now = SystemClock.uptimeMillis();
+
+            if (mLastFlingTime != 0 && now > mLastFlingTime + MAX_FLING_TIME_MILLIS) {
+                mOverscroller.forceFinished(true);
+            }
+            mOverscroller.fling(0, 0, (int)velocityX, (int)velocityY,
+                    Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
+            int duration = mOverscroller.getDuration();
+            if (duration > MAX_FLING_TIME_MILLIS) {
+                duration = MAX_FLING_TIME_MILLIS;
+            }
+            mLastFlingTime = now;
+            mCallbacks.onFling(duration);
+            return true;
+        }
+    }
+
     interface Callbacks {
         void onSwipeFromTop();
         void onSwipeFromBottom();
         void onSwipeFromRight();
+        void onFling(int durationMs);
         void onDown();
         void onUpOrCancel();
         void onDebug();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index b920f97..f7a8970 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -76,6 +76,7 @@
 
 import libcore.util.Objects;
 
+import static android.os.PowerManagerInternal.POWER_HINT_INTERACTION;
 import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
 import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
 import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
@@ -150,7 +151,6 @@
     private static final int SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 5 * 1000;
 
     // Power hints defined in hardware/libhardware/include/hardware/power.h.
-    private static final int POWER_HINT_INTERACTION = 2;
     private static final int POWER_HINT_LOW_POWER = 5;
 
     // Power features defined in hardware/libhardware/include/hardware/power.h.
@@ -3534,5 +3534,10 @@
         public void uidGone(int uid) {
             uidGoneInternal(uid);
         }
+
+        @Override
+        public void powerHint(int hintId, int data) {
+            powerHintInternal(hintId, data);
+        }
     }
 }