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

Commit 835dd731 authored by Mateusz Cicheński's avatar Mateusz Cicheński
Browse files

Move PiP in response to keep clear areas changed events.

PiP window will gravitate towards bottom of the screen if it's in the bottom half of it.
PiP window will gravitate towards left/right edge of screen, whichever is closer.
PiP window will avoid occluding any reported keep clear areas.

Test: manually, existing tests pass
Bug: 183746978

Change-Id: Idb481fee7ead67734c5de0d833b281ca2a2aaaa8
parent c0894151
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -81,6 +81,9 @@
    <!-- The width and height of the background for custom action in PiP menu. -->
    <dimen name="pip_custom_close_bg_size">32dp</dimen>

    <!-- Extra padding between picture-in-picture windows and any registered keep clear areas. -->
    <dimen name="pip_keep_clear_areas_padding">16dp</dimen>

    <dimen name="dismiss_target_x_size">24dp</dimen>
    <dimen name="floating_dismiss_bottom_margin">50dp</dimen>

+8 −6
Original line number Diff line number Diff line
@@ -72,9 +72,9 @@ import com.android.wm.shell.pip.PipTransition;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.pip.phone.PipController;
import com.android.wm.shell.pip.phone.PipKeepClearAlgorithm;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasksController;
@@ -320,7 +320,7 @@ public abstract class WMShellModule {
            DisplayController displayController,
            PipAppOpsListener pipAppOpsListener,
            PipBoundsAlgorithm pipBoundsAlgorithm,
            PipKeepClearAlgorithm pipKeepClearAlgorithm,
            PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
            PipBoundsState pipBoundsState,
            PipMotionHelper pipMotionHelper,
            PipMediaController pipMediaController,
@@ -357,15 +357,17 @@ public abstract class WMShellModule {

    @WMSingleton
    @Provides
    static PipKeepClearAlgorithm providePipKeepClearAlgorithm() {
        return new PipKeepClearAlgorithm();
    static PhonePipKeepClearAlgorithm providePhonePipKeepClearAlgorithm(Context context) {
        return new PhonePipKeepClearAlgorithm(context);
    }

    @WMSingleton
    @Provides
    static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
            PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm) {
        return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm);
            PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
            PhonePipKeepClearAlgorithm pipKeepClearAlgorithm) {
        return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm,
                pipKeepClearAlgorithm);
    }

    // Handler is used by Icon.loadDrawableAsync
+3 −2
Original line number Diff line number Diff line
@@ -37,12 +37,13 @@ interface IPip {
     * @param activityInfo ActivityInfo tied to the Activity
     * @param pictureInPictureParams PictureInPictureParams tied to the Activity
     * @param launcherRotation Launcher rotation to calculate the PiP destination bounds
     * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds
     * @param hotseatKeepClearArea Bounds of Hotseat to avoid used to calculate PiP destination
              bounds
     * @return destination bounds the PiP window should land into
     */
    Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo,
                in PictureInPictureParams pictureInPictureParams,
                int launcherRotation, int shelfHeight) = 1;
                int launcherRotation, in Rect hotseatKeepClearArea) = 1;

    /**
     * Notifies the swiping Activity to PiP onto home transition is finished
+20 −3
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ public class PipBoundsAlgorithm {

    private final @NonNull PipBoundsState mPipBoundsState;
    private final PipSnapAlgorithm mSnapAlgorithm;
    private final PipKeepClearAlgorithm mPipKeepClearAlgorithm;

    private float mDefaultSizePercent;
    private float mMinAspectRatioForMinSize;
@@ -60,9 +61,11 @@ public class PipBoundsAlgorithm {
    protected Point mScreenEdgeInsets;

    public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState,
            @NonNull PipSnapAlgorithm pipSnapAlgorithm) {
            @NonNull PipSnapAlgorithm pipSnapAlgorithm,
            @NonNull PipKeepClearAlgorithm pipKeepClearAlgorithm) {
        mPipBoundsState = pipBoundsState;
        mSnapAlgorithm = pipSnapAlgorithm;
        mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
        reloadResources(context);
        // Initialize the aspect ratio to the default aspect ratio.  Don't do this in reload
        // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
@@ -129,8 +132,21 @@ public class PipBoundsAlgorithm {
        return getDefaultBounds(INVALID_SNAP_FRACTION, null /* size */);
    }

    /** Returns the destination bounds to place the PIP window on entry. */
    /**
     * Returns the destination bounds to place the PIP window on entry.
     * If there are any keep clear areas registered, the position will try to avoid occluding them.
     */
    public Rect getEntryDestinationBounds() {
        Rect entryBounds = getEntryDestinationBoundsIgnoringKeepClearAreas();
        Rect insets = new Rect();
        getInsetBounds(insets);
        return mPipKeepClearAlgorithm.findUnoccludedPosition(entryBounds,
                mPipBoundsState.getRestrictedKeepClearAreas(),
                mPipBoundsState.getUnrestrictedKeepClearAreas(), insets);
    }

    /** Returns the destination bounds to place the PIP window on entry. */
    public Rect getEntryDestinationBoundsIgnoringKeepClearAreas() {
        final PipBoundsState.PipReentryState reentryState = mPipBoundsState.getReentryState();

        final Rect destinationBounds = reentryState != null
@@ -138,9 +154,10 @@ public class PipBoundsAlgorithm {
                : getDefaultBounds();

        final boolean useCurrentSize = reentryState != null && reentryState.getSize() != null;
        return transformBoundsToAspectRatioIfValid(destinationBounds,
        Rect aspectRatioBounds = transformBoundsToAspectRatioIfValid(destinationBounds,
                mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
                useCurrentSize);
        return aspectRatioBounds;
    }

    /** Returns the current bounds adjusted to the new aspect ratio, if valid. */
+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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 android.graphics.Rect;

import java.util.Set;

/**
 * Interface for interacting with keep clear algorithm used to move PiP window out of the way of
 * keep clear areas.
 */
public interface PipKeepClearAlgorithm {

    /**
     * Adjust the position of picture in picture window based on the registered keep clear areas.
     * @param pipBoundsState state of the PiP to use for the calculations
     * @param pipBoundsAlgorithm algorithm implementation used to get the entry destination bounds
     * @return
     */
    default Rect adjust(PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm) {
        return pipBoundsState.getBounds();
    }

    /**
     * Calculate the bounds so that none of the keep clear areas are occluded, while the bounds stay
     * within the allowed bounds. If such position is not feasible, return original bounds.
     * @param defaultBounds initial bounds used in the calculation
     * @param restrictedKeepClearAreas registered restricted keep clear areas
     * @param unrestrictedKeepClearAreas registered unrestricted keep clear areas
     * @param allowedBounds bounds that define the allowed space for the output, result will always
     *                      be inside those bounds
     * @return bounds that don't cover any of the keep clear areas and are within allowed bounds
     */
    default Rect findUnoccludedPosition(Rect defaultBounds, Set<Rect> restrictedKeepClearAreas,
            Set<Rect> unrestrictedKeepClearAreas, Rect allowedBounds) {
        return defaultBounds;
    }
}
Loading