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

Commit 429355b9 authored by Ben Lin's avatar Ben Lin Committed by Android (Google) Code Review
Browse files

Merge "TV-PiP: Migrate Menu to SystemWindows."

parents 1d2102b5 819f82ba
Loading
Loading
Loading
Loading
+106 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.pip;

import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.RemoteAction;
import android.content.pm.ParceledListSlice;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.view.SurfaceControl;
import android.view.WindowManager;

/**
 *  Interface to allow {@link com.android.wm.shell.pip.PipTaskOrganizer} to call into
 *  PiP menu when certain events happen (task appear/vanish, PiP move, etc.)
 */
public interface PipMenuController {

    String MENU_WINDOW_TITLE = "PipMenuView";

    /**
     * Called when
     * {@link PipTaskOrganizer#onTaskAppeared(RunningTaskInfo, SurfaceControl)}
     * is called.
     */
    void attach(SurfaceControl leash);

    /**
     * Called when
     * {@link PipTaskOrganizer#onTaskVanished(RunningTaskInfo)} is called.
     */
    void detach();

    /**
     * Check if menu is visible or not.
     */
    boolean isMenuVisible();

    /**
     * Show the PIP menu.
     */
    void showMenu();

    /**
     * Given a set of actions, update the menu.
     */
    void setAppActions(ParceledListSlice<RemoteAction> appActions);

    /**
     * Resize the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a
     * need to synchronize the movements on the same frame as PiP.
     */
    default void resizePipMenu(@Nullable SurfaceControl pipLeash,
            @Nullable SurfaceControl.Transaction t,
            Rect destinationBounds) {}

    /**
     * Move the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a
     * need to synchronize the movements on the same frame as PiP.
     */
    default void movePipMenu(@Nullable SurfaceControl pipLeash,
            @Nullable SurfaceControl.Transaction t,
            Rect destinationBounds) {}

    /**
     * Update the PiP menu with the given bounds for re-layout purposes.
     */
    default void updateMenuBounds(Rect destinationBounds) {}

    /**
     * Returns a default LayoutParams for the PIP Menu.
     * @param width the PIP stack width.
     * @param height the PIP stack height.
     */
    default WindowManager.LayoutParams getPipMenuLayoutParams(String title, int width, int height) {
        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
                TYPE_APPLICATION_OVERLAY,
                FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY | FLAG_NOT_TOUCHABLE,
                PixelFormat.TRANSLUCENT);
        lp.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
        lp.setTitle(title);
        return lp;
    }
}
+13 −23
Original line number Diff line number Diff line
@@ -63,7 +63,6 @@ import com.android.internal.os.SomeArgs;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.pip.phone.PipMenuActivityController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipUpdateThread;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -135,8 +134,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
    private final Handler mUpdateHandler;
    private final PipBoundsState mPipBoundsState;
    private final PipBoundsAlgorithm mPipBoundsAlgorithm;
    // TODO(b/172286265): Remove dependency on .pip.PHONE.PipMenuActivityController
    private final PipMenuActivityController mMenuActivityController;
    private final @NonNull PipMenuController mPipMenuController;
    private final PipAnimationController mPipAnimationController;
    private final PipUiEventLogger mPipUiEventLoggerLogger;
    private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
@@ -264,7 +262,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,

    public PipTaskOrganizer(Context context, @NonNull PipBoundsState pipBoundsState,
            @NonNull PipBoundsAlgorithm boundsHandler,
            PipMenuActivityController menuActivityController,
            @NonNull PipMenuController pipMenuController,
            @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
            Optional<SplitScreen> splitScreenOptional,
            @NonNull DisplayController displayController,
@@ -274,7 +272,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
        mPipBoundsState = pipBoundsState;
        mPipBoundsAlgorithm = boundsHandler;
        mMenuActivityController = menuActivityController;
        mPipMenuController = pipMenuController;
        mEnterExitAnimationDuration = context.getResources()
                .getInteger(R.integer.config_pipResizeAnimationDuration);
        mSurfaceTransactionHelper = surfaceTransactionHelper;
@@ -501,9 +499,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
            mOnDisplayIdChangeCallback.accept(info.displayId);
        }

        if (mMenuActivityController != null) {
            mMenuActivityController.onTaskAppeared();
        }
        mPipMenuController.attach(leash);


        if (mShouldIgnoreEnteringPipTransition) {
            final Rect destinationBounds = mPipBoundsState.getBounds();
@@ -674,9 +671,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        mPictureInPictureParams = null;
        mState = State.UNDEFINED;
        mPipUiEventLoggerLogger.setTaskInfo(null);
        if (mMenuActivityController != null) {
            mMenuActivityController.onTaskVanished();
        }
        mPipMenuController.detach();
    }

    @Override
@@ -956,9 +951,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        mSurfaceTransactionHelper
                .crop(tx, mLeash, destinationBounds)
                .round(tx, mLeash, mState.isInPip());
        if (mMenuActivityController != null && mMenuActivityController.isMenuVisible()) {
        if (mPipMenuController.isMenuVisible()) {
            runOnMainHandler(() ->
                    mMenuActivityController.resizePipMenu(mLeash, tx, destinationBounds));
                    mPipMenuController.resizePipMenu(mLeash, tx, destinationBounds));
        } else {
            tx.apply();
        }
