diff options
author | John Spurlock <jspurlock@google.com> | 2013-04-22 09:48:49 -0400 |
---|---|---|
committer | John Spurlock <jspurlock@google.com> | 2013-04-24 09:52:55 -0400 |
commit | 57306e6b79a87518b5739fc5717cd1cd47c75eae (patch) | |
tree | 2a8dfb9cdc910b6af43cad9ac3ea07bbc0c05fe6 /policy | |
parent | c56b831a1f6f044451df69aafaea1b37c780a360 (diff) | |
download | frameworks_base-57306e6b79a87518b5739fc5717cd1cd47c75eae.zip frameworks_base-57306e6b79a87518b5739fc5717cd1cd47c75eae.tar.gz frameworks_base-57306e6b79a87518b5739fc5717cd1cd47c75eae.tar.bz2 |
Reveal hideybars using system gesture.
Monitor input events using a dedicated input channel created by
window manager.
This new input event receiver could be used in the future for other
system-wide gestures that do not consume events.
Change-Id: Ib1be2fee0015332279fcf10f5b669fffd61acdcd
Diffstat (limited to 'policy')
-rw-r--r-- | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 45 | ||||
-rw-r--r-- | policy/src/com/android/internal/policy/impl/SystemGestures.java | 159 |
2 files changed, 180 insertions, 24 deletions
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 53c00fb..63584ac 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -152,8 +152,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist"; - static public final String ACTION_HIDEYBARS = "android.intent.action.HIDEYBARS"; - /** * These are the system UI flags that, when changing, can cause the layout * of the screen to change. @@ -559,12 +557,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int HIDEYBARS_HIDING = 2; private int mHideybars; - BroadcastReceiver mHideybarsReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - receivedHideybars(intent.getAction()); - } - }; + private InputChannel mSystemGestureInputChannel; + private InputEventReceiver mSystemGestures; IStatusBarService getStatusBarService() { synchronized (mServiceAquireLock) { @@ -918,10 +912,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); context.registerReceiver(mMultiuserReceiver, filter); - // register for hideybars - filter = new IntentFilter(); - filter.addAction(ACTION_HIDEYBARS); - context.registerReceiver(mHideybarsReceiver, filter); + // monitor for system gestures + mSystemGestureInputChannel = mWindowManagerFuncs.monitorInput("SystemGestures"); + mSystemGestures = new SystemGestures(mSystemGestureInputChannel, + mHandler.getLooper(), context, + new SystemGestures.Callbacks() { + @Override + public void onSwipeFromTop() { + showHideybars(); + }}); mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); mLongPressVibePattern = getLongIntArray(mContext.getResources(), @@ -4118,20 +4117,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - private void receivedHideybars(String action) { + private void showHideybars() { synchronized(mLock) { - if (action.equals(ACTION_HIDEYBARS)) { - if (mHideybars == HIDEYBARS_SHOWING) { - if (DEBUG) Slog.d(TAG, "Not showing hideybars, already shown"); - return; - } - if (mStatusBar.isDisplayedLw()) { - if (DEBUG) Slog.d(TAG, "Not showing hideybars, status bar already visible"); - return; - } - mHideybars = HIDEYBARS_SHOWING; - updateSystemUiVisibilityLw(); + if (mHideybars == HIDEYBARS_SHOWING) { + if (DEBUG) Slog.d(TAG, "Not showing hideybars, already shown"); + return; + } + if (mStatusBar.isDisplayedLw()) { + if (DEBUG) Slog.d(TAG, "Not showing hideybars, status bar already visible"); + return; } + mHideybars = HIDEYBARS_SHOWING; + updateSystemUiVisibilityLw(); } } diff --git a/policy/src/com/android/internal/policy/impl/SystemGestures.java b/policy/src/com/android/internal/policy/impl/SystemGestures.java new file mode 100644 index 0000000..083fcbc --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/SystemGestures.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2013 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.content.Context; +import android.os.Looper; +import android.util.Slog; +import android.view.InputChannel; +import android.view.InputDevice; +import android.view.InputEvent; +import android.view.InputEventReceiver; +import android.view.MotionEvent; + +/* + * Listens for system-wide input gestures, firing callbacks when detected. + * @hide + */ +public class SystemGestures extends InputEventReceiver { + private static final String TAG = "SystemGestures"; + private static final boolean DEBUG = false; + 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 final int mSwipeStartThreshold; + private final int mSwipeEndThreshold; + private final Callbacks mCallbacks; + private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS]; + private final float[] mDownY = new float[MAX_TRACKED_POINTERS]; + private final long[] mDownTime = new long[MAX_TRACKED_POINTERS]; + + private int mDownPointers; + private boolean mSwipeFromTopFireable; + + public SystemGestures(InputChannel inputChannel, Looper looper, + Context context, Callbacks callbacks) { + super(inputChannel, looper); + mCallbacks = checkNull("callbacks", callbacks); + mSwipeStartThreshold = checkNull("context", context).getResources() + .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); + mSwipeEndThreshold = mSwipeStartThreshold * 2; + } + + private static <T> T checkNull(String name, T arg) { + if (arg == null) { + throw new IllegalArgumentException(name + " must not be null"); + } + return arg; + } + + @Override + public void onInputEvent(InputEvent event) { + if (event instanceof MotionEvent && event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { + onPointerMotionEvent((MotionEvent) event); + } + finishInputEvent(event, false /*handled*/); + } + + private void onPointerMotionEvent(MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + mSwipeFromTopFireable = true; + mDownPointers = 0; + captureDown(event, 0); + break; + case MotionEvent.ACTION_POINTER_DOWN: + captureDown(event, event.getActionIndex()); + break; + case MotionEvent.ACTION_MOVE: + if (mSwipeFromTopFireable && detectSwipeFromTop(event)) { + mSwipeFromTopFireable = false; + if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop"); + mCallbacks.onSwipeFromTop(); + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mSwipeFromTopFireable = false; + break; + default: + if (DEBUG) Slog.d(TAG, "Ignoring " + event); + } + } + + private void captureDown(MotionEvent event, int pointerIndex) { + final int pointerId = event.getPointerId(pointerIndex); + final int i = findIndex(pointerId); + if (DEBUG) Slog.d(TAG, "pointer " + pointerId + + " down pointerIndex=" + pointerIndex + " trackingIndex=" + i); + if (i != UNTRACKED_POINTER) { + mDownY[i] = event.getY(pointerIndex); + mDownTime[i] = event.getEventTime(); + if (DEBUG) Slog.d(TAG, "pointer " + pointerId + " down y=" + mDownY[i]); + } + } + + private int findIndex(int pointerId) { + for (int i = 0; i < mDownPointers; i++) { + if (mDownPointerId[i] == pointerId) { + return i; + } + } + if (mDownPointers == MAX_TRACKED_POINTERS || pointerId == MotionEvent.INVALID_POINTER_ID) { + return UNTRACKED_POINTER; + } + mDownPointerId[mDownPointers++] = pointerId; + return mDownPointers - 1; + } + + private boolean detectSwipeFromTop(MotionEvent move) { + final int historySize = move.getHistorySize(); + final int pointerCount = move.getPointerCount(); + for (int p = 0; p < pointerCount; p++) { + final int pointerId = move.getPointerId(p); + final int i = findIndex(pointerId); + if (i != UNTRACKED_POINTER) { + for (int h = 0; h < historySize; h++) { + final long time = move.getHistoricalEventTime(h); + final float y = move.getHistoricalY(p, h); + if (detectSwipeFromTop(i, time, y)) { + return true; + } + } + if (detectSwipeFromTop(i, move.getEventTime(), move.getY(p))) { + return true; + } + } + } + return false; + } + + private boolean detectSwipeFromTop(int i, long time, float y) { + final float fromY = mDownY[i]; + final long elapsed = time - mDownTime[i]; + if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i] + + " moved from.y=" + fromY + " to.y=" + y + " in " + elapsed); + return fromY <= mSwipeStartThreshold + && y > fromY + mSwipeEndThreshold + && elapsed < SWIPE_TIMEOUT_MS; + } + + interface Callbacks { + void onSwipeFromTop(); + } +} |