android桌面滑动

桌面滑动

1、抽屉模式下,桌面上滑拉起全部应用

com/android/launcher3/allapps/AllAppsTransitionController.java

public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS = //AllApps 面板展开的动画
        new FloatProperty<AllAppsTransitionController>("allAppsProgress") {

            @Override
            public Float get(AllAppsTransitionController controller) {
                return controller.mProgress;
            }

            @Override
            public void setValue(AllAppsTransitionController controller, float progress) {
                controller.setProgress(progress);
            }
        };
public Animator createSpringAnimation(float... progressValues) {  //创建动画对象
    Animator animator = ObjectAnimator.ofFloat(this, ALL_APPS_PROGRESS, progressValues);
    animator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationCancel(Animator animation) {
            super.onAnimationCancel(animation);
            if (progressValues != null && progressValues.length > 0) {
                float lastValue = progressValues[progressValues.length - 1];
                Log.d("AllAppsTransitionController", "cancel spring animation, lastValue = " + lastValue);
                if (lastValue == 1f) {
                    ALL_APPS_PROGRESS.setValue(AllAppsTransitionController.this, 1f);
                }
            }
        }
    });
    return animator;
}

com/android/launcher3/allapps/AllAppsTransitionController.java

public void setProgress(float progress) { //更新拉动位移
    mProgress = progress;
    boolean fromBackground = mLauncher.getStateManager().getCurrentStableState() == BACKGROUND_APP;
    // Allow apps panel to shift the full screen if coming from another app.
    float shiftRange = fromBackground ? mLauncher.getDeviceProfile().heightPx : mShiftRange;
    getAppsViewProgressTranslationY().setValue(mProgress * shiftRange);
    mLauncher.onAllAppsTransition(1 - progress);

    boolean hasScrim = progress < NAV_BAR_COLOR_FORCE_UPDATE_THRESHOLD && mLauncher.getAppsView().getNavBarScrimHeight() > 0;
    mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, hasScrim ? mNavScrimFlag : 0);
}

调用createSpringAnimation的动画对象堆栈:

2025-02-27 01:21:00.997  9319-9319  AllAppsTra...Controller com.android.launcher D   setStateWithAnimation: java.lang.Throwable
   at com.android.launcher3.allapps.AllAppsTransitionController.setStateWithAnimation(AllAppsTransitionController.java:404)
   at com.android.launcher3.allapps.AllAppsTransitionController.setStateWithAnimation(AllAppsTransitionController.java:88)
   at com.android.launcher3.statemanager.StateManager.createAnimationToNewWorkspaceInternal(StateManager.java:411)
   at com.android.launcher3.statemanager.StateManager.createAnimationToNewWorkspace(StateManager.java:401)
   at com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.initCurrentAnimation(PortraitStatesTouchController.java:159)
   at com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController.initCurrentAnimation(NoButtonNavbarToOverviewTouchController.java:134)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.reinitCurrentAnimation(AbstractStateChangeTouchController.java:185)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.onDragStart(AbstractStateChangeTouchController.java:205)
   at com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController.onDragStart(NoButtonNavbarToOverviewTouchController.java:152)
   at com.android.launcher3.touch.SingleAxisSwipeDetector.reportDragStartInternal(SingleAxisSwipeDetector.java:175)
   at com.android.launcher3.touch.BaseSwipeDetector.reportDragStart(BaseSwipeDetector.java:254)
   at com.android.launcher3.touch.BaseSwipeDetector.setState(BaseSwipeDetector.java:226)
   at com.android.launcher3.touch.BaseSwipeDetector.onTouchEvent(BaseSwipeDetector.java:183)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.onControllerTouchEvent(AbstractStateChangeTouchController.java:151)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.onControllerInterceptTouchEvent(AbstractStateChangeTouchController.java:133)
   at com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.onControllerInterceptTouchEvent(PortraitStatesTouchController.java:211)
   at com.android.launcher3.views.BaseDragLayer.findControllerToHandleTouch(BaseDragLayer.java:201)
   at com.android.launcher3.views.BaseDragLayer.findActiveController(BaseDragLayer.java:212)
   at com.android.launcher3.views.BaseDragLayer.onInterceptTouchEvent(BaseDragLayer.java:177)
   at com.android.launcher3.dragndrop.DragLayer.onInterceptTouchEvent(DragLayer.java:628)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2656)
   at com.android.launcher3.views.BaseDragLayer.dispatchTouchEvent(BaseDragLayer.java:333)
   at com.android.launcher3.dragndrop.DragLayer.dispatchTouchEvent(DragLayer.java:260)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:468)
   at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:2018)
   at android.app.Activity.dispatchTouchEvent(Activity.java:4623)
   at com.android.launcher3.Launcher.dispatchTouchEvent(Launcher.java:2887)
   at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:426)
   at android.view.View.dispatchPointerEvent(View.java:16981)
   at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:8302)
   at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:8068)
   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7417)

更新进度

