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

Commit a4537878 authored by Vinit Nayak's avatar Vinit Nayak Committed by Android (Google) Code Review
Browse files

Merge "Add interfaces to abstract out Shell DragAndDrop behavior" into main

parents bc8951c6 23fbdffd
Loading
Loading
Loading
Loading
+5 −7
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import static android.view.DragEvent.ACTION_DROP;
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
@@ -247,9 +246,8 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
                R.layout.global_drop_target, null);
        rootView.setOnDragListener(this);
        rootView.setVisibility(View.INVISIBLE);
        DragLayout dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
        rootView.addView(dragLayout,
                new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        DragLayoutProvider dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
        dragLayout.addDraggingView(rootView);
        try {
            wm.addView(rootView, layoutParams);
            addDisplayDropTarget(displayId, context, wm, rootView, dragLayout);
@@ -261,7 +259,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll

    @VisibleForTesting
    void addDisplayDropTarget(int displayId, Context context, WindowManager wm,
            FrameLayout rootView, DragLayout dragLayout) {
            FrameLayout rootView, DragLayoutProvider dragLayout) {
        mDisplayDropTargets.put(displayId,
                new PerDisplay(displayId, context, wm, rootView, dragLayout));
    }
@@ -564,7 +562,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
        final Context context;
        final WindowManager wm;
        final FrameLayout rootView;
        final DragLayout dragLayout;
        final DragLayoutProvider dragLayout;
        // Tracks whether the window has fully drawn since it was last made visible
        boolean hasDrawn;

@@ -575,7 +573,7 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
        // The active drag session
        DragSession dragSession;

        PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayout dl) {
        PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayoutProvider dl) {
            displayId = dispId;
            context = c;
            wm = w;
+22 −14
Original line number Diff line number Diff line
@@ -23,10 +23,10 @@ import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;

import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;

@@ -47,6 +47,7 @@ import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.view.DragEvent;
import android.view.SurfaceControl;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowInsets.Type;
@@ -66,13 +67,13 @@ import com.android.wm.shell.shared.animation.Interpolators;
import com.android.wm.shell.splitscreen.SplitScreenController;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * Coordinates the visible drop targets for the current drag within a single display.
 */
public class DragLayout extends LinearLayout
        implements ViewTreeObserver.OnComputeInternalInsetsListener {
        implements ViewTreeObserver.OnComputeInternalInsetsListener, DragLayoutProvider {

    // While dragging the status bar is hidden.
    private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS
@@ -80,7 +81,7 @@ public class DragLayout extends LinearLayout
            | StatusBarManager.DISABLE_CLOCK
            | StatusBarManager.DISABLE_SYSTEM_INFO;

    private final DragAndDropPolicy mPolicy;
    private final DropTarget mPolicy;
    private final SplitScreenController mSplitScreenController;
    private final IconProvider mIconProvider;
    private final StatusBarManager mStatusBarManager;
@@ -91,7 +92,7 @@ public class DragLayout extends LinearLayout
    // Whether the device is currently in left/right split mode
    private boolean mIsLeftRightSplit;

    private DragAndDropPolicy.Target mCurrentTarget = null;
    private SplitDragPolicy.Target mCurrentTarget = null;
    private DropZoneView mDropZoneView1;
    private DropZoneView mDropZoneView2;

@@ -113,7 +114,7 @@ public class DragLayout extends LinearLayout
        super(context);
        mSplitScreenController = splitScreenController;
        mIconProvider = iconProvider;
        mPolicy = new DragAndDropPolicy(context, splitScreenController);
        mPolicy = new SplitDragPolicy(context, splitScreenController);
        mStatusBarManager = context.getSystemService(StatusBarManager.class);
        mLastConfiguration.setTo(context.getResources().getConfiguration());

@@ -387,6 +388,13 @@ public class DragLayout extends LinearLayout
        recomputeDropTargets();
    }

    @NonNull
    @Override
    public void addDraggingView(ViewGroup rootView) {
        // TODO(b/349828130) We need to separate out view + logic here
        rootView.addView(this, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    }

    /**
     * Recalculates the drop targets based on the current policy.
     */
@@ -394,9 +402,9 @@ public class DragLayout extends LinearLayout
        if (!mIsShowing) {
            return;
        }
        final ArrayList<DragAndDropPolicy.Target> targets = mPolicy.getTargets(mInsets);
        final List<SplitDragPolicy.Target> targets = mPolicy.getTargets(mInsets);
        for (int i = 0; i < targets.size(); i++) {
            final DragAndDropPolicy.Target target = targets.get(i);
            final SplitDragPolicy.Target target = targets.get(i);
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Add target: %s", target);
            // Inset the draw region by a little bit
            target.drawRegion.inset(mDisplayMargin, mDisplayMargin);
@@ -419,7 +427,7 @@ public class DragLayout extends LinearLayout
        }
        // Find containing region, if the same as mCurrentRegion, then skip, otherwise, animate the
        // visibility of the current region
        DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(x, y);
        SplitDragPolicy.Target target = mPolicy.getTargetAtLocation(x, y);
        if (mCurrentTarget != target) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
            if (target == null) {
@@ -493,7 +501,7 @@ public class DragLayout extends LinearLayout
        mHasDropped = true;

        // Process the drop
        mPolicy.handleDrop(mCurrentTarget, hideTaskToken);
        mPolicy.onDropped(mCurrentTarget, hideTaskToken);

        // Start animating the drop UI out with the drag surface
        hide(event, dropCompleteCallback);
@@ -576,7 +584,7 @@ public class DragLayout extends LinearLayout
        }
    }

    private void animateHighlight(DragAndDropPolicy.Target target) {
    private void animateHighlight(SplitDragPolicy.Target target) {
        if (target.type == TYPE_SPLIT_LEFT || target.type == TYPE_SPLIT_TOP) {
            mDropZoneView1.setShowingHighlight(true);
            mDropZoneView2.setShowingHighlight(false);
+80 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.wm.shell.draganddrop

import android.content.res.Configuration
import android.view.DragEvent
import android.view.SurfaceControl
import android.view.ViewGroup
import android.window.WindowContainerToken
import com.android.internal.logging.InstanceId
import java.io.PrintWriter

/** Interface to be implemented by any controllers providing a layout for DragAndDrop in Shell */
interface DragLayoutProvider {
    /**
     * Updates the drag layout based on the given drag session.
     */
    fun updateSession(session: DragSession)
    /**
     * Called when a new drag is started.
     */
    fun prepare(session: DragSession, loggerSessionId: InstanceId?)

    /**
     * Shows the drag layout.
     */
    fun show()

    /**
     * Updates the visible drop target as the user drags.
     */
    fun update(event: DragEvent?)

    /**
     * Hides the drag layout and animates out the visible drop targets.
     */
    fun hide(event: DragEvent?, hideCompleteCallback: Runnable?)

    /**
     * Whether target has already been dropped or not
     */
    fun hasDropped(): Boolean

    /**
     * Handles the drop onto a target and animates out the visible drop targets.
     */
    fun drop(
        event: DragEvent?, dragSurface: SurfaceControl,
        hideTaskToken: WindowContainerToken?, dropCompleteCallback: Runnable?
    ): Boolean

    /**
     * Dumps information about this drag layout.
     */
    fun dump(pw: PrintWriter, prefix: String?)

    /**
     * @return a View which will be added to the global root view for drag and drop
     */
    fun addDraggingView(viewGroup: ViewGroup)

    /**
     * Called when the configuration changes.
     */
    fun onConfigChanged(newConfig: Configuration?)
}
 No newline at end of file
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.wm.shell.draganddrop

import android.graphics.Insets
import android.window.WindowContainerToken
import com.android.internal.logging.InstanceId

/**
 * Interface to be implemented by classes which want to provide drop targets
 * for DragAndDrop in Shell
 */
interface DropTarget {
    // TODO(b/349828130) Delete after flexible split launches
    /**
     * Called at the start of a Drag, before input events are processed.
     */
    fun start(dragSession: DragSession, logSessionId: InstanceId)
    /**
     * @return [SplitDragPolicy.Target] corresponding to the given coords in display bounds.
     */
    fun getTargetAtLocation(x: Int, y: Int) : SplitDragPolicy.Target
    /**
     * @return total number of drop targets for the current drag session.
     */
    fun getNumTargets() : Int
    // TODO(b/349828130)

    /**
     * @return [List<SplitDragPolicy.Target>] to show for the current drag session.
     */
    fun getTargets(insets: Insets) : List<SplitDragPolicy.Target>
    /**
     * Called when user is hovering Drag object over the given Target
     */
    fun onHoveringOver(target: SplitDragPolicy.Target) {}
    /**
     * Called when the user has dropped the provided target (need not be the same target as
     * [onHoveringOver])
     */
    fun onDropped(target: SplitDragPolicy.Target, hideTaskToken: WindowContainerToken)
}
 No newline at end of file
+20 −17
Original line number Diff line number Diff line
@@ -32,11 +32,11 @@ import static android.content.Intent.EXTRA_USER;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;

import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_FULLSCREEN;
import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.shared.draganddrop.DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -80,9 +80,9 @@ import java.util.ArrayList;
/**
 * The policy for handling drag and drop operations to shell.
 */
public class DragAndDropPolicy {
public class SplitDragPolicy implements DropTarget {

    private static final String TAG = DragAndDropPolicy.class.getSimpleName();
    private static final String TAG = SplitDragPolicy.class.getSimpleName();

    private final Context mContext;
    // Used only for launching a fullscreen task (or as a fallback if there is no split starter)
@@ -90,18 +90,18 @@ public class DragAndDropPolicy {
    // Used for launching tasks into splitscreen
    private final Starter mSplitscreenStarter;
    private final SplitScreenController mSplitScreen;
    private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
    private final ArrayList<SplitDragPolicy.Target> mTargets = new ArrayList<>();
    private final RectF mDisallowHitRegion = new RectF();

    private InstanceId mLoggerSessionId;
    private DragSession mSession;

    public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
    public SplitDragPolicy(Context context, SplitScreenController splitScreen) {
        this(context, splitScreen, new DefaultStarter(context));
    }

    @VisibleForTesting
    DragAndDropPolicy(Context context, SplitScreenController splitScreen,
    SplitDragPolicy(Context context, SplitScreenController splitScreen,
            Starter fullscreenStarter) {
        mContext = context;
        mSplitScreen = splitScreen;
@@ -112,7 +112,7 @@ public class DragAndDropPolicy {
    /**
     * Starts a new drag session with the given initial drag data.
     */
    void start(DragSession session, InstanceId loggerSessionId) {
    public void start(DragSession session, InstanceId loggerSessionId) {
        mLoggerSessionId = loggerSessionId;
        mSession = session;
        RectF disallowHitRegion = mSession.appData != null
@@ -128,7 +128,8 @@ public class DragAndDropPolicy {
    /**
     * Returns the number of targets.
     */
    int getNumTargets() {
    @Override
    public int getNumTargets() {
        return mTargets.size();
    }

@@ -136,7 +137,8 @@ public class DragAndDropPolicy {
     * Returns the target's regions based on the current state of the device and display.
     */
    @NonNull
    ArrayList<Target> getTargets(Insets insets) {
    @Override
    public ArrayList<Target> getTargets(@NonNull Insets insets) {
        mTargets.clear();
        if (mSession == null) {
            // Return early if this isn't an app drag
@@ -222,12 +224,12 @@ public class DragAndDropPolicy {
     * Returns the target at the given position based on the targets previously calculated.
     */
    @Nullable
    Target getTargetAtLocation(int x, int y) {
    public Target getTargetAtLocation(int x, int y) {
        if (mDisallowHitRegion.contains(x, y)) {
            return null;
        }
        for (int i = mTargets.size() - 1; i >= 0; i--) {
            DragAndDropPolicy.Target t = mTargets.get(i);
            SplitDragPolicy.Target t = mTargets.get(i);
            if (t.hitRegion.contains(x, y)) {
                return t;
            }
@@ -241,7 +243,7 @@ public class DragAndDropPolicy {
     * container transaction if possible.
     */
    @VisibleForTesting
    void handleDrop(Target target, @Nullable WindowContainerToken hideTaskToken) {
    public void onDropped(Target target, @Nullable WindowContainerToken hideTaskToken) {
        if (target == null || !mTargets.contains(target)) {
            return;
        }
@@ -419,8 +421,9 @@ public class DragAndDropPolicy {

    /**
     * Represents a drop target.
     * TODO(b/349828130): Move this into {@link DropTarget}
     */
    static class Target {
    public static class Target {
        static final int TYPE_FULLSCREEN = 0;
        static final int TYPE_SPLIT_LEFT = 1;
        static final int TYPE_SPLIT_TOP = 2;
Loading