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

Commit 43a752be authored by Hongwei Wang's avatar Hongwei Wang
Browse files

Move bounds calculation and snap fraction to SysUI

Major changes in this CL

- Added PipBoundsHandler in SysUI package handles the bounds calculation
and save/restore the snap fraction
- Added IPinnedStackListener.onSaveReentrySnapFraction and
IPinnedStackListener.onResetReentrySnapFration, both called from
PinnedStackController (WM) to SysUI
- Added IPinnedStackListener.onPrepareAnimation, called from WM to
SysUI to notify that an animation for pinned stack is about to happen
- Added IPinnedStackController.startAnimation, called from SysUI to WM
to actually start the pinned stack animation
- Updated tv/PipManager to use PipBoundsHandler as well

Known issues and what's next

- Shelf height is set after the animation is started, therefore one may
notice the PiP window is hovering over the shelf. This is tracked
separatedly by b/139016518
- Bounds calculations still exist in PinnedStackController since
onTaskStackChanged callback requires so. Once we addressed b/139016833
(move rotation bounds calculation to SysUI), they should be all gone.
- Move the pinned stack animation from WM to SysUI and we can furthre
remove IPinnedStackListener.onPrepareAnimation and
IPinnedStackController.startAnimation

More details: go/pip-sysui-migration

Bug: 139015463
Bug: 139015142
Test: atest PinnedStackTests
Test: atest PinnedStackControllerTest
Change-Id: Ib62d8152ecc7b18a671ec403af44cc517612169e
parent 7759895e
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.view;

import android.graphics.Rect;

/**
 * An interface to the PinnedStackController to update it of state changes, and to query
 * information based on the current state.
@@ -30,15 +32,17 @@ interface IPinnedStackController {
    oneway void setIsMinimized(boolean isMinimized);

    /**
     * Notifies the controller of the current min edge size, this is needed to allow the system to
     * properly calculate the aspect ratio of the expanded PIP.  The given {@param minEdgeSize} is
     * always bounded to be larger than the default minEdgeSize, so the caller can call this method
     * with 0 to reset to the default size.
     * @return what WM considers to be the current device rotation.
     */
    oneway void setMinEdgeSize(int minEdgeSize);
    int getDisplayRotation();

    /**
     * @return what WM considers to be the current device rotation.
     * Notifies the controller to actually start the PiP animation.
     * The bounds would be calculated based on the last save reentry fraction internally.
     * {@param destinationBounds} is the stack bounds of the final PiP window
     * and {@param sourceRectHint} is the source bounds hint used when entering picture-in-picture,
     * expect the same bound passed via IPinnedStackListener#onPrepareAnimation.
     * {@param animationDuration} suggests the animation duration transitioning to PiP window.
     */
    int getDisplayRotation();
    void startAnimation(in Rect destinationBounds, in Rect sourceRectHint, int animationDuration);
}
+51 −11
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

package android.view;

import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.graphics.Rect;
import android.view.DisplayInfo;
import android.view.IPinnedStackController;