2025-02-27 01:07:16.115  9319-9319    com.android.launcher  D  setProgress: progress=0.8915926;  java.lang.Throwable
   at com.android.launcher3.allapps.AllAppsTransitionController.setProgress(AllAppsTransitionController.java:242)
   at com.android.launcher3.allapps.AllAppsTransitionController$1.setValue(AllAppsTransitionController.java:108)
   at com.android.launcher3.allapps.AllAppsTransitionController$1.setValue(AllAppsTransitionController.java:99)
   at android.animation.PropertyValuesHolder$FloatPropertyValuesHolder.setAnimatedValue(PropertyValuesHolder.java:1379)
   at android.animation.ObjectAnimator.animateValue(ObjectAnimator.java:977)
   at android.animation.ValueAnimator.setCurrentFraction(ValueAnimator.java:771)
   at com.android.launcher3.anim.AnimatorPlaybackController$Holder.setProgress(AnimatorPlaybackController.java:387)
   at com.android.launcher3.anim.AnimatorPlaybackController.setPlayFraction(AnimatorPlaybackController.java:248)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.updateProgress(AbstractStateChangeTouchController.java:278)
   at com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController.updateProgress(NoButtonNavbarToOverviewTouchController.java:176)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.onDrag(AbstractStateChangeTouchController.java:219)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.onDrag(AbstractStateChangeTouchController.java:271)
   at com.android.launcher3.touch.SingleAxisSwipeDetector$Listener.onDrag(SingleAxisSwipeDetector.java:207)
   at com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController.onDrag(NoButtonNavbarToOverviewTouchController.java:301)
   at com.android.launcher3.touch.SingleAxisSwipeDetector.reportDraggingInternal(SingleAxisSwipeDetector.java:180)
   at com.android.launcher3.touch.BaseSwipeDetector.reportDragging(BaseSwipeDetector.java:271)
   at com.android.launcher3.touch.BaseSwipeDetector.onTouchEvent(BaseSwipeDetector.java:186)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.onControllerTouchEvent(AbstractStateChangeTouchController.java:151)
   at com.android.launcher3.views.BaseDragLayer.onTouchEvent(BaseDragLayer.java:297)
   at com.android.launcher3.dragndrop.DragLayer.onTouchEvent(DragLayer.java:767)
   at android.view.View.performOnTouchCallback(View.java:16690)
   at android.view.View.dispatchTouchEvent(View.java:16647)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3123)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2789)
   at com.android.launcher3.views.BaseDragLayer.dispatchTouchEvent(BaseDragLayer.java:333)
   at com.android.launcher3.dragndrop.DragLayer.dispatchTouchEvent(DragLayer.java:260)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:468)
   at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:2018)
   at android.app.Activity.dispatchTouchEvent(Activity.java:4623)
   at com.android.launcher3.Launcher.dispatchTouchEvent(Launcher.java:2887)
   at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:426)
   at android.view.View.dispatchPointerEvent(View.java:16981)
   at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:8302)
   at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:8068)
   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:7417)
mLauncher.getStateManager().goToState(SPRING_LOADED);// 抽屉式下,从全部列表里,拖拽一个图标到桌面

2、底部边缘滑动,状态fromState : Hint

底部边缘上滑时状态会从Hint切到Overview

private boolean reinitCurrentAnimation(boolean reachedToState, boolean isDragTowardPositive) {
    LauncherState newFromState = mFromState == null ? mLauncher.getStateManager().getState() : reachedToState ? mToState : mFromState;
    LauncherState newToState = getTargetState(newFromState, isDragTowardPositive);

    onReinitToState(newToState);

    if (newFromState == mFromState && newToState == mToState || (newFromState == newToState)) {
        return false;
    }

    mFromState = newFromState;
    mToState = newToState;

    mStartProgress = 0;
    if (mCurrentAnimation != null) {
        mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
    }
    mProgressMultiplier = initCurrentAnimation();
    mCurrentAnimation.dispatchOnStart();
    return true;
}
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
    if (fromState == NORMAL && mDidTouchStartInNavBar) {
        return HINT_STATE;
    }
    return super.getTargetState(fromState, isDragTowardPositive);
}
2025-02-27 04:12:59.948 14674-14674 BaseDepthController     com.android.launcher                     D  setStateWithAnimation:  Hint;  java.lang.Throwable
   at com.android.launcher3.statehandlers.DepthController.setStateWithAnimation(DepthController.java:199)
   at com.android.launcher3.statehandlers.DepthController.setStateWithAnimation(DepthController.java:48)
   at com.android.launcher3.statemanager.StateManager.createAnimationToNewWorkspaceInternal(StateManager.java:411)
   at com.android.launcher3.statemanager.StateManager.createAnimationToNewWorkspace(StateManager.java:401)
   at com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.initCurrentAnimation(PortraitStatesTouchController.java:159)
   at com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController.initCurrentAnimation(NoButtonNavbarToOverviewTouchController.java:134)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.reinitCurrentAnimation(AbstractStateChangeTouchController.java:185)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.onDragStart(AbstractStateChangeTouchController.java:205)
   at com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController.onDragStart(NoButtonNavbarToOverviewTouchController.java:152)
   at com.android.launcher3.touch.SingleAxisSwipeDetector.reportDragStartInternal(SingleAxisSwipeDetector.java:175)
   at com.android.launcher3.touch.BaseSwipeDetector.reportDragStart(BaseSwipeDetector.java:254)
   at com.android.launcher3.touch.BaseSwipeDetector.setState(BaseSwipeDetector.java:226)
   at com.android.launcher3.touch.BaseSwipeDetector.onTouchEvent(BaseSwipeDetector.java:183)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.onControllerTouchEvent(AbstractStateChangeTouchController.java:151)
   at com.android.launcher3.touch.AbstractStateChangeTouchController.onControllerInterceptTouchEvent(AbstractStateChangeTouchController.java:133)
   at com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.onControllerInterceptTouchEvent(PortraitStatesTouchController.java:211)
   at com.android.launcher3.views.BaseDragLayer.findControllerToHandleTouch(BaseDragLayer.java:201)
   at com.android.launcher3.views.BaseDragLayer.proxyTouchEvent(BaseDragLayer.java:377)
   at com.android.quickstep.inputconsumers.OverviewInputConsumer.onMotionEvent(OverviewInputConsumer.java:91)
   at com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer.onMotionEvent(TaskbarUnstashInputConsumer.java:313)
   at com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer.onMotionEvent(NavHandleLongPressInputConsumer.java:119)
   at com.android.quickstep.TouchInteractionService.onInputEvent(TouchInteractionService.java:1193)
   at com.android.quickstep.TouchInteractionService.$r8$lambda$poRCSRM2asrdBx9AAqI9iNDwV_U(Unknown Source:0)
   at com.android.quickstep.TouchInteractionService$$ExternalSyntheticLambda11.onInputEvent(D8$$SyntheticClass:0)
   at com.android.systemui.shared.system.InputChannelCompat$InputEventReceiver$1.onInputEvent(InputChannelCompat.java:78)
   at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:295)
   at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
   at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:259)
   at android.view.BatchedInputEventReceiver.doConsumeBatchedInput(BatchedInputEventReceiver.java:91)
   at android.view.BatchedInputEventReceiver$BatchedInputRunnable.run(BatchedInputEventReceiver.java:130)
   at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1696)
   at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1705)
   at android.view.Choreographer.doCallbacks(Choreographer.java:1304)
   at android.view.Choreographer.doFrame(Choreographer.java:1226)
   at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1679)
   at android.os.Handler.handleCallback(Handler.java:959)
   at android.os.Handler.dispatchMessage(Handler.java:100)
   at android.os.Looper.loopOnce(Looper.java:233)

