Add gesture to drag in recents from navigation bar

Change-Id: I672ed08f1019835891411b87e2d0de0290defff7
This commit is contained in:
Jorim Jaggi
2015-11-18 15:57:38 -08:00
parent 6fbb5c1ca4
commit dd98d41e3a
16 changed files with 453 additions and 162 deletions

View File

@@ -31,5 +31,20 @@ public interface RecentsComponent {
/**
* Docks the top-most task and opens recents.
*/
void dockTopTask();
void dockTopTask(boolean draggingInRecents);
/**
* Called during a drag-from-navbar-in gesture.
*
* @param distanceFromTop the distance of the current drag in gesture from the top of the
* screen
*/
void onDraggingInRecents(float distanceFromTop);
/**
* Called when the gesture to drag in recents ended.
*
* @param velocity the velocity of the finger when releasing it in pixels per second
*/
void onDraggingInRecentsEnded(float velocity);
}

View File

@@ -48,12 +48,12 @@ public class SystemUIApplication extends Application {
com.android.systemui.keyguard.KeyguardViewMediator.class,
com.android.systemui.recents.Recents.class,
com.android.systemui.volume.VolumeUI.class,
Divider.class,
com.android.systemui.statusbar.SystemBars.class,
com.android.systemui.usb.StorageNotification.class,
com.android.systemui.power.PowerUI.class,
com.android.systemui.media.RingtonePlayer.class,
com.android.systemui.keyboard.KeyboardUI.class,
Divider.class
};
/**

View File

@@ -24,8 +24,10 @@ package com.android.systemui.recents;
oneway interface IRecentsNonSystemUserCallbacks {
void preloadRecents();
void cancelPreloadingRecents();
void showRecents(boolean triggeredFromAltTab);
void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents);
void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecents();
void onConfigurationChanged();
void onDraggingInRecents(float distanceFromTop);
void onDraggingInRecentsEnded(float velocity);
}

View File

@@ -73,6 +73,7 @@ public class Recents extends SystemUI
private Handler mHandler;
private RecentsImpl mImpl;
private int mDraggingInRecentsCurrentUser;
// Only For system user, this is the callbacks instance we return to each secondary user
private RecentsSystemUser mSystemUserCallbacks;
@@ -213,14 +214,14 @@ public class Recents extends SystemUI
int currentUser = sSystemServicesProxy.getCurrentUser();
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.showRecents(triggeredFromAltTab);
mImpl.showRecents(triggeredFromAltTab, false /* draggingInRecents */);
} else {
if (mSystemUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.showRecents(triggeredFromAltTab);
callbacks.showRecents(triggeredFromAltTab, false /* draggingInRecents */);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -361,8 +362,57 @@ public class Recents extends SystemUI
}
@Override
public void dockTopTask() {
mImpl.dockTopTask();
public void dockTopTask(boolean draggingInRecents) {
mImpl.dockTopTask(draggingInRecents);
if (draggingInRecents) {
mDraggingInRecentsCurrentUser = sSystemServicesProxy.getCurrentUser();
}
}
@Override
public void onDraggingInRecents(float distanceFromTop) {
if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
mImpl.onDraggingInRecents(distanceFromTop);
} else {
if (mSystemUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
mSystemUserCallbacks.getNonSystemUserRecentsForUser(
mDraggingInRecentsCurrentUser);
if (callbacks != null) {
try {
callbacks.onDraggingInRecents(distanceFromTop);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
} else {
Log.e(TAG, "No SystemUI callbacks found for user: "
+ mDraggingInRecentsCurrentUser);
}
}
}
}
@Override
public void onDraggingInRecentsEnded(float velocity) {
if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
mImpl.onDraggingInRecentsEnded(velocity);
} else {
if (mSystemUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
mSystemUserCallbacks.getNonSystemUserRecentsForUser(
mDraggingInRecentsCurrentUser);
if (callbacks != null) {
try {
callbacks.onDraggingInRecentsEnded(velocity);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
} else {
Log.e(TAG, "No SystemUI callbacks found for user: "
+ mDraggingInRecentsCurrentUser);
}
}
}
}
@Override

View File

@@ -46,6 +46,8 @@ import com.android.systemui.recents.events.activity.IterateRecentsEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
import com.android.systemui.recents.misc.DozeTrigger;
import com.android.systemui.recents.misc.ForegroundThread;
import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -140,6 +142,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
RecentsAppWidgetHost mAppWidgetHost;
boolean mBootCompleted;
boolean mCanReuseTaskStackViews = true;
boolean mDraggingInRecents;
// Task launching
Rect mSearchBarBounds = new Rect();
@@ -164,14 +167,13 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
public void run() {
// When this fires, then the user has not released alt-tab for at least
// FAST_ALT_TAB_DELAY_MS milliseconds
showRecents(mTriggeredFromAltTab);
showRecents(mTriggeredFromAltTab, false /* draggingInRecents */);
}
});
Bitmap mThumbnailTransitionBitmapCache;
Task mThumbnailTransitionBitmapCacheKey;
public RecentsImpl(Context context) {
mContext = context;
mHandler = new Handler();
@@ -248,8 +250,9 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
}
@Override
public void showRecents(boolean triggeredFromAltTab) {
public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents) {
mTriggeredFromAltTab = triggeredFromAltTab;
mDraggingInRecents = draggingInRecents;
if (mFastAltTabTrigger.hasTriggered()) {
// We are calling this from the doze trigger, so just fall through to show Recents
mFastAltTabTrigger.resetTrigger();
@@ -315,6 +318,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
return;
}
mDraggingInRecents = false;
mTriggeredFromAltTab = false;
try {
@@ -385,6 +389,16 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
// Do nothing
}
@Override
public void onDraggingInRecents(float distanceFromTop) {
EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEvent(distanceFromTop));
}
@Override
public void onDraggingInRecentsEnded(float velocity) {
EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity));
}
/**
* Transitions to the next recent task in the stack.
*/
@@ -521,13 +535,13 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
showRelativeAffiliatedTask(false);
}
public void dockTopTask() {
public void dockTopTask(boolean draggingInRecents) {
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
if (topTask != null && !SystemServicesProxy.isHomeStack(topTask.stackId)) {
ssp.startTaskInDockedMode(topTask.id,
ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
showRecents(false /* triggeredFromAltTab */);
showRecents(false /* triggeredFromAltTab */, draggingInRecents);
}
}
@@ -856,7 +870,8 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
launchState.launchedHasConfigurationChanged = false;
launchState.startHidden = topTask != null && topTask.stackId == FREEFORM_WORKSPACE_STACK_ID;
launchState.startHidden = topTask != null && topTask.stackId == FREEFORM_WORKSPACE_STACK_ID
|| mDraggingInRecents;
Intent intent = new Intent();
intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);

View File

@@ -502,6 +502,19 @@ public class EventBus extends BroadcastReceiver {
queueEvent(event);
}
/**
* If this method is called from the main thread, it will be handled directly. If this method
* is not called from the main thread, it will be posted onto the main thread.
*/
public void sendOntoMainThread(Event event) {
long callingThreadId = Thread.currentThread().getId();
if (callingThreadId != mHandler.getLooper().getThread().getId()) {
post(event);
} else {
send(event);
}
}
/** Prevent post()ing an InterprocessEvent */
@Deprecated
public void post(InterprocessEvent event) {

View File

@@ -0,0 +1,15 @@
package com.android.systemui.recents.events.ui;
import com.android.systemui.recents.events.EventBus.Event;
/**
* This event is sent when the user finished dragging in recents.
*/
public class DraggingInRecentsEndedEvent extends Event {
public final float velocity;
public DraggingInRecentsEndedEvent(float velocity) {
this.velocity = velocity;
}
}

View File

@@ -0,0 +1,15 @@
package com.android.systemui.recents.events.ui;
import com.android.systemui.recents.events.EventBus.Event;
/**
* This event is sent when the user changed how far they are dragging in recents.
*/
public class DraggingInRecentsEvent extends Event {
public final float distanceFromTop;
public DraggingInRecentsEvent(float distanceFromTop) {
this.distanceFromTop = distanceFromTop;
}
}

View File

@@ -41,6 +41,8 @@ import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
@@ -542,6 +544,15 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
}
}
public final void onBusEvent(DraggingInRecentsEvent event) {
setStackViewVisibility(View.VISIBLE);
setTranslationY(event.distanceFromTop - mTaskStackView.getTaskViews().get(0).getY());
}
public final void onBusEvent(DraggingInRecentsEndedEvent event) {
animate().translationY(0f);
}
/**
* Updates the dock region to match the specified dock state.
*/

