private int mCurrentBoundedUserId = -1;
private float mNavBarButtonAlpha;
private boolean mInputFocusTransferStarted;
+ private float mInputFocusTransferStartY;
+ private long mInputFocusTransferStartMillis;
private float mWindowCornerRadius;
private boolean mSupportsRoundedCornersOnWindows;
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
int action = event.getActionMasked();
if (action == ACTION_DOWN) {
mInputFocusTransferStarted = true;
-
+ mInputFocusTransferStartY = event.getY();
+ mInputFocusTransferStartMillis = event.getEventTime();
+ bar.onInputFocusTransfer(mInputFocusTransferStarted, 0 /* velocity */);
}
if (action == ACTION_UP || action == ACTION_CANCEL) {
mInputFocusTransferStarted = false;
+ bar.onInputFocusTransfer(mInputFocusTransferStarted,
+ (event.getY() - mInputFocusTransferStartY)
+ / (event.getEventTime() - mInputFocusTransferStartMillis));
}
- bar.onInputFocusTransfer(mInputFocusTransferStarted);
event.recycle();
}
});
StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
if (bar != null) {
mInputFocusTransferStarted = false;
- bar.onInputFocusTransfer(false);
+ bar.onInputFocusTransfer(false, 0 /* velocity */);
}
});
}
private boolean mIsFullWidth;
private boolean mBlockingExpansionForCurrentTouch;
- private boolean mExpectingOpenPanelGesture;
+ /**
+ * Following variables maintain state of events when input focus transfer may occur.
+ */
+ private boolean mExpectingSynthesizedDown; // expecting to see synthesized DOWN event
+ private boolean mLastEventSynthesizedDown; // last event was synthesized DOWN event
/**
* Current dark amount that follows regular interpolation curve of animation.
mDownY = event.getY();
mCollapsedOnDown = isFullyCollapsed();
mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
+ if (mExpectingSynthesizedDown) {
+ mLastEventSynthesizedDown = true;
+ } else {
+ // down but not synthesized motion event.
+ mLastEventSynthesizedDown = false;
+ }
+ } else {
+ // not down event at all.
+ mLastEventSynthesizedDown = false;
}
}
return false;
}
- initDownStates(event);
// Make sure the next touch won't the blocked after the current ends.
if (event.getAction() == MotionEvent.ACTION_UP
|| event.getAction() == MotionEvent.ACTION_CANCEL) {
mBlockingExpansionForCurrentTouch = false;
}
+ // When touch focus transfer happens, ACTION_DOWN->ACTION_UP may happen immediately
+ // without any ACTION_MOVE event.
+ // In such case, simply expand the panel instead of being stuck at the bottom bar.
+ if (mLastEventSynthesizedDown && event.getAction() == MotionEvent.ACTION_UP) {
+ expand(true /* animate */);
+ }
+ initDownStates(event);
if (!mIsExpanding && !shouldQuickSettingsIntercept(mDownX, mDownY, 0)
&& mPulseExpansionHandler.onTouchEvent(event)) {
// We're expanding all the other ones shouldn't get this anymore
if (!isFullyCollapsed()) {
return;
}
- mExpectingOpenPanelGesture = true;
+ mExpectingSynthesizedDown = true;
onTrackingStarted();
}
/**
- * Input focus transfer has already happened as this view decided to intercept
- * very first down event.
+ * Called when this view is no longer waiting for input focus transfer.
+ *
+ * There are two scenarios behind this function call. First, input focus transfer
+ * has successfully happened and this view already received synthetic DOWN event.
+ * (mExpectingSynthesizedDown == false). Do nothing.
+ *
+ * Second, before input focus transfer finished, user may have lifted finger
+ * in previous window and this window never received synthetic DOWN event.
+ * (mExpectingSynthesizedDown == true).
+ * In this case, we use the velocity to trigger fling event.
+ *
+ * @param velocity unit is in px / millis
*/
- public void stopWaitingForOpenPanelGesture() {
- if (mExpectingOpenPanelGesture) {
- mExpectingOpenPanelGesture = false;
+ public void stopWaitingForOpenPanelGesture(float velocity) {
+ if (mExpectingSynthesizedDown) {
+ mExpectingSynthesizedDown = false;
+ fling(velocity > 1f ? 1000f * velocity : 0, true /* animate */);
onTrackingStopped(false);
}
}
@Override
protected boolean shouldGestureWaitForTouchSlop() {
- if (mExpectingOpenPanelGesture) {
- mExpectingOpenPanelGesture = false;
+ if (mExpectingSynthesizedDown) {
+ mExpectingSynthesizedDown = false;
return false;
}
return isFullyCollapsed() || mBarState != StatusBarState.SHADE;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
/**
* Called when another window is about to transfer it's input focus.
*/
- public void onInputFocusTransfer(boolean start) {
+ public void onInputFocusTransfer(boolean start, float velocity) {
if (!mCommandQueue.panelsEnabled()) {
return;
}
if (start) {
mNotificationPanel.startWaitingForOpenPanelGesture();
} else {
- mNotificationPanel.stopWaitingForOpenPanelGesture();
+ mNotificationPanel.stopWaitingForOpenPanelGesture(velocity);
}
}