3、桌面图标拖拽

com/android/launcher3/touch/ItemLongClickListener.java

长按选中拖拽目标
1、长按桌面图标或者文件夹拖拽
private static boolean onWorkspaceItemLongClick(View v) {
    Launcher launcher = Launcher.getLauncher(v.getContext());
    if (!canStartDrag(launcher)) return false;
    if (!launcher.isInState(NORMAL)  && !launcher.isInState(OVERVIEW) && !launcher.isInState(EDIT_MODE)) {
        return false;
    }
    if (!(v.getTag() instanceof ItemInfo)) return false;

    launcher.setWaitingForResult(null);
    beginDrag(v, launcher, (ItemInfo) v.getTag(), new DragOptions());//长按监听,开始拖拽
    return true;
}
public static void beginDrag(View v, Launcher launcher, ItemInfo info,
        DragOptions dragOptions) {
    if (info.container >= 0) {
        Folder folder = Folder.getOpen(launcher);
        if (folder != null) {
            if (!folder.getIconsInReadingOrder().contains(v)) {
                folder.close(true);
            } else {
                folder.startDrag(v, dragOptions);
                return;
            }
        }
    }
    CellInfo longClickCellInfo = new CellInfo(v, info,   launcher.getCellPosMapper().mapModelToPresenter(info));
    launcher.getWorkspace().startDrag(longClickCellInfo, dragOptions);
}
2025-02-27 04:54:29.804 17403-17403  com.android.launcher     D  startDrag --1: null;  java.lang.Throwable
   at com.android.launcher3.dragndrop.DragController.startDrag(DragController.java:169)
   at com.android.launcher3.Workspace.beginDragShared(Workspace.java:2094)
   at com.android.launcher3.Workspace.beginDragShared(Workspace.java:1994)
   at com.android.launcher3.Workspace.startDrag(Workspace.java:1983)
   at com.android.launcher3.touch.ItemLongClickListener.beginDrag(ItemLongClickListener.java:126)
   at com.android.launcher3.touch.ItemLongClickListener.onWorkspaceItemLongClick(ItemLongClickListener.java:106)
   at com.android.launcher3.touch.ItemLongClickListener.$r8$lambda$ryNc3dw8A3h2eelScomTmWsFA9E(Unknown Source:0)
   at com.android.launcher3.touch.ItemLongClickListener$$ExternalSyntheticLambda0.onLongClick(D8$$SyntheticClass:0)
   at android.view.View.performLongClickInternal(View.java:8144)
   at android.view.View.performLongClick(View.java:8100)
   at android.widget.TextView.performLongClick(TextView.java:15111)
   at android.view.View.performLongClick(View.java:8118)
   at android.view.View$CheckForLongPress.run(View.java:31538)
   at android.os.Handler.handleCallback(Handler.java:959)
   at android.os.Handler.dispatchMessage(Handler.java:100)
   at android.os.Looper.loopOnce(Looper.java:233)
   at android.os.Looper.loop(Looper.java:318)
   at android.app.ActivityThread.main(ActivityThread.java:9318)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:892)
2、拖拽桌面widget
private static boolean onWidgetItemLongClick(WidgetCell v) {
    // Get the widget preview as the drag representation
    WidgetImageView image = v.getWidgetView();
    Launcher launcher = Launcher.getLauncher(v.getContext());
    DragSource dragSource = (target, dragObject, success) -> { };

    // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
    // we abort the drag.
    if (image.getDrawable() == null && v.getAppWidgetHostViewPreview() == null) {
        return false;
    }
    PendingItemDragHelper dragHelper = new PendingItemDragHelper(v);
    // RemoteViews are being rendered in AppWidgetHostView in WidgetCell. And thus, the scale of
    // RemoteViews is equivalent to the AppWidgetHostView scale.
    dragHelper.setRemoteViewsPreview(v.getRemoteViewsPreview(), v.getAppWidgetHostViewScale());
    dragHelper.setAppWidgetHostViewPreview(v.getAppWidgetHostViewPreview());

    if (image.getDrawable() != null) {
        int[] loc = new int[2];
        launcher.getDragLayer().getLocationInDragLayer(image, loc);
        dragHelper.startDrag(image.getBitmapBounds(), image.getDrawable().getIntrinsicWidth(),
                image.getWidth(), new Point(loc[0], loc[1]), dragSource, new DragOptions());
    } else {
        NavigableAppWidgetHostView preview = v.getAppWidgetHostViewPreview();
        int[] loc = new int[2];
        launcher.getDragLayer().getLocationInDragLayer(preview, loc);
        Rect r = new Rect();
        preview.getWorkspaceVisualDragBounds(r);
        dragHelper.startDrag(r, preview.getMeasuredWidth(), preview.getMeasuredWidth(),
                new Point(loc[0], loc[1]), dragSource, new DragOptions());
    }
    return true;
}
2025-02-27 05:08:54.716 17403-17403   com.android.launcher  D  startDrag --1: null;  java.lang.Throwable
   at com.android.launcher3.dragndrop.DragController.startDrag(DragController.java:169)
   at com.android.launcher3.Workspace.beginDragShared(Workspace.java:2094)
   at com.android.launcher3.Workspace.beginDragShared(Workspace.java:1994)
   at com.android.launcher3.Workspace.startDrag(Workspace.java:1983)
   at com.android.launcher3.touch.ItemLongClickListener.beginDrag(ItemLongClickListener.java:126)
   at com.android.launcher3.touch.ItemLongClickListener.onWorkspaceItemLongClick(ItemLongClickListener.java:106)
   at com.android.launcher3.touch.ItemLongClickListener.$r8$lambda$ryNc3dw8A3h2eelScomTmWsFA9E(Unknown Source:0)
   at com.android.launcher3.touch.ItemLongClickListener$$ExternalSyntheticLambda0.onLongClick(D8$$SyntheticClass:0)
   at android.view.View.performLongClickInternal(View.java:8144)
   at android.view.View.performLongClick(View.java:8100)
   at com.android.launcher3.widget.LauncherAppWidgetHostView.onLongClick(LauncherAppWidgetHostView.java:122)
   at com.android.launcher3.CheckLongPressHelper.triggerLongPress(CheckLongPressHelper.java:158)
   at com.android.launcher3.CheckLongPressHelper.$r8$lambda$3FGJlMeB-D64lryLpjvbJwllqTg(Unknown Source:0)
   at com.android.launcher3.CheckLongPressHelper$$ExternalSyntheticLambda1.run(D8$$SyntheticClass:0)
   at android.os.Handler.handleCallback(Handler.java:959)
   at android.os.Handler.dispatchMessage(Handler.java:100)
   at android.os.Looper.loopOnce(Looper.java:233)
   at android.os.Looper.loop(Looper.java:318)
   at android.app.ActivityThread.main(ActivityThread.java:9318)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:892)
