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

Commit 44ee2fec authored by Mady Mellor's avatar Mady Mellor
Browse files

Allow bubbles to be displayed at the bottom of the screen

* Positions the bubbles to show at the bottom of the screen, above the
 'dismiss' target UI by default
* Adds flag to toggle bubbles to show at the top of the screen instead
* Adds flag to show bubble header as a footer instead

Test: manual - have bubbles, expand them, note that they are positioned at
      bottom of screen
Bug: 123540009
Change-Id: I938d3ab7d4ec6f6bd88f3a33f73a97d5f80a45f5
parent a54cb88d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_height="@dimen/bubble_permission_height"
    android:animateLayoutChanges="true"
    android:orientation="vertical"
    android:paddingStart="@dimen/bubble_expanded_header_horizontal_padding"
+4 −0
Original line number Diff line number Diff line
@@ -1045,4 +1045,8 @@
    <dimen name="bubble_header_icon_size">48dp</dimen>
    <!-- Size of the app icon shown in the bubble permission view -->
    <dimen name="bubble_permission_icon_size">24dp</dimen>
    <!-- Space between the pointer triangle and the bubble expanded view -->
    <dimen name="bubble_pointer_margin">8dp</dimen>
    <!-- Height of the permission prompt shown with bubbles -->
    <dimen name="bubble_permission_height">120dp</dimen>
</resources>
+25 −4
Original line number Diff line number Diff line
@@ -80,16 +80,21 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
    // Enables some subset of notifs to automatically become bubbles
    private static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;

    // Secure settings flags
    // Feature level flag
    /** Flag to enable or disable the entire feature */
    private static final String ENABLE_BUBBLES = "experiment_enable_bubbles";
    // Auto bubble flags set whether different notification types should be presented as a bubble
    /** Auto bubble flags set whether different notif types should be presented as a bubble */
    private static final String ENABLE_AUTO_BUBBLE_MESSAGES = "experiment_autobubble_messaging";
    private static final String ENABLE_AUTO_BUBBLE_ONGOING = "experiment_autobubble_ongoing";
    private static final String ENABLE_AUTO_BUBBLE_ALL = "experiment_autobubble_all";
    // Use an activity view for an auto-bubbled notification if it has an appropriate content intent

    /** Use an activityView for an auto-bubbled notifs if it has an appropriate content intent */
    private static final String ENABLE_BUBBLE_CONTENT_INTENT = "experiment_bubble_content_intent";

    /** Whether the row of bubble circles are anchored to the top or bottom of the screen. */
    private static final String ENABLE_BUBBLES_AT_TOP = "experiment_enable_top_bubbles";
    /** Flag to position the header below the activity view */
    private static final String ENABLE_BUBBLE_FOOTER = "experiment_enable_bubble_footer";

    private final Context mContext;
    private final NotificationEntryManager mNotificationEntryManager;
    private final IActivityTaskManager mActivityTaskManager;
@@ -548,6 +553,22 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe
                ENABLE_BUBBLES, 1) != 0;
    }

    /**
     * Whether bubbles should be positioned at the top of the screen or not.
     */
    public static boolean showBubblesAtTop(Context context) {
        return Settings.Secure.getInt(context.getContentResolver(),
                ENABLE_BUBBLES_AT_TOP, 0) != 0;
    }

    /**
     * Whether the bubble chrome should display as a footer or not (in which case it's a header).
     */
    public static boolean useFooter(Context context) {
        return Settings.Secure.getInt(context.getContentResolver(),
                ENABLE_BUBBLE_FOOTER, 0) != 0;
    }

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

+48 −3
Original line number Diff line number Diff line
@@ -70,8 +70,13 @@ import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
public class BubbleExpandedView extends LinearLayout implements View.OnClickListener {
    private static final String TAG = "BubbleExpandedView";

    // Configurable via bubble settings; just for testing
    private boolean mUseFooter;
    private boolean mShowOnTop;

    // The triangle pointing to the expanded view
    private View mPointerView;
    private int mPointerMargin;

    // Header
    private View mHeaderView;
@@ -90,6 +95,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList

    private int mMinHeight;
    private int mHeaderHeight;
    private int mBubbleHeight;
    private int mPermissionHeight;

    private NotificationEntry mEntry;
    private PackageManager mPm;
@@ -150,6 +157,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
        mPm = context.getPackageManager();
        mMinHeight = getResources().getDimensionPixelSize(
                R.dimen.bubble_expanded_default_height);
        mPointerMargin = getResources().getDimensionPixelSize(R.dimen.bubble_pointer_margin);
        try {
            mNotificationManagerService = INotificationManager.Stub.asInterface(
                    ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE));
@@ -172,8 +180,11 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
        int bgColor = ta.getColor(0, Color.WHITE);
        ta.recycle();

        mShowOnTop = BubbleController.showBubblesAtTop(getContext());
        mUseFooter = BubbleController.useFooter(getContext());

        ShapeDrawable triangleDrawable = new ShapeDrawable(
                TriangleShape.create(width, height, true /* pointUp */));
                TriangleShape.create(width, height, mShowOnTop /* pointUp */));
        triangleDrawable.setTint(bgColor);
        mPointerView.setBackground(triangleDrawable);

