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

Commit 2d80fed9 authored by Mady Mellor's avatar Mady Mellor
Browse files

Bubbles: improve how rotation is listened for

Previously we relied on ConfigurationListener for
rotation, however, this relies on portrait / landscape
rather than the actual rotation of the device (e.g. 90
vs 270) so if the device was rotated from 90 to 270
(both 'landscape') we wouldn't be notified to update the
position of the bubble.

Fix is to use onDisplayChangingListener to get the exact
rotation. This is notified *before* the layout has
happened for the new config so updates to the positioner
have moved into BubbleStackView where there's a layout
listener in response to the orientation.

Fixes: 182172825
Fixes: 172530640
Test: - Have a bubble
      - Put device in landscape
      - Rotate it to be landscape again but on the other
        side
      - Rotate back to portrait
      => Note that the bubble is always along the edge
         of the phone & never goes off screen or is in
         the middle of the screen
      => Also expand the stack in each of these steps to
         ensure the bubbles are at the top in portrait
         and at the sides in landscape
Test: - Have a bubble, expand it
      - Rotate the device several times, make sure the
        position of the bubbles & expanded view are
        correct
Test: - Have bubbles on left edge
      - Change the screen size
      => Notice that the bubbles are placed correctly
Change-Id: I76e97529d991102e5b052176bff29e1063537273
parent 681f269d
Loading
Loading
Loading
Loading
+39 −21
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -70,6 +71,7 @@ import android.util.SparseSetArray;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.window.WindowContainerTransaction;

