Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39938cbc authored by Tony Wickham's avatar Tony Wickham
Browse files

Initiate Hotseat drag from long pressing corresponding Taskbar item

When you long press on the taskbar hotseat item, the following happens:
- We start a system drag and drop with an invisible drag shadow
- We create a new DragOptions with the simulatedDndStartPoint set to the
  drag down position, and tell Launcher to use that for the next drag
- We perform a long click on the equivalent Hotseat item in Launcher
- We pass the drag events of that operation to Launcher's DragController

This allows Launcher to handle the entire drag operation, including the
pre-drag (with popup), and taskbar already hides when the drag starts.

Test: Long press items in taskbar hotseat, able to drag them to workspace

Bug: 179886115
Bug: 171917176
Change-Id: I576b80cb1bd0225cdc91cf7689fdee0481265109
parent 3ca4b0d8
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.view.View;
import androidx.annotation.Nullable;

import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.proxy.ProxyActivityStarter;
@@ -83,6 +84,8 @@ public abstract class BaseQuickstepLauncher extends Launcher

    private @Nullable TaskbarController mTaskbarController;
    private final TaskbarStateHandler mTaskbarStateHandler = new TaskbarStateHandler(this);
    // Will be updated when dragging from taskbar.
    private DragOptions mWorkspaceDragOptions = new DragOptions();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
@@ -269,6 +272,15 @@ public abstract class BaseQuickstepLauncher extends Launcher
        return mTaskbarController != null && mTaskbarController.isViewInTaskbar(v);
    }

    @Override
    public DragOptions getDefaultWorkspaceDragOptions() {
        return mWorkspaceDragOptions;
    }

    public void setWorkspaceDragOptions(DragOptions dragOptions) {
        mWorkspaceDragOptions = dragOptions;
    }

    @Override
    public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) {
        QuickstepAppTransitionManagerImpl appTransitionManager =
+2 −1
Original line number Diff line number Diff line
@@ -107,7 +107,8 @@ public class HotseatPredictionController implements DragController.DragListener,
        WorkspaceItemInfo dragItem = new WorkspaceItemInfo((WorkspaceItemInfo) v.getTag());
        v.setVisibility(View.INVISIBLE);
        mLauncher.getWorkspace().beginDragShared(
                v, null, this, dragItem, new DragPreviewProvider(v), new DragOptions());
                v, null, this, dragItem, new DragPreviewProvider(v),
                mLauncher.getDefaultWorkspaceDragOptions());
        return true;
    };

