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

Commit 64acbe36 authored by Winson Chung's avatar Winson Chung Committed by Automerger Merge Worker
Browse files

Merge "Add test mechanism to check whether the shell drop target window has...

Merge "Add test mechanism to check whether the shell drop target window has drawn" into udc-dev am: d4760a4d am: 73b4f7d1

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22939180



Change-Id: Ieb4a88efdf03d153b8f1d86a53fcae6d8ba2183f
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents b67eecbe 73b4f7d1
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -189,12 +189,13 @@ public abstract class WMShellBaseModule {
    static Optional<DragAndDropController> provideDragAndDropController(Context context,
            ShellInit shellInit,
            ShellController shellController,
            ShellCommandHandler shellCommandHandler,
            DisplayController displayController,
            UiEventLogger uiEventLogger,
            IconProvider iconProvider,
            @ShellMainThread ShellExecutor mainExecutor) {
        return Optional.ofNullable(DragAndDropController.create(context, shellInit, shellController,
                displayController, uiEventLogger, iconProvider, mainExecutor));
                shellCommandHandler, displayController, uiEventLogger, iconProvider, mainExecutor));
    }

    @WMSingleton
+112 −13
Original line number Diff line number Diff line
@@ -35,10 +35,14 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;

import android.content.ClipDescription;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.HardwareRenderer;
import android.graphics.PixelFormat;
import android.util.Slog;
import android.util.SparseArray;
@@ -50,6 +54,8 @@ import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;

import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;

import com.android.internal.logging.InstanceId;
@@ -58,25 +64,31 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalMainThread;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;

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

/**
 * Handles the global drag and drop handling for the Shell.
 */