View File

@@ -32,6 +32,7 @@ public class Divider extends SystemUI {
private static final String TAG = "Divider";
private int mDividerWindowWidth;
private DividerWindowManager mWindowManager;
private DividerView mView;
@Override
public void start() {
@@ -39,6 +40,7 @@ public class Divider extends SystemUI {
mDividerWindowWidth = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
update(mContext.getResources().getConfiguration());
putComponent(Divider.class, this);
}
@Override
@@ -47,14 +49,18 @@ public class Divider extends SystemUI {
update(newConfig);
}
public DividerView getView() {
return mView;
}
private void addDivider(Configuration configuration) {
DividerView view = (DividerView)
mView = (DividerView)
LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null);
final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
final int width = landscape ? mDividerWindowWidth : MATCH_PARENT;
final int height = landscape ? MATCH_PARENT : mDividerWindowWidth;
mWindowManager.add(view, width, height);
view.setWindowManager(mWindowManager);
mWindowManager.add(mView, width, height);
mView.setWindowManager(mWindowManager);
}
private void removeDivider() {

View File

@@ -98,10 +98,10 @@ public class DividerSnapAlgorithm {
// TODO: Better calculation
targets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
targets.add(new SnapTarget((int) (0.35f * dividerMax) - mDividerSize / 2,
targets.add(new SnapTarget((int) (0.38f * dividerMax) - mDividerSize / 2,
SnapTarget.FLAG_NONE));
targets.add(new SnapTarget(dividerMax / 2 - mDividerSize / 2, SnapTarget.FLAG_NONE));
targets.add(new SnapTarget((int) (0.65f * dividerMax) - mDividerSize / 2,
targets.add(new SnapTarget((int) (0.62f * dividerMax) - mDividerSize / 2,
SnapTarget.FLAG_NONE));
targets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
return targets;

View File

@@ -127,6 +127,28 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mWindowManager = windowManager;
}
public WindowManagerProxy getWindowManagerProxy() {
return mWindowManagerProxy;
}
public boolean startDragging() {
mDockSide = mWindowManagerProxy.getDockSide();
if (mDockSide != WindowManager.DOCKED_INVALID) {
mWindowManagerProxy.setResizing(true);
mWindowManager.setSlippery(false);
liftBackground();
return true;
} else {
return false;
}
}
public void stopDragging(int position, float velocity) {
fling(position, velocity);
mWindowManager.setSlippery(true);
releaseBackground();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
convertToScreenCoordinates(event);
@@ -138,20 +160,13 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mStartX = (int) event.getX();
mStartY = (int) event.getY();
getLocationOnScreen(mTempInt2);
mDockSide = mWindowManagerProxy.getDockSide();
boolean result = startDragging();
if (isHorizontalDivision()) {
mStartPosition = mTempInt2[1] + mDividerInsets;
} else {
mStartPosition = mTempInt2[0] + mDividerInsets;
}
if (mDockSide != WindowManager.DOCKED_INVALID) {
mWindowManagerProxy.setResizing(true);
mWindowManager.setSlippery(false);
liftBackground();
return true;
} else {
return false;
}
return result;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
int x = (int) event.getX();
@@ -168,10 +183,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,
y = (int) event.getRawY();
mVelocityTracker.computeCurrentVelocity(1000);
fling(x, y, mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
mWindowManager.setSlippery(true);
releaseBackground();
int position = calculatePosition(x, y);
stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
: mVelocityTracker.getXVelocity());
break;
}
return true;
@@ -181,9 +195,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
event.setLocation(event.getRawX(), event.getRawY());
}
private void fling(int x, int y, float xVelocity, float yVelocity) {
int position = calculatePosition(x, y);
float velocity = isHorizontalDivision() ? yVelocity : xVelocity;
private void fling(int position, float velocity) {
final SnapTarget snapTarget = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils,
mDividerSize, isHorizontalDivision()).calculateSnapTarget(position, velocity);
@@ -277,9 +289,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
return isHorizontalDivision() ? calculateYPosition(touchY) : calculateXPosition(touchX);
}
private boolean isHorizontalDivision() {
return mDockSide == WindowManager.DOCKED_TOP
|| mDockSide == WindowManager.DOCKED_BOTTOM;
public boolean isHorizontalDivision() {
return getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
}
private int calculateXPosition(int touchX) {
@@ -290,7 +301,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
return mStartPosition + touchY - mStartY;
}
private void resizeStack(int position) {
public void resizeStack(int position) {
mTmpRect.set(0, 0, mDisplayWidth, mDisplayHeight);
switch (mDockSide) {
case WindowManager.DOCKED_LEFT:

View File

@@ -0,0 +1,250 @@
/*
* 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.systemui.statusbar.phone;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.SystemProperties;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.BaseStatusBar;
import static android.view.WindowManager.*;
/**
* Class to detect gestures on the navigation bar.
*/
public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureListener {
private static final String DOCK_WINDOW_GESTURE_ENABLED_PROP = "persist.dock_gesture_enabled";
/**
* When dragging from the navigation bar, we drag in recents.
*/
private static final int DRAG_MODE_RECENTS = 0;
/**
* When dragging from the navigation bar, we drag the divider.
*/
private static final int DRAG_MODE_DIVIDER = 1;
private RecentsComponent mRecentsComponent;
private Divider mDivider;
private boolean mIsVertical;
private boolean mIsRTL;
private final GestureDetector mTaskSwitcherDetector;
private final int mScrollTouchSlop;
private final int mTouchSlop;
private final int mMinFlingVelocity;
private int mTouchDownX;
private int mTouchDownY;
private VelocityTracker mVelocityTracker;
private boolean mDockWindowEnabled;
private boolean mDockWindowTouchSlopExceeded;
private int mDragMode;
public NavigationBarGestureHelper(Context context) {
ViewConfiguration configuration = ViewConfiguration.get(context);
Resources r = context.getResources();
mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity();
mTaskSwitcherDetector = new GestureDetector(context, this);
mDockWindowEnabled = SystemProperties.getBoolean(DOCK_WINDOW_GESTURE_ENABLED_PROP, false);
}
public void setComponents(RecentsComponent recentsComponent, Divider divider) {
mRecentsComponent = recentsComponent;
mDivider = divider;
}
public void setBarState(boolean isVertical, boolean isRTL) {
mIsVertical = isVertical;
mIsRTL = isRTL;
}
public boolean onInterceptTouchEvent(MotionEvent event) {
// If we move more than a fixed amount, then start capturing for the
// task switcher detector
mTaskSwitcherDetector.onTouchEvent(event);
int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
mTouchDownX = (int) event.getX();
mTouchDownY = (int) event.getY();
break;
}
case MotionEvent.ACTION_MOVE: {
int x = (int) event.getX();
int y = (int) event.getY();
int xDiff = Math.abs(x - mTouchDownX);
int yDiff = Math.abs(y - mTouchDownY);
boolean exceededTouchSlop = !mIsVertical
? xDiff > mScrollTouchSlop && xDiff > yDiff
: yDiff > mScrollTouchSlop && yDiff > xDiff;
if (exceededTouchSlop) {
return true;
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
break;
}
return mDockWindowEnabled && interceptDockWindowEvent(event);
}
private boolean interceptDockWindowEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
handleDragActionDownEvent(event);
break;
case MotionEvent.ACTION_MOVE:
return handleDragActionMoveEvent(event);
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
handleDragActionUpEvent(event);
break;
}
return false;
}
private boolean handleDockWindowEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
handleDragActionDownEvent(event);
break;
case MotionEvent.ACTION_MOVE:
handleDragActionMoveEvent(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
handleDragActionUpEvent(event);
break;
}
return true;
}
private void handleDragActionDownEvent(MotionEvent event) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(event);
mDockWindowTouchSlopExceeded = false;
mTouchDownX = (int) event.getX();
mTouchDownY = (int) event.getY();
}
private boolean handleDragActionMoveEvent(MotionEvent event) {
mVelocityTracker.addMovement(event);
int x = (int) event.getX();
int y = (int) event.getY();
int xDiff = Math.abs(x - mTouchDownX);
int yDiff = Math.abs(y - mTouchDownY);
if (!mDockWindowTouchSlopExceeded) {
boolean touchSlopExceeded = !mIsVertical
? yDiff > mTouchSlop && yDiff > xDiff
: xDiff > mTouchSlop && xDiff > yDiff;
if (touchSlopExceeded && mDivider.getView().getWindowManagerProxy().getDockSide()
== DOCKED_INVALID) {
mDragMode = calculateDragMode();
mRecentsComponent.dockTopTask(mDragMode == DRAG_MODE_RECENTS);
if (mDragMode == DRAG_MODE_DIVIDER) {
mDivider.getView().startDragging();
}
mDockWindowTouchSlopExceeded = true;
return true;
}
} else {
if (mDragMode == DRAG_MODE_DIVIDER) {
mDivider.getView().resizeStack(
!mIsVertical ? (int) event.getRawY() : (int) event.getRawX());
} else if (mDragMode == DRAG_MODE_RECENTS) {
mRecentsComponent.onDraggingInRecents(event.getRawY());
}
}
return false;
}
private void handleDragActionUpEvent(MotionEvent event) {
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
if (mDockWindowTouchSlopExceeded) {
if (mDragMode == DRAG_MODE_DIVIDER) {
mDivider.getView().stopDragging(!mIsVertical
? (int) event.getRawY()
: (int) event.getRawX(),
!mIsVertical
? mVelocityTracker.getXVelocity()
: mVelocityTracker.getYVelocity());
} else if (mDragMode == DRAG_MODE_RECENTS) {
mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity());
}
}
mVelocityTracker.recycle();
mVelocityTracker = null;
}
private int calculateDragMode() {
if (mIsVertical && !mDivider.getView().isHorizontalDivision()) {
return DRAG_MODE_DIVIDER;
}
if (!mIsVertical && mDivider.getView().isHorizontalDivision()) {
return DRAG_MODE_DIVIDER;
}
return DRAG_MODE_RECENTS;
}
public boolean onTouchEvent(MotionEvent event) {
boolean result = mTaskSwitcherDetector.onTouchEvent(event);
if (mDockWindowEnabled) {
result |= handleDockWindowEvent(event);
}
return result;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float absVelX = Math.abs(velocityX);
float absVelY = Math.abs(velocityY);
boolean isValidFling = absVelX > mMinFlingVelocity &&
mIsVertical ? (absVelY > absVelX) : (absVelX > absVelY);
if (isValidFling) {
boolean showNext;
if (!mIsRTL) {
showNext = mIsVertical ? (velocityY < 0) : (velocityX < 0);
} else {
// In RTL, vertical is still the same, but horizontal is flipped
showNext = mIsVertical ? (velocityY < 0) : (velocityX > 0);
}
if (showNext) {
mRecentsComponent.showNextAffiliatedTask();
} else {
mRecentsComponent.showPrevAffiliatedTask();
}
}
return true;
}
}

View File

@@ -40,7 +40,6 @@ import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
@@ -48,6 +47,8 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonView;
@@ -78,7 +79,7 @@ public class NavigationBarView extends LinearLayout {
private Drawable mRecentIcon;
private Drawable mRecentLandIcon;
private NavigationBarViewTaskSwitchHelper mTaskSwitchHelper;
private NavigationBarGestureHelper mGestureHelper;
private DeadZone mDeadZone;
private final NavigationBarTransitions mBarTransitions;
@@ -180,7 +181,7 @@ public class NavigationBarView extends LinearLayout {
mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
mVertical = false;
mShowMenu = false;
mTaskSwitchHelper = new NavigationBarViewTaskSwitchHelper(context);
mGestureHelper = new NavigationBarGestureHelper(context);
getIcons(res);
@@ -191,8 +192,8 @@ public class NavigationBarView extends LinearLayout {
return mBarTransitions;
}
public void setBar(PhoneStatusBar phoneStatusBar) {
mTaskSwitchHelper.setBar(phoneStatusBar);
public void setComponents(RecentsComponent recentsComponent, Divider divider) {
mGestureHelper.setComponents(recentsComponent, divider);
}
public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
@@ -202,7 +203,7 @@ public class NavigationBarView extends LinearLayout {
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mTaskSwitchHelper.onTouchEvent(event)) {
if (mGestureHelper.onTouchEvent(event)) {
return true;
}
if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
@@ -213,7 +214,7 @@ public class NavigationBarView extends LinearLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return mTaskSwitchHelper.onInterceptTouchEvent(event);
return mGestureHelper.onInterceptTouchEvent(event);
}
public void abortCurrentGesture() {
@@ -488,7 +489,7 @@ public class NavigationBarView extends LinearLayout {
private void updateTaskSwitchHelper() {
boolean isRtl = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
mTaskSwitchHelper.setBarState(mVertical, isRtl);
mGestureHelper.setBarState(mVertical, isRtl);
}
@Override

View File

@@ -1,114 +0,0 @@
/*
* 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.systemui.statusbar.phone;
import android.content.Context;
import android.content.res.Resources;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
public class NavigationBarViewTaskSwitchHelper extends GestureDetector.SimpleOnGestureListener {
private BaseStatusBar mBar;
private boolean mIsVertical;
private boolean mIsRTL;
private final GestureDetector mTaskSwitcherDetector;
private final int mScrollTouchSlop;
private final int mMinFlingVelocity;
private int mTouchDownX;
private int mTouchDownY;
public NavigationBarViewTaskSwitchHelper(Context context) {
ViewConfiguration configuration = ViewConfiguration.get(context);
Resources r = context.getResources();
mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity();
mTaskSwitcherDetector = new GestureDetector(context, this);
}
public void setBar(BaseStatusBar phoneStatusBar) {
mBar = phoneStatusBar;
}
public void setBarState(boolean isVertical, boolean isRTL) {
mIsVertical = isVertical;
mIsRTL = isRTL;
}
public boolean onInterceptTouchEvent(MotionEvent event) {
// If we move more than a fixed amount, then start capturing for the
// task switcher detector
mTaskSwitcherDetector.onTouchEvent(event);
int action = event.getAction();
boolean intercepted = false;
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
mTouchDownX = (int) event.getX();
mTouchDownY = (int) event.getY();
break;
}
case MotionEvent.ACTION_MOVE: {
int x = (int) event.getX();
int y = (int) event.getY();
int xDiff = Math.abs(x - mTouchDownX);
int yDiff = Math.abs(y - mTouchDownY);
boolean exceededTouchSlop = !mIsVertical
? xDiff > mScrollTouchSlop && xDiff > yDiff
: yDiff > mScrollTouchSlop && yDiff > xDiff;
if (exceededTouchSlop) {
return true;
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
break;
}
return intercepted;
}
public boolean onTouchEvent(MotionEvent event) {
return mTaskSwitcherDetector.onTouchEvent(event);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float absVelX = Math.abs(velocityX);
float absVelY = Math.abs(velocityY);
boolean isValidFling = absVelX > mMinFlingVelocity &&
mIsVertical ? (absVelY > absVelX) : (absVelX > absVelY);
if (isValidFling) {
boolean showNext;
if (!mIsRTL) {
showNext = mIsVertical ? (velocityY < 0) : (velocityX < 0);
} else {
// In RTL, vertical is still the same, but horizontal is flipped
showNext = mIsVertical ? (velocityY < 0) : (velocityX > 0);
}
if (showNext) {
mBar.showNextAffiliatedTask();
} else {
mBar.showPreviousAffiliatedTask();
}
}
return true;
}
}

View File

@@ -117,6 +117,7 @@ import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.BaseStatusBar;
@@ -739,7 +740,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
context, R.layout.navigation_bar, null);
}
mNavigationBarView.setDisabledFlags(mDisabled1);
mNavigationBarView.setBar(this);
mNavigationBarView.setComponents(mRecents, getComponent(Divider.class));
mNavigationBarView.setOnVerticalChangedListener(
new NavigationBarView.OnVerticalChangedListener() {
@Override
@@ -1135,7 +1136,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public boolean onLongClick(View v) {
if (mRecents != null) {
mRecents.dockTopTask();
mRecents.dockTopTask(false /* draggingInRecents */);
return true;
}
return false;