+8 −1
Original line number Diff line number Diff line
@@ -170,7 +170,14 @@ public class TaskbarController {

            @Override
            public View.OnLongClickListener getItemOnLongClickListener() {
                return mDragController::startDragOnLongClick;
                return view -> {
                    if (mLauncher.hasBeenResumed() && view.getTag() instanceof ItemInfo) {
                        alignRealHotseatWithTaskbar();
                        return mDragController.startWorkspaceDragOnLongClick(view);
                    } else {
                        return mDragController.startSystemDragOnLongClick(view);
                    }
                };
            }

            @Override
+34 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ClipDescriptionCompat;
@@ -57,7 +58,7 @@ public class TaskbarDragController {
     * generate the ClipDescription and Intent.
     * @return Whether {@link View#startDragAndDrop} started successfully.
     */
    protected boolean startDragOnLongClick(View view) {
    protected boolean startSystemDragOnLongClick(View view) {
        if (!(view instanceof BubbleTextView)) {
            return false;
        }
@@ -124,6 +125,38 @@ public class TaskbarDragController {
        return false;
    }

    /**
     * Starts a drag and drop operation that controls a real Workspace (Hotseat) view.
     * @param view The Taskbar item that was long clicked.
     * @return Whether {@link View#startDragAndDrop} started successfully.
     */
    protected boolean startWorkspaceDragOnLongClick(View view) {
        View.DragShadowBuilder transparentShadowBuilder = new View.DragShadowBuilder(view) {
            private static final int ARBITRARY_SHADOW_SIZE = 10;

            @Override
            public void onDrawShadow(Canvas canvas) {
            }

            @Override
            public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) {
                outShadowSize.set(ARBITRARY_SHADOW_SIZE, ARBITRARY_SHADOW_SIZE);
                outShadowTouchPoint.set(ARBITRARY_SHADOW_SIZE / 2, ARBITRARY_SHADOW_SIZE / 2);
            }
        };

        TaskbarDragListener taskbarDragListener = new TaskbarDragListener(mLauncher,
                (ItemInfo) view.getTag());
        if (view.startDragAndDrop(new ClipData("", new String[] {taskbarDragListener.getMimeType()},
                        new ClipData.Item("")),
                transparentShadowBuilder, null /* localState */, View.DRAG_FLAG_GLOBAL)) {
            view.setOnDragListener(getDraggedViewDragListener());
            taskbarDragListener.init(mLauncher.getDragLayer());
            return true;
        }
        return false;
    }

    /**
     * Hide the original Taskbar item while it is being dragged.
     */
+99 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.launcher3.taskbar;

import android.content.ClipDescription;
import android.graphics.Point;
import android.view.DragEvent;
import android.view.View;

import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.model.data.ItemInfo;

import java.util.UUID;

/**
 * Listens to system drag and drop events initated by the Taskbar, and forwards them to Launcher's
 * internal DragController to move Hotseat items.
 */
public class TaskbarDragListener implements View.OnDragListener {

    private static final String MIME_TYPE_PREFIX = "com.android.launcher3.taskbar.drag_and_drop/";

    private final BaseQuickstepLauncher mLauncher;
    private final ItemInfo mDraggedItem;
    private final DragOptions mDragOptions;
    // Randomly generated id used to verify the drag event.
    private final String mId;

    // Initialized in init().
    DragLayer mDragLayer;

    /**
     * @param draggedItem The info of the item that was long clicked, which we will use to find
     *                    the equivalent match on Hotseat to drag internally.
     */
    public TaskbarDragListener(BaseQuickstepLauncher launcher, ItemInfo draggedItem) {
        mLauncher = launcher;
        mDraggedItem = draggedItem;
        mDragOptions = new DragOptions();
        mDragOptions.simulatedDndStartPoint = new Point();
        mId = UUID.randomUUID().toString();
    }

    protected void init(DragLayer dragLayer) {
        mDragLayer = dragLayer;
        mDragLayer.setOnDragListener(this);
    }

    private void cleanup() {
        mDragLayer.setOnDragListener(null);
        mLauncher.setWorkspaceDragOptions(new DragOptions());
    }

    /**
     * Returns a randomly generated id used to verify the drag event.
     */
    protected String getMimeType() {
        return MIME_TYPE_PREFIX + mId;
    }

    @Override
    public boolean onDrag(View dragLayer, DragEvent dragEvent) {
        ClipDescription clipDescription = dragEvent.getClipDescription();
        if (dragEvent.getAction() == DragEvent.ACTION_DRAG_STARTED) {
            if (clipDescription == null || !clipDescription.hasMimeType(getMimeType())) {
                // We didn't initiate this drag, ignore.
                cleanup();
                return false;
            }
            View hotseatView = mLauncher.getHotseat().getFirstItemMatch(
                    (info, view) -> info == mDraggedItem);
            if (hotseatView == null) {
                cleanup();
                return false;
            }
            mDragOptions.simulatedDndStartPoint.set((int) dragEvent.getX(), (int) dragEvent.getY());
            mLauncher.setWorkspaceDragOptions(mDragOptions);
            hotseatView.performLongClick();
        } else if (dragEvent.getAction() == DragEvent.ACTION_DRAG_ENDED) {
            cleanup();
        }
        return mLauncher.getDragController().onDragEvent(dragEvent);
    }
}
Loading