import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
@@ -79,6 +81,8 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerCallback;
@@ -131,6 +135,7 @@ public class BubbleController {
    private final WindowManager mWindowManager;
    private final TaskStackListenerImpl mTaskStackListener;
    private final ShellTaskOrganizer mTaskOrganizer;
    private final DisplayController mDisplayController;

    // Used to post to main UI thread
    private final ShellExecutor mMainExecutor;
@@ -171,25 +176,21 @@ public class BubbleController {
    /** Whether or not the BubbleStackView has been added to the WindowManager. */
    private boolean mAddedToWindowManager = false;

    /** Last known orientation, used to detect orientation changes in {@link #onConfigChanged}. */
    private int mOrientation = Configuration.ORIENTATION_UNDEFINED;

    /**
     * Last known screen density, used to detect display size changes in {@link #onConfigChanged}.
     */
    /** Saved screen density, used to detect display size changes in {@link #onConfigChanged}. */
    private int mDensityDpi = Configuration.DENSITY_DPI_UNDEFINED;

    /**
     * Last known font scale, used to detect font size changes in {@link #onConfigChanged}.
     */
    /** Saved screen bounds, used to detect screen size changes in {@link #onConfigChanged}. **/
    private Rect mScreenBounds = new Rect();

    /** Saved font scale, used to detect font size changes in {@link #onConfigChanged}. */
    private float mFontScale = 0;

    /** Last known direction, used to detect layout direction changes @link #onConfigChanged}. */
    /** Saved direction, used to detect layout direction changes @link #onConfigChanged}. */
    private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED;

    private boolean mInflateSynchronously;

    /** true when user is in status bar unlock shade. */
    /** True when user is in status bar unlock shade. */
    private boolean mIsStatusBarShade = true;

    /**
@@ -205,6 +206,7 @@ public class BubbleController {
            TaskStackListenerImpl taskStackListener,
            UiEventLogger uiEventLogger,
            ShellTaskOrganizer organizer,
            DisplayController displayController,
            ShellExecutor mainExecutor,
            Handler mainHandler) {
        BubbleLogger logger = new BubbleLogger(uiEventLogger);
@@ -213,7 +215,8 @@ public class BubbleController {
        return new BubbleController(context, data, synchronizer, floatingContentCoordinator,
                new BubbleDataRepository(context, launcherApps, mainExecutor),
                statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
                logger, taskStackListener, organizer, positioner, mainExecutor, mainHandler);
                logger, taskStackListener, organizer, positioner, displayController, mainExecutor,
                mainHandler);
    }

    /**
@@ -233,6 +236,7 @@ public class BubbleController {
            TaskStackListenerImpl taskStackListener,
            ShellTaskOrganizer organizer,
            BubblePositioner positioner,
            DisplayController displayController,
            ShellExecutor mainExecutor,
            Handler mainHandler) {
        mContext = context;
@@ -256,6 +260,7 @@ public class BubbleController {
        mBubbleData = data;
        mSavedBubbleKeysPerUser = new SparseSetArray<>();
        mBubbleIconFactory = new BubbleIconFactory(context);
        mDisplayController = displayController;
    }

    public void initialize() {
@@ -287,7 +292,6 @@ public class BubbleController {
            e.printStackTrace();
        }


        mBubbleData.setCurrentUserId(mCurrentUserId);

        mTaskOrganizer.addLocusIdListener((taskId, locus, visible) ->
@@ -366,6 +370,23 @@ public class BubbleController {
                }
            }
        });

        mDisplayController.addDisplayChangingController(
                new DisplayChangeController.OnDisplayChangingListener() {
                    @Override
                    public void onRotateDisplay(int displayId, int fromRotation, int toRotation,
                            WindowContainerTransaction t) {
                        // This is triggered right before the rotation is applied
                        if (fromRotation != toRotation) {
                            mBubblePositioner.setRotation(toRotation);
                            if (mStackView != null) {
                                // Layout listener set on stackView will update the positioner
                                // once the rotation is applied
                                mStackView.onOrientationChanged();
                            }
                        }
                    }
                });
    }

    @VisibleForTesting
@@ -585,7 +606,7 @@ public class BubbleController {
            mStackView.addView(mBubbleScrim);
            mWindowManager.addView(mStackView, mWmLayoutParams);
            // Position info is dependent on us being attached to a window
            mBubblePositioner.update(mOrientation);
            mBubblePositioner.update();
        } catch (IllegalStateException e) {
            // This means the stack has already been added. This shouldn't happen...
            e.printStackTrace();
@@ -682,16 +703,13 @@ public class BubbleController {

    private void onConfigChanged(Configuration newConfig) {
        if (mBubblePositioner != null) {
            // This doesn't trigger any changes, always update it
            mBubblePositioner.update(newConfig.orientation);
            mBubblePositioner.update();
        }
        if (mStackView != null && newConfig != null) {
            if (newConfig.orientation != mOrientation) {
                mOrientation = newConfig.orientation;
                mStackView.onOrientationChanged();
            }
            if (newConfig.densityDpi != mDensityDpi) {
            if (newConfig.densityDpi != mDensityDpi
                    || !newConfig.windowConfiguration.getBounds().equals(mScreenBounds)) {
                mDensityDpi = newConfig.densityDpi;
                mScreenBounds.set(newConfig.windowConfiguration.getBounds());
                mBubbleIconFactory = new BubbleIconFactory(mContext);
                mStackView.onDisplaySizeChanged();
            }
+16 −13
Original line number Diff line number Diff line
@@ -20,13 +20,13 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import android.view.Surface;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -65,7 +65,7 @@ public class BubblePositioner {
    private Context mContext;
    private WindowManager mWindowManager;
    private Rect mPositionRect;
    private int mOrientation;
    private @Surface.Rotation int mRotation = Surface.ROTATION_0;
    private Insets mInsets;

    private int mBubbleSize;
@@ -82,14 +82,18 @@ public class BubblePositioner {
    public BubblePositioner(Context context, WindowManager windowManager) {
        mContext = context;
        mWindowManager = windowManager;
        update(Configuration.ORIENTATION_UNDEFINED);
        update();
    }

    public void setRotation(int rotation) {
        mRotation = rotation;
    }

    /**
     * Updates orientation, available space, and inset information. Call this when config changes
     * Available space and inset information. Call this when config changes
     * occur or when added to a window.
     */
    public void update(int orientation) {
    public void update() {
        WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
        if (windowMetrics == null) {
            return;
@@ -102,12 +106,12 @@ public class BubblePositioner {

        if (BubbleDebugConfig.DEBUG_POSITIONER) {
            Log.w(TAG, "update positioner:"
                    + " landscape= " + (orientation == Configuration.ORIENTATION_LANDSCAPE)
                    + " rotation= " + mRotation
                    + " insets: " + insets
                    + " bounds: " + windowMetrics.getBounds()
                    + " showingInTaskbar: " + mShowingInTaskbar);
        }
        updateInternal(orientation, insets, windowMetrics.getBounds());
        updateInternal(mRotation, insets, windowMetrics.getBounds());
    }

    /**
@@ -122,12 +126,12 @@ public class BubblePositioner {
        mTaskbarIconSize =  iconSize;
        mTaskbarPosition = taskbarPosition;
        mTaskbarSize = taskbarSize;
        update(mOrientation);
        update();
    }

    @VisibleForTesting
    public void updateInternal(int orientation, Insets insets, Rect bounds) {
        mOrientation = orientation;
    public void updateInternal(int rotation, Insets insets, Rect bounds) {
        mRotation = rotation;
        mInsets = insets;

        mPositionRect = new Rect(bounds);
@@ -189,7 +193,7 @@ public class BubblePositioner {
     * @return whether the device is in landscape orientation.
     */
    public boolean isLandscape() {
        return mOrientation == Configuration.ORIENTATION_LANDSCAPE;
        return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270;
    }

    /**
@@ -200,8 +204,7 @@ public class BubblePositioner {
     * to the left or right side.
     */
    public boolean showBubblesVertically() {
        return mOrientation == Configuration.ORIENTATION_LANDSCAPE
                || mShowingInTaskbar;
        return isLandscape() || mShowingInTaskbar;
    }

    /** Size of the bubble account for badge & dot. */
+10 −4
Original line number Diff line number Diff line
@@ -884,6 +884,7 @@ public class BubbleStackView extends FrameLayout

        mOrientationChangedListener =
                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                    mPositioner.update();
                    onDisplaySizeChanged();
                    mExpandedAnimationController.updateResources();
                    mStackAnimationController.updateResources();
@@ -1214,11 +1215,12 @@ public class BubbleStackView extends FrameLayout
        updateExpandedViewTheme();
    }

    /** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */
    /**
     * Respond to the phone being rotated by repositioning the stack and hiding any flyouts.
     * This is called prior to the rotation occurring, any values that should be updated
     * based on the new rotation should occur in {@link #mOrientationChangedListener}.
     */
    public void onOrientationChanged() {
        Resources res = getContext().getResources();
        mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);

        mRelativeStackPositionBeforeRotation = new RelativeStackPosition(
                mPositioner.getRestingPosition(),
                mStackAnimationController.getAllowableStackPositionRegion());
@@ -1261,6 +1263,10 @@ public class BubbleStackView extends FrameLayout
        mStackAnimationController.updateResources();
        mDismissView.updateResources();
        mMagneticTarget.setMagneticFieldRadiusPx(mBubbleSize * 2);
        mStackAnimationController.setStackPosition(
                new RelativeStackPosition(
                        mPositioner.getRestingPosition(),
                        mStackAnimationController.getAllowableStackPositionRegion()));
    }

    @Override
+2 −1
Original line number Diff line number Diff line
@@ -189,12 +189,13 @@ public abstract class WMShellBaseModule {
            TaskStackListenerImpl taskStackListener,
            UiEventLogger uiEventLogger,
            ShellTaskOrganizer organizer,
            DisplayController displayController,
            @ShellMainThread ShellExecutor mainExecutor,
            @ShellMainThread Handler mainHandler) {
        return Optional.of(BubbleController.create(context, null /* synchronizer */,
                floatingContentCoordinator, statusBarService, windowManager,
                windowManagerShellWrapper, launcherApps, taskStackListener,
                uiEventLogger, organizer, mainExecutor, mainHandler));
                uiEventLogger, organizer, displayController, mainExecutor, mainHandler));
    }

    //
+2 −0
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.bubbles.BubbleViewInfoTask;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -315,6 +316,7 @@ public class BubblesTest extends SysuiTestCase {
                mTaskStackListener,
                mShellTaskOrganizer,
                mPositioner,
                mock(DisplayController.class),
                syncExecutor,
                mock(Handler.class));
        mBubbleController.setExpandListener(mBubbleExpandListener);
Loading