@@ -982,9 +977,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,

        final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
        mSurfaceTransactionHelper.scale(tx, mLeash, startBounds, destinationBounds);
        if (mMenuActivityController != null && mMenuActivityController.isMenuVisible()) {
        if (mPipMenuController.isMenuVisible()) {
            runOnMainHandler(() ->
                    mMenuActivityController.movePipMenu(mLeash, tx, destinationBounds));
                    mPipMenuController.movePipMenu(mLeash, tx, destinationBounds));
        } else {
            tx.apply();
        }
@@ -1001,8 +996,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
            removePipImmediately();
            return;
        } else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA
                && mMenuActivityController != null) {
        } else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
            // TODO: Synchronize this correctly in #applyEnterPipSyncTransaction
            finishResizeForMenu(destinationBounds);
            return;
@@ -1015,13 +1009,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
    }

    private void finishResizeForMenu(Rect destinationBounds) {
        if (mMenuActivityController == null) {
            if (DEBUG) Log.d(TAG, "mMenuActivityController is null");
            return;
        }
        runOnMainHandler(() -> {
            mMenuActivityController.movePipMenu(null, null, destinationBounds);
            mMenuActivityController.updateMenuBounds(destinationBounds);
            mPipMenuController.movePipMenu(null, null, destinationBounds);
            mPipMenuController.updateMenuBounds(destinationBounds);
        });
    }

+30 −38
Original line number Diff line number Diff line
@@ -18,12 +18,6 @@ package com.android.wm.shell.pip.phone;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;

import android.annotation.Nullable;
@@ -33,7 +27,6 @@ import android.app.RemoteAction;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Debug;
@@ -44,27 +37,26 @@ import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;

import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipMediaController.ActionListener;
import com.android.wm.shell.pip.PipMenuController;

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

/**
 * Manages the PiP menu activity which can show menu options or a scrim.
 * Manages the PiP menu view which can show menu options or a scrim.
 *
 * The current media session provides actions whenever there are no valid actions provided by the
 * current PiP activity. Otherwise, those actions always take precedence.
 */
public class PipMenuActivityController {
public class PhonePipMenuController implements PipMenuController {

    private static final String TAG = "PipMenuActController";
    private static final String MENU_WINDOW_TITLE = "PipMenuView";
    private static final boolean DEBUG = false;

    public static final int MENU_STATE_NONE = 0;
@@ -124,7 +116,7 @@ public class PipMenuActivityController {
        }
    };