3、拖拽所有应用列表中的图标
private static boolean onAllAppsItemLongClick(View view) {
    if (view instanceof WidgetCell wc) {
        return onWidgetItemLongClick(wc);
    }
    view.cancelLongPress();
    View v = (view instanceof BubbleTextHolder)  ? ((BubbleTextHolder) view).getBubbleText() : view;
    Launcher launcher = Launcher.getLauncher(v.getContext());
    if (!canStartDrag(launcher)) return false;
    // When we have exited all apps or are in transition, disregard long clicks
    if (!launcher.isInState(ALL_APPS) && !launcher.isInState(OVERVIEW)) return false;
    if (launcher.getWorkspace().isSwitchingState()) return false;

    StatsLogger logger = launcher.getStatsLogManager().logger();
    if (v.getTag() instanceof ItemInfo itemInfo) {
        if (itemInfo instanceof PrivateSpaceInstallAppButtonInfo) {
            return false;
        }
        logger.withItemInfo((ItemInfo) v.getTag());
    }
    logger.log(LAUNCHER_ALLAPPS_ITEM_LONG_PRESSED);

    // Start the drag
    final DragController dragController = launcher.getDragController();
    dragController.addDragListener(new DragController.DragListener() {
        @Override
        public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
            v.setVisibility(INVISIBLE);
        }
        @Override
        public void onDragEnd() {
            v.setVisibility(VISIBLE);
            dragController.removeDragListener(this);
        }
    });

    launcher.getWorkspace().beginDragShared(v, launcher.getAppsView(), new DragOptions());
    return false;
}
2025-02-27 05:11:46.428 17403-17403   com.android.launcher  D  startDrag --1: null;  java.lang.Throwable
   at com.android.launcher3.dragndrop.DragController.startDrag(DragController.java:169)
   at com.android.launcher3.Workspace.beginDragShared(Workspace.java:2094)
   at com.android.launcher3.Workspace.beginDragShared(Workspace.java:1994)
   at com.android.launcher3.touch.ItemLongClickListener.onAllAppsItemLongClick(ItemLongClickListener.java:210)
   at com.android.launcher3.touch.ItemLongClickListener.$r8$lambda$fWCCoyjZXwIcAdgbQhoEQV6IR3o(Unknown Source:0)
   at com.android.launcher3.touch.ItemLongClickListener$$ExternalSyntheticLambda1.onLongClick(D8$$SyntheticClass:0)
   at android.view.View.performLongClickInternal(View.java:8144)
   at android.view.View.performLongClick(View.java:8100)
   at android.widget.TextView.performLongClick(TextView.java:15111)
   at android.view.View.performLongClick(View.java:8118)
   at android.view.View$CheckForLongPress.run(View.java:31538)
   at android.os.Handler.handleCallback(Handler.java:959)
   at android.os.Handler.dispatchMessage(Handler.java:100)
   at android.os.Looper.loopOnce(Looper.java:233)
   at android.os.Looper.loop(Looper.java:318)
   at android.app.ActivityThread.main(ActivityThread.java:9318)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:892)
拖拽过程
1、开始拖拽startDrag

com/android/launcher3/dragndrop/DragController.java

protected abstract DragView startDrag( //开始拖拽
        @Nullable Drawable drawable,
        @Nullable View view,
        DraggableView originalView,
        int dragLayerX,
        int dragLayerY,
        DragSource source,
        ItemInfo dragInfo,
        Rect dragRegion,
        float initialDragViewScale,
        float dragViewScaleOnDrop,
        DragOptions options);
2、拖拽准备工作onDragStart

onDragStart 方法是在启动拖放操作时调用的,主要负责处理拖放开始时的一系列初始化和准备工作,包括确保拖放事件顺序、标记单元格状态、更新子视图层状态、添加额外空屏幕、调整页面以及切换 Launcher 状态等,同时记录拖放开始的日志信息。