/**
@@ -36,18 +38,13 @@ oneway interface IPinnedStackListener {
    /**
     * Called when the window manager has detected a change that would cause the movement bounds
     * to be changed (ie. after configuration change, aspect ratio change, etc). It then provides
     * the components that allow the listener to calculate the movement bounds itself. The
     * {@param normalBounds} are also the default bounds that the PiP would be entered in its
     * current state with the aspect ratio applied.  The {@param animatingBounds} are provided
     * to indicate the current target bounds of the pinned stack (the final bounds if animating,
     * the current bounds if not), which may be helpful in calculating dependent animation bounds.
     *
     * The {@param displayRotation} is provided so that the client can verify when making certain
     * calls that it will not provide stale information based on an old display rotation (ie. if
     * the WM has changed in the mean time but the client has not received onMovementBoundsChanged).
     * the components that allow the listener to calculate the movement bounds itself.
     * The {@param animatingBounds} are provided to indicate the current target bounds of the
     * pinned stack (the final bounds if animating, the current bounds if not),
     * which may be helpful in calculating dependent animation bounds.
     */
    void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds, in Rect animatingBounds,
            boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation);
    void onMovementBoundsChanged(in Rect animatingBounds, boolean fromImeAdjustment,
            boolean fromShelfAdjustment);

    /**
     * Called when window manager decides to adjust the pinned stack bounds because of the IME, or
@@ -76,4 +73,47 @@ oneway interface IPinnedStackListener {
     * is first registered to allow the listener to synchronized its state with the controller.
     */
    void onActionsChanged(in ParceledListSlice actions);

    /**
     * Called by the window manager to notify the listener to save the reentry fraction,
     * typically when an Activity leaves PiP (picture-in-picture) mode to fullscreen.
     * {@param componentName} represents the application component of PiP window
     * while {@param bounds} is the current PiP bounds used to calculate the
     * reentry snap fraction.
     */
    void onSaveReentrySnapFraction(in ComponentName componentName, in Rect bounds);

    /**
     * Called by the window manager to notify the listener to reset saved reentry fraction,
     * typically when an Activity enters PiP (picture-in-picture) mode from fullscreen.
     * {@param componentName} represents the application component of PiP window.
     */
    void onResetReentrySnapFraction(in ComponentName componentName);

    /**
     * Called when the window manager has detected change on DisplayInfo,  or
     * when the listener is first registered to allow the listener to synchronized its state with
     * the controller.
     */
    void onDisplayInfoChanged(in DisplayInfo displayInfo);

    /**
     * Called by the window manager at the beginning of a configuration update cascade
     * since the metrics from these resources are used for bounds calculations.
     */
    void onConfigurationChanged();

    /**
     * Called by the window manager when the aspect ratio is reset.
     */
    void onAspectRatioChanged(float aspectRatio);

    /**
     * Called by the window manager to notify the listener to prepare for PiP animation.
     * Internally, the target bounds would be calculated from the given {@param aspectRatio}
     * and {@param bounds}, the saved reentry snap fraction also contributes.
     * Caller would wait for a IPinnedStackController#startAnimation callback to actually
     * start the animation, see details in IPinnedStackController.
     */
    void onPrepareAnimation(in Rect sourceRectHint, float aspectRatio, in Rect bounds);
}
+93 −22
Original line number Diff line number Diff line
@@ -16,9 +16,10 @@

package com.android.systemui.shared.system;

import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.graphics.Rect;
import android.os.RemoteException;
import android.view.DisplayInfo;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;

@@ -32,62 +33,132 @@ import java.util.List;
 * previously set listener.
 */
public class PinnedStackListenerForwarder extends IPinnedStackListener.Stub {
    private List<IPinnedStackListener> mListeners = new ArrayList<>();
    private List<PinnedStackListener> mListeners = new ArrayList<>();