@@ -195,6 +206,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList

        mHeaderHeight = getContext().getResources().getDimensionPixelSize(
                R.dimen.bubble_expanded_header_height);
        mPermissionHeight = getContext().getResources().getDimensionPixelSize(
                R.dimen.bubble_permission_height);
        mHeaderView = findViewById(R.id.header_layout);
        mDeepLinkIcon = findViewById(R.id.deep_link_button);
        mSettingsIcon = findViewById(R.id.settings_button);
@@ -226,6 +239,15 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
            activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
            return view.onApplyWindowInsets(insets);
        });

        if (!mShowOnTop) {
            removeView(mPointerView);
            if (mUseFooter) {
                removeView(viewWrapper);
                addView(viewWrapper);
            }
            addView(mPointerView);
        }
    }

    /**
@@ -332,7 +354,11 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList

            // Use notification view
            mNotifRow = mEntry.getRow();
            if (mShowOnTop) {
                addView(mNotifRow);
            } else {
                addView(mNotifRow, mUseFooter ? 0 : 1);
            }
        }
        updateView();
    }
@@ -345,6 +371,17 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
        return true;
    }

    /**
     * @return total height that the expanded view occupies.
     */
    int getExpandedSize() {
        int chromeHeight = mPermissionView.getVisibility() != View.VISIBLE
                ? mHeaderHeight
                : mPermissionHeight;
        return mBubbleHeight + mPointerView.getHeight() + mPointerMargin
                + chromeHeight;
    }

    void updateHeight() {
        if (usingActivityView()) {
            Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
@@ -358,12 +395,19 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
                        ? data.getDesiredHeight()
                        : mMinHeight;
            }
            int max = mStackView.getMaxExpandedHeight() - mHeaderHeight;
            int chromeHeight = mPermissionView.getVisibility() != View.VISIBLE
                    ? mHeaderHeight
                    : mPermissionHeight;
            int max = mStackView.getMaxExpandedHeight() - chromeHeight - mPointerView.getHeight()
                    - mPointerMargin;
            int height = Math.min(desiredHeight, max);
            height = Math.max(height, mMinHeight);
            LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
            lp.height = height;
            mBubbleHeight = height;
            mActivityView.setLayoutParams(lp);
        } else {
            mBubbleHeight = mNotifRow != null ? mNotifRow.getIntrinsicHeight() : mMinHeight;
        }
    }

@@ -412,6 +456,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
            } else if (mOnBubbleBlockedListener != null) {
                mOnBubbleBlockedListener.onBubbleBlocked(mEntry);
            }
            mStackView.onExpandedHeightChanged();
            logBubbleClickEvent(mEntry.notification,
                    allowed ? StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_IN :
                            StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_OUT);
+36 −9
Original line number Diff line number Diff line
@@ -173,7 +173,7 @@ public class BubbleStackView extends FrameLayout {
        int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);

        mStackAnimationController = new StackAnimationController();
        mExpandedAnimationController = new ExpandedAnimationController();
        mExpandedAnimationController = new ExpandedAnimationController(mDisplaySize);

        mBubbleContainer = new PhysicsAnimationLayout(context);
        mBubbleContainer.setMaxRenderedChildren(
@@ -513,8 +513,7 @@ public class BubbleStackView extends FrameLayout {
            final float yStart = Math.min(
                    mStackAnimationController.getStackPosition().y,
                    mExpandedAnimateYDistance);
            final float yDest = getStatusBarHeight()
                    + mExpandedBubble.iconView.getHeight() + mBubblePadding;
            final float yDest = getYPositionForExpandedView();

            if (shouldExpand) {
                mExpandedViewContainer.setTranslationX(xStart);
@@ -668,13 +667,39 @@ public class BubbleStackView extends FrameLayout {
     * y position when the bubbles are expanded as well as the bounds of the dismiss target.
     */
    int getMaxExpandedHeight() {
        boolean showOnTop = BubbleController.showBubblesAtTop(getContext());
        int expandedY = (int) mExpandedAnimationController.getExpandedY();
        int bubbleContainerHeight = mBubbleContainer.getChildAt(0) != null
                ? mBubbleContainer.getChildAt(0).getHeight()
                : 0;
        if (showOnTop) {
            // PIP dismiss view uses FLAG_LAYOUT_IN_SCREEN so we need to subtract the bottom inset
            int pipDismissHeight = mPipDismissHeight - getBottomInset();
            return mDisplaySize.y - expandedY - mBubbleSize - pipDismissHeight;
        } else {
            return expandedY - getStatusBarHeight();
        }
    }

    /**
     * Calculates the y position of the expanded view when it is expanded.
     */
    float getYPositionForExpandedView() {
        boolean showOnTop = BubbleController.showBubblesAtTop(getContext());
        if (showOnTop) {
            return getStatusBarHeight() + mBubbleSize + mBubblePadding;
        } else {
            return mExpandedAnimationController.getExpandedY()
                    - mExpandedBubble.expandedView.getExpandedSize() - mBubblePadding;
        }
    }

    /**
     * Called when the height of the currently expanded view has changed (not via an
     * update to the bubble's desired height but for some other reason, e.g. permission view
     * goes away).
     */
    void onExpandedHeightChanged() {
        if (mIsExpanded) {
            requestUpdate();
        }
    }

    /**
@@ -751,6 +776,8 @@ public class BubbleStackView extends FrameLayout {

        mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
        if (mIsExpanded) {
            final float y = getYPositionForExpandedView();
            mExpandedViewContainer.setTranslationY(y);
            mExpandedBubble.expandedView.updateView();
        }

Loading