public void onDragStart(DragObject dragObject, DragOptions options) {
    if (ENFORCE_DRAG_EVENT_ORDER) {
        enforceDragParity("onDragStart", 0, 0);
    }
    if (mDragInfo != null && mDragInfo.cell != null) {
        CellLayout layout = (CellLayout) (mDragInfo.cell instanceof LauncherAppWidgetHostView
                ? dragObject.dragView.getContentViewParent().getParent()
                : mDragInfo.cell.getParent().getParent());
         //调用 layout.markCellsAsUnoccupiedForView 方法将该视图占用的单元格标记为未占用,以便在拖放过程中可以重新安排其他视图。
        layout.markCellsAsUnoccupiedForView(mDragInfo.cell);
    }

    updateChildrenLayersEnabled();

    // Do not add a new page if it is a accessible drag which was not started by the workspace.
    // We do not support accessibility drag from other sources and instead provide a direct
    // action for move/add to homescreen.
    // When a accessible drag is started by the folder, we only allow rearranging withing the
    // folder.
    boolean addNewPage = !(options.isAccessibleDrag && dragObject.dragSource != this);
    if (addNewPage) {
        mDeferRemoveExtraEmptyScreen = false;
       //调用 addExtraEmptyScreenOnDrag 方法添加额外的空屏幕。
        addExtraEmptyScreenOnDrag(dragObject);

        if (dragObject.dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
                && dragObject.dragSource != this) {
            // When dragging a widget from different source, move to a page which has
            // enough space to place this widget (after rearranging/resizing). We special case
            // widgets as they cannot be placed inside a folder.
            // Start at the current page and search right (on LTR) until finding a page with
            // enough space. Since an empty screen is the furthest right, a page must be found.
            int currentPage = getDestinationPage();
            for (int pageIndex = currentPage; pageIndex < getPageCount(); pageIndex++) {
                CellLayout page = (CellLayout) getPageAt(pageIndex);
                if (page.hasReorderSolution(dragObject.dragInfo)) {
                    setCurrentPage(pageIndex);
                    break;
                }
            }
        }
    }

    if (!mLauncher.isInState(EDIT_MODE)) {
        mLauncher.getStateManager().goToState(SPRING_LOADED);
    }
    mStatsLogManager.logger().withItemInfo(dragObject.dragInfo)
            .withInstanceId(dragObject.logInstanceId)
            .log(LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED);
}
private void addExtraEmptyScreenOnDrag(DragObject dragObject) {
    boolean lastChildOnScreen = false;
    boolean childOnFinalScreen = false;

    if (mDragSourceInternal != null) {
        int dragSourceChildCount = mDragSourceInternal.getChildCount();

        // If the icon was dragged from Hotseat, there is no page pair
        if (isTwoPanelEnabled() && !(mDragSourceInternal.getParent() instanceof Hotseat)) {
            int pagePairScreenId = getScreenPair(getCellPosMapper().mapModelToPresenter(
                    dragObject.dragInfo).screenId);
            CellLayout pagePair = mWorkspaceScreens.get(pagePairScreenId);
            dragSourceChildCount += pagePair.getShortcutsAndWidgets().getChildCount();
        }

        // When the drag view content is a LauncherAppWidgetHostView, we should increment the
        // drag source child count by 1 because the widget in drag has been detached from its
        // original parent, ShortcutAndWidgetContainer, and reattached to the DragView.
        if (dragObject.dragView.getContentView() instanceof LauncherAppWidgetHostView) {
            dragSourceChildCount++;
        }

        if (dragSourceChildCount == 1) {
            lastChildOnScreen = true;
        }
        CellLayout cl = (CellLayout) mDragSourceInternal.getParent();
        if (!FOLDABLE_SINGLE_PAGE.get() && getLeftmostVisiblePageForIndex(indexOfChild(cl))
                == getLeftmostVisiblePageForIndex(getPageCount() - 1)) {
            childOnFinalScreen = true;
        }
    }

    // If this is the last item on the final screen
    if (lastChildOnScreen && childOnFinalScreen) {
        return;
    }

    forEachExtraEmptyPageId(extraEmptyPageId -> {
        if (!mWorkspaceScreens.containsKey(extraEmptyPageId)) {
            insertNewWorkspaceScreen(extraEmptyPageId);//添加新一屏
        }
    });
}


public void insertNewWorkspaceScreen(int screenId) {
    insertNewWorkspaceScreen(screenId, getChildCount());
}

public CellLayout insertNewWorkspaceScreen(int screenId, int insertIndex) { //添加新一屏幕的workspace
    if (mWorkspaceScreens.containsKey(screenId)) {
        throw new RuntimeException("Screen id " + screenId + " already exists!");
    }

    // Inflate the cell layout, but do not add it automatically so that we can get the newly
    // created CellLayout.
    DeviceProfile dp = mLauncher.getDeviceProfile();
    CellLayout newScreen;
    if (FOLDABLE_SINGLE_PAGE.get() && dp.isTwoPanels) {
        newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
                R.layout.workspace_screen_foldable, this, false /* attachToRoot */);
    } else {
        newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(    //创建新的CellLayout容器
                R.layout.workspace_screen, this, false /* attachToRoot */);
    }
    newScreen.setCellLayoutContainer(this);

    mWorkspaceScreens.put(screenId, newScreen);
    mScreenOrder.add(insertIndex, screenId);
    addView(newScreen, insertIndex); //新的CellLayout容器添加到workspace中
    mStateTransitionAnimation.applyChildState(
            mLauncher.getStateManager().getState(), newScreen, insertIndex);

    updatePageScrollValues();
    updateCellLayoutMeasures();
    return newScreen;
}

3、拖拽过程中onDragOver

onDragOver 方法是用于处理拖放操作时,当被拖动的对象经过某个可放置区域时的逻辑。其核心功能是根据当前的拖放状态、被拖动对象的信息以及目标布局,确定合适的放置位置,处理文件夹相关反馈,进行重新排序,并根据不同情况恢复临时状态。

