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

Commit f94e099e authored by Winson Chung's avatar Winson Chung Committed by Android Build Coastguard Worker
Browse files

Add mechanism for a task to be hidden as a part of starting a drag

- This change adds a new DRAG_FLAG_HIDE_CALLING_TASK_ON_DRAG_START
  (restricted to the assistant uid) which will allow the calling task's
  window to hide it's surface for the duration of the drag.  As a part
  of setting this flag, the return/cancel animations are also adjusted
  to fade out in-place.

  In order to handle most of this logic in the shell instead of core,
  the drag & drop flow will notify (only) the shell of the drag source
  task id (if it has requested the flag to hide), and the shell will
  in turn hide the task surface and upon successful drop to invoke
  splitscreen, the shell will reorder the task to the back. If the drag
  is not handled or canceled, the task surface is made visible again.

Bug: 350016003
Flag: EXEMPT bugfix
Test: Drag floating window to split, ensure it hides and restores if the
      drag is canceled
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b51bba4b02d02b1f3cbd244d956e1231dc5a4b65)
Merged-In: Id96ef40a6f74892eac22b9ef3c04107b1b07cfb2
Change-Id: Id96ef40a6f74892eac22b9ef3c04107b1b07cfb2
parent 4a78cc84
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -135,6 +135,14 @@ public class ClipDescription implements Parcelable {
    public static final String EXTRA_LOGGING_INSTANCE_ID =
            "android.intent.extra.LOGGING_INSTANCE_ID";

    /**
     * The id of the task containing the window that initiated the drag that should be hidden.
     * Only provided to internal drag handlers as a part of the DRAG_START event.
     * @hide
     */
    public static final String EXTRA_HIDE_DRAG_SOURCE_TASK_ID =
            "android.intent.extra.HIDE_DRAG_SOURCE_TASK_ID";

    /**
     * Indicates that a ClipData contains potentially sensitive information, such as a
     * password or credit card number.
+8 −0
Original line number Diff line number Diff line
@@ -5511,6 +5511,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS)
    public static final int DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG = 1 << 13;
    /**
     * Flag indicating that this drag will result in the caller activity's task to be hidden for the
     * duration of the drag, this means that the source activity will not receive drag events for
     * the current drag gesture. Only the current voice interaction service may use this flag.
     * @hide
     */
    public static final int DRAG_FLAG_HIDE_CALLING_TASK_ON_DRAG_START = 1 << 14;
    /**
     * Vertical scroll factor cached by {@link #getVerticalScrollFactor}.
     */
+16 −0
Original line number Diff line number Diff line
@@ -680,6 +680,22 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
        }
    }

    /**
     * Shows/hides the given task surface.  Not for general use as changing the task visibility may
     * conflict with other Transitions.  This is currently ONLY used to temporarily hide a task
     * while a drag is in session.
     */
    public void setTaskSurfaceVisibility(int taskId, boolean visible) {
        synchronized (mLock) {
            final TaskAppearedInfo info = mTasks.get(taskId);
            if (info != null) {
                SurfaceControl.Transaction t = new SurfaceControl.Transaction();
                t.setVisibility(info.getLeash(), visible);
                t.apply();
            }
        }
    }

    private boolean updateTaskListenerIfNeeded(RunningTaskInfo taskInfo, SurfaceControl leash,
            TaskListener oldListener, TaskListener newListener) {
        if (oldListener == newListener) return false;
+24 −1
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

import androidx.annotation.BinderThread;
@@ -353,6 +354,12 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
                pd.dragSession.initialize();
                pd.activeDragCount++;
                pd.dragLayout.prepare(pd.dragSession, mLogger.logStart(pd.dragSession));
                if (pd.dragSession.hideDragSourceTaskId != -1) {
                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                            "Hiding task surface: taskId=%d", pd.dragSession.hideDragSourceTaskId);
                    mShellTaskOrganizer.setTaskSurfaceVisibility(
                            pd.dragSession.hideDragSourceTaskId, false /* visible */);
                }
                setDropTargetWindowVisibility(pd, View.VISIBLE);
                notifyListeners(l -> {
                    l.onDragStarted();
@@ -382,6 +389,13 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
                if (pd.dragLayout.hasDropped()) {
                    mLogger.logDrop();
                } else {
                    if (pd.dragSession.hideDragSourceTaskId != -1) {
                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                                "Re-showing task surface: taskId=%d",
                                pd.dragSession.hideDragSourceTaskId);
                        mShellTaskOrganizer.setTaskSurfaceVisibility(
                                pd.dragSession.hideDragSourceTaskId, true /* visible */);
                    }
                    pd.activeDragCount--;
                    pd.dragLayout.hide(event, () -> {
                        if (pd.activeDragCount == 0) {
@@ -435,7 +449,16 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll
    private boolean handleDrop(DragEvent event, PerDisplay pd) {
        final SurfaceControl dragSurface = event.getDragSurface();
        pd.activeDragCount--;
        return pd.dragLayout.drop(event, dragSurface, () -> {
        // Find the token of the task to hide as a part of entering split
        WindowContainerToken hideTaskToken = null;
        if (pd.dragSession.hideDragSourceTaskId != -1) {
            ActivityManager.RunningTaskInfo info = mShellTaskOrganizer.getRunningTaskInfo(
                    pd.dragSession.hideDragSourceTaskId);
            if (info != null) {
                hideTaskToken = info.token;
            }
        }
        return pd.dragLayout.drop(event, dragSurface, hideTaskToken, () -> {
            if (pd.activeDragCount == 0) {
                // Hide the window if another drag hasn't been started while animating the drop
                setDropTargetWindowVisibility(pd, View.INVISIBLE);
+36 −12
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
import android.window.WindowContainerToken;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
@@ -234,8 +235,13 @@ public class DragAndDropPolicy {
        return null;
    }

    /**
     * Handles the drop on a given {@param target}.  If a {@param hideTaskToken} is set, then the
     * handling of the drop will attempt to hide the given task as a part of the same window
     * container transaction if possible.
     */
    @VisibleForTesting
    void handleDrop(Target target) {
    void handleDrop(Target target, @Nullable WindowContainerToken hideTaskToken) {
        if (target == null || !mTargets.contains(target)) {
            return;
        }
@@ -254,16 +260,17 @@ public class DragAndDropPolicy {
                ? mFullscreenStarter
                : mSplitscreenStarter;
        if (mSession.appData != null) {
            launchApp(mSession, starter, position);
            launchApp(mSession, starter, position, hideTaskToken);
        } else {
            launchIntent(mSession, starter, position);
            launchIntent(mSession, starter, position, hideTaskToken);
        }
    }

    /**
     * Launches an app provided by SysUI.
     */
    private void launchApp(DragSession session, Starter starter, @SplitPosition int position) {
    private void launchApp(DragSession session, Starter starter, @SplitPosition int position,
            @Nullable WindowContainerToken hideTaskToken) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching app data at position=%d",
                position);
        final ClipDescription description = session.getClipDescription();
@@ -283,8 +290,12 @@ public class DragAndDropPolicy {

        if (isTask) {
            final int taskId = session.appData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
            starter.startTask(taskId, position, opts);
            starter.startTask(taskId, position, opts, hideTaskToken);
        } else if (isShortcut) {
            if (hideTaskToken != null) {
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                        "Can not hide task token with starting shortcut");
            }
            final String packageName = session.appData.getStringExtra(EXTRA_PACKAGE_NAME);
            final String id = session.appData.getStringExtra(EXTRA_SHORTCUT_ID);
            starter.startShortcut(packageName, id, position, opts, user);
@@ -297,14 +308,15 @@ public class DragAndDropPolicy {
                }
            }
            starter.startIntent(launchIntent, user.getIdentifier(), null /* fillIntent */,
                    position, opts);
                    position, opts, hideTaskToken);
        }
    }

    /**
     * Launches an intent sender provided by an application.
     */
    private void launchIntent(DragSession session, Starter starter, @SplitPosition int position) {
    private void launchIntent(DragSession session, Starter starter, @SplitPosition int position,
            @Nullable WindowContainerToken hideTaskToken) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching intent at position=%d",
                position);
        final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic();
@@ -319,18 +331,20 @@ public class DragAndDropPolicy {
        final Bundle opts = baseActivityOpts.toBundle();
        starter.startIntent(session.launchableIntent,
                session.launchableIntent.getCreatorUserHandle().getIdentifier(),
                null /* fillIntent */, position, opts);
                null /* fillIntent */, position, opts, hideTaskToken);
    }

    /**
     * Interface for actually committing the task launches.
     */
    public interface Starter {
        void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options);
        void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options,
                @Nullable WindowContainerToken hideTaskToken);
        void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
                @Nullable Bundle options, UserHandle user);
        void startIntent(PendingIntent intent, int userId, Intent fillInIntent,
                @SplitPosition int position, @Nullable Bundle options);
                @SplitPosition int position, @Nullable Bundle options,
                @Nullable WindowContainerToken hideTaskToken);
        void enterSplitScreen(int taskId, boolean leftOrTop);

        /**
@@ -352,7 +366,12 @@ public class DragAndDropPolicy {
        }

        @Override
        public void startTask(int taskId, int position, @Nullable Bundle options) {
        public void startTask(int taskId, int position, @Nullable Bundle options,
                @Nullable WindowContainerToken hideTaskToken) {
            if (hideTaskToken != null) {
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                        "Default starter does not support hide task token");
            }
            try {
                ActivityTaskManager.getService().startActivityFromRecents(taskId, options);
            } catch (RemoteException e) {
@@ -375,7 +394,12 @@ public class DragAndDropPolicy {

        @Override
        public void startIntent(PendingIntent intent, int userId, @Nullable Intent fillInIntent,
                int position, @Nullable Bundle options) {
                int position, @Nullable Bundle options,
                @Nullable WindowContainerToken hideTaskToken) {
            if (hideTaskToken != null) {
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                        "Default starter does not support hide task token");
            }
            try {
                intent.send(mContext, 0, fillInIntent, null, null, null, options);
            } catch (PendingIntent.CanceledException e) {
Loading