Add gesture to drag in recents from navigation bar
Change-Id: I672ed08f1019835891411b87e2d0de0290defff7
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user