    /** Adds a listener to receive updates from the WindowManagerService. */
    public void addListener(IPinnedStackListener listener) {
    public void addListener(PinnedStackListener listener) {
        mListeners.add(listener);
    }

    /** Removes a listener so it will no longer receive updates from the WindowManagerService. */
    public void removeListener(IPinnedStackListener listener) {
    public void removeListener(PinnedStackListener listener) {
        mListeners.remove(listener);
    }

    @Override
    public void onListenerRegistered(IPinnedStackController controller) throws RemoteException {
        for (IPinnedStackListener listener : mListeners) {
    public void onListenerRegistered(IPinnedStackController controller) {
        for (PinnedStackListener listener : mListeners) {
            listener.onListenerRegistered(controller);
        }
    }

    @Override
    public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect animatingBounds,
            boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation)
            throws RemoteException {
        for (IPinnedStackListener listener : mListeners) {
            listener.onMovementBoundsChanged(
                    insetBounds, normalBounds, animatingBounds,
                    fromImeAdjustment, fromShelfAdjustment, displayRotation);
    public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment,
            boolean fromShelfAdjustment) {
        for (PinnedStackListener listener : mListeners) {
            listener.onMovementBoundsChanged(animatingBounds, fromImeAdjustment,
                    fromShelfAdjustment);
        }
    }

    @Override
    public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) throws RemoteException {
        for (IPinnedStackListener listener : mListeners) {
    public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
        for (PinnedStackListener listener : mListeners) {
            listener.onImeVisibilityChanged(imeVisible, imeHeight);
        }
    }

    @Override
    public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight)
            throws RemoteException {
        for (IPinnedStackListener listener : mListeners) {
    public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
        for (PinnedStackListener listener : mListeners) {
            listener.onShelfVisibilityChanged(shelfVisible, shelfHeight);
        }
    }

    @Override
    public void onMinimizedStateChanged(boolean isMinimized) throws RemoteException {
        for (IPinnedStackListener listener : mListeners) {
    public void onMinimizedStateChanged(boolean isMinimized) {
        for (PinnedStackListener listener : mListeners) {
            listener.onMinimizedStateChanged(isMinimized);
        }
    }

    @Override
    public void onActionsChanged(ParceledListSlice actions) throws RemoteException {
        for (IPinnedStackListener listener : mListeners) {
    public void onActionsChanged(ParceledListSlice actions) {
        for (PinnedStackListener listener : mListeners) {
            listener.onActionsChanged(actions);
        }
    }

    @Override
    public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {
        for (PinnedStackListener listener : mListeners) {
            listener.onSaveReentrySnapFraction(componentName, bounds);
        }
    }

    @Override
    public void onResetReentrySnapFraction(ComponentName componentName) {
        for (PinnedStackListener listener : mListeners) {
            listener.onResetReentrySnapFraction(componentName);
        }
    }

    @Override
    public void onDisplayInfoChanged(DisplayInfo displayInfo) {
        for (PinnedStackListener listener : mListeners) {
            listener.onDisplayInfoChanged(displayInfo);
        }
    }

    @Override
    public void onConfigurationChanged() {
        for (PinnedStackListener listener : mListeners) {
            listener.onConfigurationChanged();
        }
    }

    @Override
    public void onAspectRatioChanged(float aspectRatio) {
        for (PinnedStackListener listener : mListeners) {
            listener.onAspectRatioChanged(aspectRatio);
        }
    }

    @Override
    public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {
        for (PinnedStackListener listener : mListeners) {
            listener.onPrepareAnimation(sourceRectHint, aspectRatio, bounds);
        }
    }

    /**
     * A counterpart of {@link IPinnedStackListener} with empty implementations.
     * Subclasses can ignore those methods they do not intend to take action upon.
     */
    public static class PinnedStackListener {
        public void onListenerRegistered(IPinnedStackController controller) {}

        public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment,
                boolean fromShelfAdjustment) {}

        public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}

        public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {}

        public void onMinimizedStateChanged(boolean isMinimized) {}

        public void onActionsChanged(ParceledListSlice actions) {}

        public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {}

        public void onResetReentrySnapFraction(ComponentName componentName) {}

        public void onDisplayInfoChanged(DisplayInfo displayInfo) {}

        public void onConfigurationChanged() {}

        public void onAspectRatioChanged(float aspectRatio) {}

        public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {}
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -27,12 +27,12 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.IPinnedStackListener;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;

import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;

public class WindowManagerWrapper {

@@ -212,7 +212,7 @@ public class WindowManagerWrapper {
     * Adds a pinned stack listener, which will receive updates from the window manager service
     * along with any other pinned stack listeners that were added via this method.
     */
    public void addPinnedStackListener(IPinnedStackListener listener) throws RemoteException {
    public void addPinnedStackListener(PinnedStackListener listener) throws RemoteException {
        mPinnedStackListenerForwarder.addListener(listener);
        WindowManagerGlobal.getWindowManagerService().registerPinnedStackListener(
                DEFAULT_DISPLAY, mPinnedStackListenerForwarder);
@@ -221,7 +221,7 @@ public class WindowManagerWrapper {
    /**
     * Removes a pinned stack listener.
     */
    public void removePinnedStackListener(IPinnedStackListener listener) {
    public void removePinnedStackListener(PinnedStackListener listener) {
        mPinnedStackListenerForwarder.removeListener(listener);
    }
}
+2 −24
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
@@ -61,8 +60,6 @@ import android.util.Log;
import android.util.Pair;
import android.util.SparseSetArray;
import android.view.Display;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;

@@ -76,6 +73,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PinnedStackListenerForwarder;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -993,32 +991,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
    }

    /** PinnedStackListener that dispatches IME visibility updates to the stack. */
    private class BubblesImeListener extends IPinnedStackListener.Stub {

        @Override
        public void onListenerRegistered(IPinnedStackController controller) throws RemoteException {
        }

        @Override
        public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
                Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
                int displayRotation) throws RemoteException {}

    private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedStackListener {
        @Override
        public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
            if (mStackView != null && mStackView.getBubbleCount() > 0) {
                mStackView.post(() -> mStackView.onImeVisibilityChanged(imeVisible, imeHeight));
            }
        }

        @Override
        public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight)
                throws RemoteException {}

        @Override
        public void onMinimizedStateChanged(boolean isMinimized) throws RemoteException {}

        @Override
        public void onActionsChanged(ParceledListSlice actions) throws RemoteException {}
    }
}
Loading