    public PipMenuActivityController(Context context,
    public PhonePipMenuController(Context context,
            PipMediaController mediaController, SystemWindows systemWindows) {
        mContext = context;
        mMediaController = mediaController;
@@ -138,20 +130,22 @@ public class PipMenuActivityController {
    /**
     * Attach the menu when the PiP task first appears.
     */
    public void onTaskAppeared() {
    @Override
    public void attach(SurfaceControl leash) {
        attachPipMenuView();
    }

    /**
     * Detach the menu when the PiP task is gone.
     */
    public void onTaskVanished() {
    @Override
    public void detach() {
        hideMenu();
        detachPipMenuView();
    }


    public void onPinnedStackAnimationEnded() {
    void onPinnedStackAnimationEnded() {
        if (isMenuVisible()) {
            mPipMenuView.onPipAnimationEnded();
        }
@@ -163,7 +157,9 @@ public class PipMenuActivityController {
            detachPipMenuView();
        }
        mPipMenuView = new PipMenuView(mContext, this);
        mSystemWindows.addView(mPipMenuView, getPipMenuLayoutParams(0, 0), 0, SHELL_ROOT_LAYER_PIP);
        mSystemWindows.addView(mPipMenuView,
                getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
                0, SHELL_ROOT_LAYER_PIP);
    }

    private void detachPipMenuView() {
@@ -181,9 +177,11 @@ public class PipMenuActivityController {
     * Updates the layout parameters of the menu.
     * @param destinationBounds New Menu bounds.
     */
    @Override
    public void updateMenuBounds(Rect destinationBounds) {
        mSystemWindows.updateViewLayout(mPipMenuView,
                getPipMenuLayoutParams(destinationBounds.width(), destinationBounds.height()));
                getPipMenuLayoutParams(MENU_WINDOW_TITLE, destinationBounds.width(),
                        destinationBounds.height()));
    }

    /**
@@ -205,6 +203,16 @@ public class PipMenuActivityController {
        }
    }

    /**
     * When other components requests the menu controller directly to show the menu, we must
     * first fire off the request to the other listeners who will then propagate the call
     * back to the controller with the right parameters.
     */
    @Override
    public void showMenu() {
        mListeners.forEach(Listener::onPipShowMenu);
    }

    /**
     * Similar to {@link #showMenu(int, Rect, boolean, boolean, boolean)} but only show the menu
     * upon PiP window transition is finished.
@@ -250,6 +258,7 @@ public class PipMenuActivityController {
    /**
     * Move the PiP menu, which does a translation and possibly a scale transformation.
     */
    @Override
    public void movePipMenu(@Nullable SurfaceControl pipLeash,
            @Nullable SurfaceControl.Transaction t,
            Rect destinationBounds) {
@@ -290,6 +299,7 @@ public class PipMenuActivityController {
    /**
     * Does an immediate window crop of the PiP menu.
     */
    @Override
    public void resizePipMenu(@Nullable SurfaceControl pipLeash,
            @Nullable SurfaceControl.Transaction t,
            Rect destinationBounds) {
@@ -391,8 +401,9 @@ public class PipMenuActivityController {
    }

    /**
     * Sets the menu actions to the actions provided by the current PiP activity.
     * Sets the menu actions to the actions provided by the current PiP menu.
     */
    @Override
    public void setAppActions(ParceledListSlice<RemoteAction> appActions) {
        mAppActions = appActions;
        updateMenuActions();
@@ -406,10 +417,6 @@ public class PipMenuActivityController {
        mListeners.forEach(Listener::onPipDismiss);
    }

    void onPipShowMenu() {
        mListeners.forEach(Listener::onPipShowMenu);
    }

    /**
     * @return the best set of actions to show in the PiP menu.
     */
@@ -420,21 +427,6 @@ public class PipMenuActivityController {
        return mMediaActions;
    }

    /**
     * Returns a default LayoutParams for the PIP Menu.
     * @param width the PIP stack width.
     * @param height the PIP stack height.
     */
    public static WindowManager.LayoutParams getPipMenuLayoutParams(int width, int height) {
        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
                TYPE_APPLICATION_OVERLAY,
                FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY | FLAG_NOT_TOUCHABLE,
                PixelFormat.TRANSLUCENT);
        lp.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
        lp.setTitle(MENU_WINDOW_TITLE);
        return lp;
    }

    /**
     * Updates the PiP menu with the best set of actions provided.
     */
@@ -521,7 +513,7 @@ public class PipMenuActivityController {
        }
    }

    public void dump(PrintWriter pw, String prefix) {
    void dump(PrintWriter pw, String prefix) {
        final String innerPrefix = prefix + "  ";
        pw.println(prefix + TAG);
        pw.println(innerPrefix + "mMenuState=" + mMenuState);
+5 −5
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
    private boolean mIsInFixedRotation;
    private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;

    protected PipMenuActivityController mMenuController;
    protected PhonePipMenuController mMenuController;
    protected PipTaskOrganizer mPipTaskOrganizer;
    protected PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener =
            new PipControllerPinnedStackListener();
@@ -229,7 +229,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
            PipBoundsAlgorithm pipBoundsAlgorithm,
            @NonNull PipBoundsState pipBoundsState,
            PipMediaController pipMediaController,
            PipMenuActivityController pipMenuActivityController,
            PhonePipMenuController phonePipMenuController,
            PipTaskOrganizer pipTaskOrganizer,
            PipTouchHandler pipTouchHandler,
            WindowManagerShellWrapper windowManagerShellWrapper,
@@ -250,7 +250,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
        mPipTaskOrganizer = pipTaskOrganizer;
        mMainExecutor = mainExecutor;
        mMediaController = pipMediaController;
        mMenuController = pipMenuActivityController;
        mMenuController = phonePipMenuController;
        mTouchHandler = pipTouchHandler;
        mAppOpsListener = pipAppOpsListener;
        mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
@@ -632,7 +632,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
    public static PipController create(Context context, DisplayController displayController,
            PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
            PipBoundsState pipBoundsState, PipMediaController pipMediaController,
            PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
            PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
            PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
            TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
        if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
@@ -641,7 +641,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
        }

        return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm,
                pipBoundsState, pipMediaController, pipMenuActivityController, pipTaskOrganizer,
                pipBoundsState, pipMediaController, phonePipMenuController, pipTaskOrganizer,
                pipTouchHandler, windowManagerShellWrapper, taskStackListener, mainExecutor);
    }
}
+6 −6
Original line number Diff line number Diff line
@@ -23,9 +23,9 @@ import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTR
import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;

import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -105,7 +105,7 @@ public class PipMenuView extends FrameLayout {
    private int mBetweenActionPaddingLand;

    private AnimatorSet mMenuContainerAnimator;
    private PipMenuActivityController mController;
    private PhonePipMenuController mController;

    private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
            new ValueAnimator.AnimatorUpdateListener() {
@@ -127,7 +127,7 @@ public class PipMenuView extends FrameLayout {
    protected View mTopEndContainer;
    protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;

    public PipMenuView(Context context, PipMenuActivityController controller) {
    public PipMenuView(Context context, PhonePipMenuController controller) {
        super(context, null, 0);
        mContext = context;
        mController = controller;
@@ -182,7 +182,7 @@ public class PipMenuView extends FrameLayout {
            @Override
            public boolean performAccessibilityAction(View host, int action, Bundle args) {
                if (action == ACTION_CLICK && mMenuState == MENU_STATE_CLOSE) {
                    mController.onPipShowMenu();
                    mController.showMenu();
                }
                return super.performAccessibilityAction(host, action, args);
            }
Loading