public void onDragOver(DragObject d) {
    // Skip drag over events while we are dragging over side pages
    if (!transitionStateShouldAllowDrop()) return;

    ItemInfo item = d.dragInfo;
    if (item == null) {
        return;
    }

    // Ensure that we have proper spans for the item that we are dropping
    if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");
    mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);

    final View child = (mDragInfo == null) ? null : mDragInfo.cell;
    if (setDropLayoutForDragObject(d, mDragViewVisualCenter[0], mDragViewVisualCenter[1])) {
        if (mDragTargetLayout == null || mLauncher.isHotseatLayout(mDragTargetLayout)) {
            mSpringLoadedDragController.cancel();
        } else {
            mSpringLoadedDragController.setAlarm(mDragTargetLayout);
        }
    }

    // Handle the drag over
    if (mDragTargetLayout != null) {
        // We want the point to be mapped to the dragTarget.
        mapPointFromDropLayout(mDragTargetLayout, mDragViewVisualCenter);

        int minSpanX = item.spanX;
        int minSpanY = item.spanY;
        if (item.minSpanX > 0 && item.minSpanY > 0) {
            minSpanX = item.minSpanX;
            minSpanY = item.minSpanY;
        }

        mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX, item.spanY,mDragTargetLayout, mTargetCell);
        int reorderX = mTargetCell[0];
        int reorderY = mTargetCell[1];

        setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);

        float targetCellDistance = mDragTargetLayout.getDistanceFromWorkspaceCellVisualCenter(mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);
      // 拖动图标覆盖旁边图标位置,会创建文件夹动画,以及加入文件夹等,处理文件夹反馈
        manageFolderFeedback(targetCellDistance, d);

        boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,
                item.spanY, child, mTargetCell);
       // 拖动图标挤占旁边图标位置,位置调整和动画等,处理拖放过程中的重新排序操作。
        manageReorderOnDragOver(d, targetCellDistance, nearestDropOccupied, minSpanX, minSpanY, reorderX, reorderY);

        if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER ||
                !nearestDropOccupied) {
            if (mDragTargetLayout != null) {
                mDragTargetLayout.revertTempState();
            }
        }
    }
}
private void manageFolderFeedback(float distance, DragObject dragObject) {
    if (distance > mDragTargetLayout.getFolderCreationRadius(mTargetCell)) {
        if ((mDragMode == DRAG_MODE_ADD_TO_FOLDER
                || mDragMode == DRAG_MODE_CREATE_FOLDER)) {
            setDragMode(DRAG_MODE_NONE);
        }
        return;
    }

    mDragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);
    ItemInfo info = dragObject.dragInfo;
    boolean userFolderPending = willCreateUserFolder(info, mDragOverView, false);//是否创建新的文件夹
    if (mDragMode == DRAG_MODE_NONE && userFolderPending) {

        mFolderCreateBg = new PreviewBackground(getContext());
        mFolderCreateBg.setup(mLauncher, mLauncher, null, mDragOverView.getMeasuredWidth(), mDragOverView.getPaddingTop());//初始化背景

        // The full preview background should appear behind the icon
        mFolderCreateBg.isClipping = false;

        if (mDragOverView instanceof AppPairIcon api) {
            api.getIconDrawableArea().onTemporaryContainerChange(DISPLAY_FOLDER);
        }

        mFolderCreateBg.animateToAccept(mDragTargetLayout, mTargetCell[0], mTargetCell[1]);// 拖拽图标交叠时,下面图标会创建文件夹背景
        mDragTargetLayout.clearDragOutlines();
        setDragMode(DRAG_MODE_CREATE_FOLDER);

        if (dragObject.stateAnnouncer != null) {
            dragObject.stateAnnouncer.announce(WorkspaceAccessibilityHelper.getDescriptionForDropOver(mDragOverView, getContext()));
        }
        return;
    }

    boolean willAddToFolder = willAddToExistingUserFolder(info, mDragOverView); //是否添加到已存在的文件夹
    if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {
        mDragOverFolderIcon = ((FolderIcon) mDragOverView);
        mDragOverFolderIcon.onDragEnter(info);
        if (mDragTargetLayout != null) {
            mDragTargetLayout.clearDragOutlines();
        }
        setDragMode(DRAG_MODE_ADD_TO_FOLDER);

        if (dragObject.stateAnnouncer != null) {
            dragObject.stateAnnouncer.announce(WorkspaceAccessibilityHelper.getDescriptionForDropOver(mDragOverView, getContext()));
        }
        return;
    }

    if (mDragMode == DRAG_MODE_ADD_TO_FOLDER && !willAddToFolder) {
        setDragMode(DRAG_MODE_NONE);
    }
    if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) {
        setDragMode(DRAG_MODE_NONE);
    }
}

拖拽时重新排序图标

Workspace.java#manageReorderOnDragOver ----- CellLayout.java#performReorder------CellLayout.java#animateItemsToSolution-----CellLayout.java#animateChildToPosition

4、拖拽抬手后onDrop

抬手后,执行onDrop,找一个合适的放置拖拽的图标