public class DragAndDropController implements DisplayController.OnDisplaysChangedListener,
public class DragAndDropController implements RemoteCallable<DragAndDropController>,
        DisplayController.OnDisplaysChangedListener,
        View.OnDragListener, ComponentCallbacks2 {

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

    private final Context mContext;
    private final ShellController mShellController;
    private final ShellCommandHandler mShellCommandHandler;
    private final DisplayController mDisplayController;
    private final DragAndDropEventLogger mLogger;
    private final IconProvider mIconProvider;
@@ -100,6 +112,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
    public static DragAndDropController create(Context context,
            ShellInit shellInit,
            ShellController shellController,
            ShellCommandHandler shellCommandHandler,
            DisplayController displayController,
            UiEventLogger uiEventLogger,
            IconProvider iconProvider,
@@ -107,19 +120,21 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
        if (!context.getResources().getBoolean(R.bool.config_enableShellDragDrop)) {
            return null;
        }
        return new DragAndDropController(context, shellInit, shellController, displayController,
                uiEventLogger, iconProvider, mainExecutor);
        return new DragAndDropController(context, shellInit, shellController, shellCommandHandler,
                displayController, uiEventLogger, iconProvider, mainExecutor);
    }

    DragAndDropController(Context context,
            ShellInit shellInit,
            ShellController shellController,
            ShellCommandHandler shellCommandHandler,
            DisplayController displayController,
            UiEventLogger uiEventLogger,
            IconProvider iconProvider,
            ShellExecutor mainExecutor) {
        mContext = context;
        mShellController = shellController;
        mShellCommandHandler = shellCommandHandler;
        mDisplayController = displayController;
        mLogger = new DragAndDropEventLogger(uiEventLogger);
        mIconProvider = iconProvider;
@@ -137,6 +152,23 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
        mMainExecutor.executeDelayed(() -> {
            mDisplayController.addDisplayWindowListener(this);
        }, 0);
        mShellController.addExternalInterface(KEY_EXTRA_SHELL_DRAG_AND_DROP,
                this::createExternalInterface, this);
        mShellCommandHandler.addDumpCallback(this::dump, this);
    }

    private ExternalInterfaceBinder createExternalInterface() {
        return new IDragAndDropImpl(this);
    }

    @Override
    public Context getContext() {
        return mContext;
    }

    @Override
    public ShellExecutor getRemoteCallExecutor() {
        return mMainExecutor;
    }

    /**
@@ -156,7 +188,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
        mListeners.remove(listener);
    }

    private void notifyListeners() {
    private void notifyDragStarted() {
        for (int i = 0; i < mListeners.size(); i++) {
            mListeners.get(i).onDragStarted();
        }
@@ -273,7 +305,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
                pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
                        event.getClipData(), loggerSessionId);
                setDropTargetWindowVisibility(pd, View.VISIBLE);
                notifyListeners();
                notifyDragStarted();
                break;
            case ACTION_DRAG_ENTERED:
                pd.dragLayout.show();
@@ -327,13 +359,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
    }

    private void setDropTargetWindowVisibility(PerDisplay pd, int visibility) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                "Set drop target window visibility: displayId=%d visibility=%d",
                pd.displayId, visibility);
        pd.rootView.setVisibility(visibility);
        if (visibility == View.VISIBLE) {
            pd.rootView.requestApplyInsets();
        }
        pd.setWindowVisibility(visibility);
    }

    private String getMimeTypes(ClipDescription description) {
@@ -347,6 +373,18 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
        return mimeTypes;
    }

    /**
     * Returns if any displays are currently ready to handle a drag/drop.
     */
    private boolean isReadyToHandleDrag() {
        for (int i = 0; i < mDisplayDropTargets.size(); i++) {
            if (mDisplayDropTargets.valueAt(i).mHasDrawn) {
                return true;
            }
        }
        return false;
    }

    // Note: Component callbacks are always called on the main thread of the process
    @ExternalMainThread
    @Override
@@ -372,12 +410,53 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
        // Do nothing
    }

    private static class PerDisplay {
    /**
     * Dumps information about this controller.
     */
    public void dump(@NonNull PrintWriter pw, String prefix) {
        pw.println(prefix + TAG);
        pw.println(prefix + " listeners=" + mListeners.size());
    }
    
    /**
     * The interface for calls from outside the host process.
     */
    @BinderThread
    private static class IDragAndDropImpl extends IDragAndDrop.Stub
            implements ExternalInterfaceBinder {
        private DragAndDropController mController;

        public IDragAndDropImpl(DragAndDropController controller) {
            mController = controller;
        }

        /**
         * Invalidates this instance, preventing future calls from updating the controller.
         */
        @Override
        public void invalidate() {
            mController = null;
        }

        @Override
        public boolean isReadyToHandleDrag() {
            boolean[] result = new boolean[1];
            executeRemoteCallWithTaskPermission(mController, "isReadyToHandleDrag",
                    controller -> result[0] = controller.isReadyToHandleDrag(),
                    true /* blocking */
            );
            return result[0];
        }
    }

    private static class PerDisplay implements HardwareRenderer.FrameDrawingCallback {
        final int displayId;
        final Context context;
        final WindowManager wm;
        final FrameLayout rootView;
        final DragLayout dragLayout;
        // Tracks whether the window has fully drawn since it was last made visible
        boolean mHasDrawn;

        boolean isHandlingDrag;
        // A count of the number of active drags in progress to ensure that we only hide the window
@@ -391,5 +470,25 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
            rootView = rv;
            dragLayout = dl;
        }

        private void setWindowVisibility(int visibility) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
                    "Set drop target window visibility: displayId=%d visibility=%d",
                    displayId, visibility);
            rootView.setVisibility(visibility);
            if (visibility == View.VISIBLE) {
                rootView.requestApplyInsets();
                if (!mHasDrawn && rootView.getViewRootImpl() != null) {
                    rootView.getViewRootImpl().registerRtFrameCallback(this);
                }
            } else {
                mHasDrawn = false;
            }
        }

        @Override
        public void onFrameDraw(long frame) {
            mHasDrawn = true;
        }
    }
}
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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;

/**
 * Interface that is exposed to remote callers to manipulate drag and drop.
 */
interface IDragAndDrop {
    /**
     * Returns whether the shell drop target is showing and will handle a drag/drop.
     */
    boolean isReadyToHandleDrag() = 1;
}
// Last id = 1
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
@@ -42,4 +42,6 @@ public class ShellSharedConstants {
    public static final String KEY_EXTRA_SHELL_FLOATING_TASKS = "extra_shell_floating_tasks";
    // See IDesktopMode.aidl
    public static final String KEY_EXTRA_SHELL_DESKTOP_MODE = "extra_shell_desktop_mode";
    // See IDragAndDrop.aidl
    public static final String KEY_EXTRA_SHELL_DRAG_AND_DROP = "extra_shell_drag_and_drop";
}
+5 −1
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;

@@ -71,6 +72,8 @@ public class DragAndDropControllerTest extends ShellTestCase {
    @Mock
    private ShellController mShellController;
    @Mock
    private ShellCommandHandler mShellCommandHandler;
    @Mock
    private DisplayController mDisplayController;
    @Mock
    private UiEventLogger mUiEventLogger;
@@ -89,7 +92,8 @@ public class DragAndDropControllerTest extends ShellTestCase {
    public void setUp() throws RemoteException {
        MockitoAnnotations.initMocks(this);
        mController = new DragAndDropController(mContext, mShellInit, mShellController,
                mDisplayController, mUiEventLogger, mIconProvider, mMainExecutor);
                mShellCommandHandler, mDisplayController, mUiEventLogger, mIconProvider,
                mMainExecutor);
        mController.onInit();
    }