目录
3.1 AbstractStateChangeTouchController.java关于手势上滑弹出抽屉式的相关功能分析
3.2 PortraitStatesTouchController.java关于竖屏显示拖拽app列表的相关方法
3.3 LandscapeEdgeSwipeController.java关于横屏上滑显示app的相关功能分析
1.概述
在产品开发中,Launcher3中定制的功能也是特别多的,有功能需求要求禁止抽屉式上滑显示app列表页,也就是去掉抽屉式功能,这就需要分析上滑功能怎么 实现的,然后禁用相关代码就可以了
2.禁止抽屉式上滑显示app列表页的核心代码
packages/apps/Launcher3/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
packages/apps/Launcher3/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
packages/apps/Launcher3/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java
3.禁止抽屉式上滑显示app列表页核心功能分析以及功能实现
3.1 AbstractStateChangeTouchController.java关于手势上滑弹出抽屉式的相关功能分析
public abstract class AbstractStateChangeTouchController
implements TouchController, SingleAxisSwipeDetector.Listener {
// Progress after which the transition is assumed to be a success in case user does not fling
public static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
/**
* Play an atomic recents animation when the progress from NORMAL to OVERVIEW reaches this.
*/
public static final float ATOMIC_OVERVIEW_ANIM_THRESHOLD = 0.5f;
protected final long ATOMIC_DURATION = getAtomicDuration();
protected final Launcher mLauncher;
protected final SingleAxisSwipeDetector mDetector;
protected final SingleAxisSwipeDetector.Direction mSwipeDirection;
private boolean mNoIntercept;
private boolean mIsLogContainerSet;
protected int mStartContainerType;
protected LauncherState mStartState;
protected LauncherState mFromState;
protected LauncherState mToState;
protected AnimatorPlaybackController mCurrentAnimation;
protected PendingAnimation mPendingAnimation;
private float mStartProgress;
// Ratio of transition process [0, 1] to drag displacement (px)
private float mProgressMultiplier;
private float mDisplacementShift;
private boolean mCanBlockFling;
private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
protected AnimatorSet mAtomicAnim;
// True if we want to resume playing atomic components when mAtomicAnim completes.
private boolean mScheduleResumeAtomicComponent;
private AutoPlayAtomicAnimationInfo mAtomicAnimAutoPlayInfo;
private boolean mPassedOverviewAtomicThreshold;
// mAtomicAnim plays the atomic components of the state animations when we pass the threshold.
// However, if we reinit to transition to a new state (e.g. OVERVIEW -> ALL_APPS) before the
// atomic animation finishes, we only control the non-atomic components so that we don't
// interfere with the atomic animation. When the atomic animation ends, we start controlling
// the atomic components as well, using this controller.
private AnimatorPlaybackController mAtomicComponentsController;
private LauncherState mAtomicComponentsTargetState = NORMAL;
private float mAtomicComponentsStartProgress;
public AbstractStateChangeTouchController(Launcher l, SingleAxisSwipeDetector.Direction dir) {
mLauncher = l;
mDetector = new SingleAxisSwipeDetector(l, this, dir);
mSwipeDirection = dir;
}
protected long getAtomicDuration() {
return 200;
}
/**
* Returns the state to go to from fromState given the drag direction. If there is no state in
* that direction, returns fromState. 拖拽方向以及显示内容
*/
protected abstract LauncherState getTargetState(LauncherState fromState,
boolean isDragTowardPositive);
//展示当前动画
protected abstract float initCurrentAnimation(@AnimationFlags int animComponents);
/**
* Returns the container that the touch started from when leaving NORMAL state.
*/
protected abstract int getLogContainerTypeForNormalState(MotionEvent ev);
// 开始从底部拖拽显示动画
@Override
public void onDragStart(boolean start, float startDisplacement) {
mStartState = mLauncher.getStateManager().getState();
mIsLogContainerSet = false;
if (mCurrentAnimation == null) {
mFromState = mStartState;
mToState = null;
cancelAnimationControllers();
reinitCurrentAnimation(false, mDetector.wasInitialTouchPositive());
mDisplacementShift = 0;
} else {
mCurrentAnimation.pause();
mStartProgress = mCurrentAnimation.getProgressFraction();
mAtomicAnimAutoPlayInfo = null;
if (mAtomicComponentsController != null) {
mAtomicComponentsController.pause();
}
}
mCanBlockFling = mFromState == NORMAL;
mFlingBlockCheck.unblockFling();
// Must be called after all the animation controllers have been paused
if (mToState == ALL_APPS || mToState == NORMAL) {
mLauncher.getAllAppsController().onDragStart(mToState == ALL_APPS);
}
}
@Override
public boolean onDrag(float displacement) {
float deltaProgress = mProgressMultiplier * (displacement - mDisplacementShift);
float progress = deltaProgress + mStartProgress;
updateProgress(progress);
boolean isDragTowardPositive = mSwipeDirection.isPositive(
displacement - mDisplacementShift);
if (progress <= 0) {
if (reinitCurrentAnimation(false, isDragTowardPositive)) {
mDisplacementShift = displacement;
if (mCanBlockFling) {
mFlingBlockCheck.blockFling();
}
}
} else if (progress >= 1) {
if (reinitCurrentAnimation(true, isDragTowardPositive)) {
mDisplacementShift = displacement;
if (mCanBlockFling) {
mFlingBlockCheck.blockFling();
}
}
} else {
mFlingBlockCheck.onEvent();
}
return true;
}
}
3.2 PortraitStatesTouchController.java关于竖屏显示拖拽app列表的相关方法
/**
* Touch controller for handling various state transitions in portrait UI.
*/
public class PortraitStatesTouchController extends AbstractStateChangeTouchController {
private static final String TAG = "PortraitStatesTouchCtrl";
/**
* The progress at which all apps content will be fully visible when swiping up from overview.
*/
protected static final float ALL_APPS_CONTENT_FADE_THRESHOLD = 0.08f;
/**
* The progress at which recents will begin fading out when swiping up from overview.
*/
private static final float RECENTS_FADE_THRESHOLD = 0.88f;
private final PortraitOverviewStateTouchHelper mOverviewPortraitStateTouchHelper;
private final InterpolatorWrapper mAllAppsInterpolatorWrapper = new InterpolatorWrapper();
private final boolean mAllowDragToOverview;
// If true, we will finish the current animation instantly on second touch.
private boolean mFinishFastOnSecondTouch;
public PortraitStatesTouchController(Launcher l, boolean allowDragToOverview) {
super(l, SingleAxisSwipeDetector.VERTICAL);
mOverviewPortraitStateTouchHelper = new PortraitOverviewStateTouchHelper(l);
mAllowDragToOverview = allowDragToOverview;
}
@Override
protected boolean canInterceptTouch(MotionEvent ev) {
if (mCurrentAnimation != null) {
if (mFinishFastOnSecondTouch) {
mCurrentAnimation.getAnimationPlayer().end();
}
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
if (ev.getY() >= allAppsController.getShiftRange() * allAppsController.getProgress()) {
// If we are already animating from a previous state, we can intercept as long as
// the touch is below the current all apps progress (to allow for double swipe).
return true;
}
// Otherwise, make sure everything is settled and don't intercept so they can scroll
// recents, dismiss a task, etc.
if (mAtomicAnim != null) {
mAtomicAnim.end();
}
return false;
}
if (mLauncher.isInState(ALL_APPS)) {
// In all-apps only listen if the container cannot scroll itself
if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
return false;
}
} else if (mLauncher.isInState(OVERVIEW)) {
if (!mOverviewPortraitStateTouchHelper.canInterceptTouch(ev)) {
return false;
}
} else {
// If we are swiping to all apps instead of overview, allow it from anywhere.
boolean interceptAnywhere = mLauncher.isInState(NORMAL) && !mAllowDragToOverview;
// For all other states, only listen if the event originated below the hotseat height
if (!interceptAnywhere && !isTouchOverHotseat(mLauncher, ev)) {
return false;
}
}
if (getTopOpenViewWithType(mLauncher, TYPE_ACCESSIBLE | TYPE_ALL_APPS_EDU) != null) {
return false;
}
return true;
}
// 获取上滑拖拽显示app列表
@Override
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "PortraitStatesTouchController.getTargetState");
}
if (fromState == ALL_APPS && !isDragTowardPositive) {
// Should swipe down go to OVERVIEW instead?
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
"PortraitStatesTouchController.getTargetState 1");
}
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(mLauncher)) {
// Don't allow swiping down to overview.
return NORMAL;
}
return TouchInteractionService.isConnected() ?
mLauncher.getStateManager().getLastState() : NORMAL;
} else if (fromState == OVERVIEW) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
"PortraitStatesTouchController.getTargetState 2");
}
LauncherState positiveDragTarget = ALL_APPS;
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(mLauncher)) {
// Don't allow swiping up to all apps.
positiveDragTarget = OVERVIEW;
}
return isDragTowardPositive ? positiveDragTarget : NORMAL;
} else if (fromState == NORMAL && isDragTowardPositive) { // 从底部上滑拖拽时,返回ALL_APPS列表展示出来
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
"PortraitStatesTouchController.getTargetState 3");
}
int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
return mAllowDragToOverview && TouchInteractionService.isConnected()
&& (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0
? OVERVIEW : ALL_APPS;
}
return fromState;
}
}
所以在竖屏的时候可以修改为:
@Override
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "PortraitStatesTouchController.getTargetState");
}
if (fromState == ALL_APPS && !isDragTowardPositive) {
// Should swipe down go to OVERVIEW instead?
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
"PortraitStatesTouchController.getTargetState 1");
}
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(mLauncher)) {
// Don't allow swiping down to overview.
return NORMAL;
}
return TouchInteractionService.isConnected() ?
mLauncher.getStateManager().getLastState() : NORMAL;
} else if (fromState == OVERVIEW) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
"PortraitStatesTouchController.getTargetState 2");
}
LauncherState positiveDragTarget = ALL_APPS;
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(mLauncher)) {
// Don't allow swiping up to all apps.
positiveDragTarget = OVERVIEW;
}
return isDragTowardPositive ? positiveDragTarget : NORMAL;
} else if (fromState == NORMAL && isDragTowardPositive) { // 从底部上滑拖拽时,返回ALL_APPS列表展示出来
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
"PortraitStatesTouchController.getTargetState 3");
}
int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
- return mAllowDragToOverview && TouchInteractionService.isConnected()
- && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0
- ? OVERVIEW : ALL_APPS;
+ return mAllowDragToOverview && TouchInteractionService.isConnected()
+ && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0
+ ? OVERVIEW : NORMAL;
}
return fromState;
}
}
3.3 LandscapeEdgeSwipeController.java关于横屏上滑显示app的相关功能分析
3.3 LandscapeEdgeSwipeController.java关于横屏上滑显示app的相关功能分析
/**
* Touch controller for handling edge swipes in landscape/seascape UI
*/
public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchController {
private static final String TAG = "LandscapeEdgeSwipeCtrl";
public LandscapeEdgeSwipeController(Launcher l) {
super(l, SingleAxisSwipeDetector.HORIZONTAL);
}
@Override
protected boolean canInterceptTouch(MotionEvent ev) {
if (mCurrentAnimation != null) {
// If we are already animating from a previous state, we can intercept.
return true;
}
if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
return false;
}
return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
}
// 上滑显示是否app列表 分析得知返回的是NORMAL 所以就不需要修改
@Override
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive;
return draggingFromNav ? OVERVIEW : NORMAL;
}
}