public void onDrop(final DragObject d, DragOptions options) {
    mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
    CellLayout dropTargetLayout = mDropToLayout;

    // We want the point to be mapped to the dragTarget.
    if (dropTargetLayout != null) {
        mapPointFromDropLayout(dropTargetLayout, mDragViewVisualCenter);
    }

    boolean droppedOnOriginalCell = false;

    boolean snappedToNewPage = false;
    boolean resizeOnDrop = false;
    Runnable onCompleteRunnable = null;
    if (d.dragSource != this || mDragInfo == null) {
        final int[] touchXY = new int[]{(int) mDragViewVisualCenter[0],  (int) mDragViewVisualCenter[1]};
        onDropExternal(touchXY, dropTargetLayout, d);
    } else {
        final View cell = mDragInfo.cell;
        boolean droppedOnOriginalCellDuringTransition = false;

        if (dropTargetLayout != null && !d.cancelled) {
            // Move internally
            boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);
            boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
            int container = hasMovedIntoHotseat ?
                    LauncherSettings.Favorites.CONTAINER_HOTSEAT :
                    LauncherSettings.Favorites.CONTAINER_DESKTOP;
            int screenId = (mTargetCell[0] < 0) ? mDragInfo.screenId : getCellLayoutId(dropTargetLayout);
            int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
            int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
            // First we find the cell nearest to point at which the item is
            // dropped, without any consideration to whether there is an item there.
           // 找到最近的空闲单元格,并处理小部件调整大小的情况。
            mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)      // 找到最近的单元格
                    mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);
            float distance = dropTargetLayout.getDistanceFromWorkspaceCellVisualCenter(
                    mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);

            // If the item being dropped is a shortcut and the nearest drop
            // cell also contains a shortcut, then create a folder with the two shortcuts.
            if (createUserFolderIfNecessary(cell, container, dropTargetLayout, mTargetCell, distance, false, d) // 创建或添加到文件夹
                    || addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,  distance, d, false)) {
                if (!mLauncher.isInState(EDIT_MODE)) {
                    mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
                }
                return;
            }

            // Aside from the special case where we're dropping a shortcut onto a shortcut,
            // we need to find the nearest cell location that is vacant
            ItemInfo item = d.dragInfo;
            int minSpanX = item.spanX;
            int minSpanY = item.spanY;
            if (item.minSpanX > 0 && item.minSpanY > 0) {
                minSpanX = item.minSpanX;
                minSpanY = item.minSpanY;
            }

            CellPos originalPresenterPos = getCellPosMapper().mapModelToPresenter(item);
            droppedOnOriginalCell = originalPresenterPos.screenId == screenId
                    && item.container == container
                    && originalPresenterPos.cellX == mTargetCell[0]
                    && originalPresenterPos.cellY == mTargetCell[1];
            droppedOnOriginalCellDuringTransition = droppedOnOriginalCell && mIsSwitchingState;

            // When quickly moving an item, a user may accidentally rearrange their
            // workspace. So instead we move the icon back safely to its original position.
            boolean returnToOriginalCellToPreventShuffling = !isFinishedSwitchingState()
                    && !droppedOnOriginalCellDuringTransition && !dropTargetLayout.isRegionVacant(mTargetCell[0], mTargetCell[1], spanX, spanY);
            int[] resultSpan = new int[2];
            if (returnToOriginalCellToPreventShuffling) {
                mTargetCell[0] = mTargetCell[1] = -1;
            } else {
                mTargetCell = dropTargetLayout.performReorder((int) mDragViewVisualCenter[0],   //mTargetCell 拖拽放置的目标位置
                        (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
                        cell, mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);
            }

            boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;//mTargetCell 数值大于0,找到了合适的目标位置

            // if the widget resizes on drop
            if (foundCell && (cell instanceof AppWidgetHostView) &&  (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) {
                resizeOnDrop = true;
                item.spanX = resultSpan[0];
                item.spanY = resultSpan[1];
                AppWidgetHostView awhv = (AppWidgetHostView) cell;
                WidgetSizes.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0], resultSpan[1]);
            }
          // 处理页面切换和视图重新布局
            if (foundCell) {
                int targetScreenIndex = getPageIndexForScreenId(screenId);
                int snapScreen = getLeftmostVisiblePageForIndex(targetScreenIndex);
                // On large screen devices two pages can be shown at the same time, and snap
                // isn't needed if the source and target screens appear at the same time
                if (snapScreen != mCurrentPage && !hasMovedIntoHotseat) {
                    snapToPage(snapScreen);
                    snappedToNewPage = true;
                }
                final ItemInfo info = (ItemInfo) cell.getTag();
                if (hasMovedLayouts) {
                    // Reparent the view
                    CellLayout parentCell = getParentCellLayoutForView(cell);
                    if (parentCell != null) {
                        parentCell.removeView(cell);
                    } else if (mDragInfo.cell instanceof LauncherAppWidgetHostView) {
                        d.dragView.detachContentView(/* reattachToPreviousParent= */ false);
                    } else if (FeatureFlags.IS_STUDIO_BUILD) {
                        throw new NullPointerException("mDragInfo.cell has null parent");
                    }
                    addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1],  info.spanX, info.spanY);// 添加拖动的元素到screenId 的workpace中
                }

                // update the item's position after drop
                CellLayoutLayoutParams lp = (CellLayoutLayoutParams) cell.getLayoutParams();
                lp.setTmpCellX(mTargetCell[0]);
                lp.setCellX(mTargetCell[0]);
                lp.setTmpCellY(mTargetCell[1]);
                lp.setCellY(mTargetCell[1]);
                lp.cellHSpan = item.spanX;
                lp.cellVSpan = item.spanY;
                lp.isLockedToGrid = true;

                if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && cell instanceof LauncherAppWidgetHostView) {
                    // We post this call so that the widget has a chance to be placed in its final location
                    onCompleteRunnable = getWidgetResizeFrameRunnable(options, (LauncherAppWidgetHostView) cell, dropTargetLayout);
                }
                mLauncher.getModelWriter().modifyItemInDatabase(info, container, screenId,  lp.getCellX(), lp.getCellY(), item.spanX, item.spanY);
            } else {
                if (!returnToOriginalCellToPreventShuffling) {
                    onNoCellFound(dropTargetLayout, d.dragInfo, d.logInstanceId);
                }
                if (mDragInfo.cell instanceof LauncherAppWidgetHostView) {
                    d.dragView.detachContentView(/* reattachToPreviousParent= */ true);
                }
                
                //如果未找到合适的单元格,处理返回原始位置的逻辑。
                // If we can't find a drop location, we return the item to its original position
                CellLayoutLayoutParams lp = (CellLayoutLayoutParams) cell.getLayoutParams();
                mTargetCell[0] = lp.getCellX();
                mTargetCell[1] = lp.getCellY();
                CellLayout layout = (CellLayout) cell.getParent().getParent();
                layout.markCellsAsOccupiedForView(cell);
            }
        } else {
           //   处理拖放取消的情况。
            // When drag is cancelled, reattach content view back to its original parent.
            if (cell instanceof LauncherAppWidgetHostView) {
                d.dragView.detachContentView(/* reattachToPreviousParent= */ true);
                final CellLayout cellLayout = getParentCellLayoutForView(cell);
                boolean pageIsVisible = isVisible(cellLayout);
                if (pageIsVisible) {
                    onCompleteRunnable = getWidgetResizeFrameRunnable(options,  (LauncherAppWidgetHostView) cell, cellLayout);
                }
            }
        }

        final CellLayout parent = (CellLayout) cell.getParent().getParent();
        if (d.dragView.hasDrawn()) {
            if (droppedOnOriginalCellDuringTransition) {
           //  如果拖放视图已经绘制,根据不同情况执行动画,包括回到原始位置、小部件动画和普通视图动画。
                // Animate the item to its original position, while simultaneously exiting
                // spring-loaded mode so the page meets the icon where it was picked up.
                final RunnableList callbackList = new RunnableList();
                final Runnable onCompleteCallback = onCompleteRunnable;
                LauncherState currentState = mLauncher.getStateManager().getState();
                mLauncher.getDragController().animateDragViewToOriginalPosition(
                        /* onComplete= */ callbackList::executeAllAndDestroy, cell,
                        currentState.getTransitionDuration(mLauncher, true /* isToState */));
                if (!mLauncher.isInState(EDIT_MODE)) {
                    mLauncher.getStateManager().goToState(NORMAL, /* delay= */ 0,
                            onCompleteCallback == null
                                    ? null
                                    : forSuccessCallback(
                                            () -> callbackList.add(onCompleteCallback)));
                } else if (onCompleteCallback != null) {
                    forSuccessCallback(() -> callbackList.add(onCompleteCallback));
                }
                mLauncher.getDropTargetBar().onDragEnd();
                parent.onDropChild(cell);
                return;
            }
            final ItemInfo info = (ItemInfo) cell.getTag();
            boolean isWidget = info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
                    || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
            if (isWidget && dropTargetLayout != null) {
                // animate widget to a valid place
                int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :   ANIMATE_INTO_POSITION_AND_DISAPPEAR;
                animateWidgetDrop(info, parent, d.dragView, null, animationType, cell, false);
            } else {
                int duration = snappedToNewPage ? ADJACENT_SCREEN_DROP_DURATION : -1;
                mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,  this);
            }
        } else {
            d.deferDragViewCleanupPostAnimation = false;
            cell.setVisibility(VISIBLE);
        }
        parent.onDropChild(cell);

        if (!mLauncher.isInState(EDIT_MODE)) {
            mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY,
                    onCompleteRunnable == null ? null : forSuccessCallback(onCompleteRunnable));
        } else if (onCompleteRunnable != null) {
            forSuccessCallback(onCompleteRunnable);
        }
        mStatsLogManager.logger().withItemInfo(d.dragInfo).withInstanceId(d.logInstanceId)
                .log(LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED);
    }

    if (d.stateAnnouncer != null && !droppedOnOriginalCell) {
        d.stateAnnouncer.completeAction(R.string.item_moved);
    }
}
2025-02-27 05:28:33.800 18524-18524 Launcher.Workspace    com.android.launcher    D  onDrop: java.lang.Throwable
   at com.android.launcher3.Workspace.onDrop(Workspace.java:2400)
   at com.android.launcher3.dragndrop.DragController.drop(DragController.java:562)
   at com.android.launcher3.dragndrop.DragController.onDriverDragEnd(DragController.java:409)
   at com.android.launcher3.dragndrop.DragDriver$InternalDragDriver.onTouchEvent(DragDriver.java:195)
   at com.android.launcher3.dragndrop.DragController.onControllerTouchEvent(DragController.java:456)
   at com.android.launcher3.views.BaseDragLayer.onTouchEvent(BaseDragLayer.java:297)
   at com.android.launcher3.dragndrop.DragLayer.onTouchEvent(DragLayer.java:767)
   at android.view.View.performOnTouchCallback(View.java:16690)
   at android.view.View.dispatchTouchEvent(View.java:16647)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3123)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2789)
   at com.android.launcher3.views.BaseDragLayer.dispatchTouchEvent(BaseDragLayer.java:333)
   at com.android.launcher3.dragndrop.DragLayer.dispatchTouchEvent(DragLayer.java:260)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3129)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2803)
   at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:468)
   at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:2018)
   at android.app.Activity.dispatchTouchEvent(Activity.java:4623)
   at com.android.launcher3.Launcher.dispatchTouchEvent(Launcher.java:2887)
   at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:426)
   at android.view.View.dispatchPointerEvent(View.java:16981)

4、进入多任务桌面图标隐藏逻辑

WorkspaceStateTransitionAnimation.java#setWorkspaceProperty 桌面区域属性动画

private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter, StateAnimationConfig config) {
    ScaleAndTranslation scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
    ScaleAndTranslation hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation(mLauncher);
    mNewScale = scaleAndTranslation.scale;
    PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
    final int childCount = mWorkspace.getChildCount();
    for (int i = 0; i < childCount; i++) {
        applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider, propertySetter, config);//针对桌面的各个元素逐一做隐藏动画 alpha,scale,fade
    }

    int elements = state.getVisibleElements(mLauncher);
    Hotseat hotseat = mWorkspace.getHotseat();
    Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
    LauncherState fromState = mLauncher.getStateManager().getState();

    boolean shouldSpring = propertySetter instanceof PendingAnimation && fromState == HINT_STATE && state == NORMAL;
    if (shouldSpring) { // workpace是否做弹簧动画
        ((PendingAnimation) propertySetter).add(getSpringScaleAnimator(mLauncher, mWorkspace, mNewScale, WORKSPACE_SCALE_PROPERTY));
    } else {
        propertySetter.setFloat(mWorkspace, WORKSPACE_SCALE_PROPERTY, mNewScale, scaleInterpolator);
    }

    mWorkspace.setPivotToScaleWithSelf(hotseat);
    float hotseatScale = hotseatScaleAndTranslation.scale;
    if (shouldSpring) { // hotseat是否做弹簧动画
        PendingAnimation pa = (PendingAnimation) propertySetter;
        pa.add(getSpringScaleAnimator(mLauncher, hotseat, hotseatScale, HOTSEAT_SCALE_PROPERTY));
    } else {
        Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE, scaleInterpolator);
        propertySetter.setFloat(hotseat, HOTSEAT_SCALE_PROPERTY, hotseatScale,hotseatScaleInterpolator);
    }

    Interpolator workspaceFadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE, pageAlphaProvider.interpolator);
    float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;    //PageIndicator页面指示器
    propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(), workspacePageIndicatorAlpha, workspaceFadeInterpolator);
    //hotseat
    Interpolator hotseatFadeInterpolator = config.getInterpolator(ANIM_HOTSEAT_FADE, workspaceFadeInterpolator);
    float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
    propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, hotseatFadeInterpolator);

    // Update the accessibility flags for hotseat based on launcher state.
    hotseat.setImportantForAccessibility(state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE) ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
                    : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
    hotseat.setDescendantFocusability(state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE)  ? ViewGroup.FOCUS_BLOCK_DESCENDANTS : ViewGroup.FOCUS_BEFORE_DESCENDANTS);

    Interpolator translationInterpolator =  config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
    propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_X, scaleAndTranslation.translationX, translationInterpolator);
    propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY, translationInterpolator);
    PageTranslationProvider pageTranslationProvider = state.getWorkspacePageTranslationProvider(mLauncher);

    if (!FOLDABLE_SINGLE_PAGE.get()) {
        for (int i = 0; i < childCount; i++) {
            applyPageTranslation((CellLayout) mWorkspace.getChildAt(i), i, pageTranslationProvider, propertySetter, config);
        }
    }

    Interpolator hotseatTranslationInterpolator = config.getInterpolator(ANIM_HOTSEAT_TRANSLATE, translationInterpolator);
    propertySetter.setFloat(hotseat, VIEW_TRANSLATE_Y,  hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);
    propertySetter.setFloat(mWorkspace.getPageIndicator(), VIEW_TRANSLATE_Y, hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);

    if (!config.hasAnimationFlag(SKIP_SCRIM)) {
        setScrim(propertySetter, state, config);//上滑进入多任务背景颜色会加深
    }
}
private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
        PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter, StateAnimationConfig config) {
    float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
    float springLoadedProgress = (state instanceof  SpringLoadedState || state instanceof EditModeState) ? 1f : 0f;
    propertySetter.setFloat(cl,  CellLayout.SPRING_LOADED_PROGRESS, springLoadedProgress, ZOOM_OUT);
    Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE, pageAlphaProvider.interpolator);
    propertySetter.setFloat(cl.getShortcutsAndWidgets(), VIEW_ALPHA, pageAlpha, fadeInterpolator);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值