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

Commit 1685e634 authored by Selim Cinek's avatar Selim Cinek
Browse files

Further improved NotificationStackScroller

The top card is now collapsed during the pulldown of
the notification shade and expanded during the transition.
The scrollstate is also reset once the shade is closed.

Change-Id: Ibf17eef1f338d674c545e5bf55261e60db62b2ce
parent 9817ddd4
Loading
Loading
Loading
Loading
+13 −9
Original line number Original line Diff line number Diff line
@@ -138,7 +138,8 @@ public abstract class BaseStatusBar extends SystemUI implements


    protected IDreamManager mDreamManager;
    protected IDreamManager mDreamManager;
    PowerManager mPowerManager;
    PowerManager mPowerManager;
    protected int mRowHeight;
    protected int mRowMinHeight;
    protected int mRowMaxHeight;


    // public mode, private notifications, etc
    // public mode, private notifications, etc
    private boolean mLockscreenPublicMode = false;
    private boolean mLockscreenPublicMode = false;
@@ -880,7 +881,7 @@ public abstract class BaseStatusBar extends SystemUI implements
            }
            }
        }
        }
        entry.row = row;
        entry.row = row;
        entry.row.setRowHeight(mRowHeight);
        entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
        entry.content = content;
        entry.content = content;
        entry.expanded = contentViewLocal;
        entry.expanded = contentViewLocal;
        entry.expandedPublic = publicViewLocal;
        entry.expandedPublic = publicViewLocal;
@@ -1055,17 +1056,19 @@ public abstract class BaseStatusBar extends SystemUI implements
    }
    }


    protected void updateExpansionStates() {
    protected void updateExpansionStates() {

        // TODO: Handle user expansion better
        int N = mNotificationData.size();
        int N = mNotificationData.size();
        for (int i = 0; i < N; i++) {
        for (int i = 0; i < N; i++) {
            NotificationData.Entry entry = mNotificationData.get(i);
            NotificationData.Entry entry = mNotificationData.get(i);
            if (!entry.row.isUserLocked()) {
            if (!entry.row.isUserLocked()) {
                if (i == (N-1)) {
                if (i == (N-1)) {
                    if (DEBUG) Log.d(TAG, "expanding top notification at " + i);
                    if (DEBUG) Log.d(TAG, "expanding top notification at " + i);
                    entry.row.setExpanded(true);
                    entry.row.setSystemExpanded(true);
                } else {
                } else {
                    if (!entry.row.isUserExpanded()) {
                    if (!entry.row.isUserExpanded()) {
                        if (DEBUG) Log.d(TAG, "collapsing notification at " + i);
                        if (DEBUG) Log.d(TAG, "collapsing notification at " + i);
                        entry.row.setExpanded(false);
                        entry.row.setSystemExpanded(false);
                    } else {
                    } else {
                        if (DEBUG) Log.d(TAG, "ignoring user-modified notification at " + i);
                        if (DEBUG) Log.d(TAG, "ignoring user-modified notification at " + i);
                    }
                    }
@@ -1218,13 +1221,14 @@ public abstract class BaseStatusBar extends SystemUI implements
            if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
            if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
            if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
            if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed"));
            if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
            if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top"));
            final boolean wasExpanded = oldEntry.row.isUserExpanded();
            removeNotificationViews(key);
            removeNotificationViews(key);
            addNotificationViews(key, notification);  // will also replace the heads up
            addNotificationViews(key, notification);  // will also replace the heads up
            if (wasExpanded) {
            final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
            final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
                newEntry.row.setExpanded(true);
            final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
                newEntry.row.setUserExpanded(true);
            if (userChangedExpansion) {
                boolean userExpanded = oldEntry.row.isUserExpanded();
                newEntry.row.applyExpansionToLayout(userExpanded);
                newEntry.row.setUserExpanded(userExpanded);
            }
            }
        }
        }


+124 −15
Original line number Original line Diff line number Diff line
@@ -22,30 +22,49 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.FrameLayout;


import com.android.internal.widget.SizeAdaptiveLayout;
import com.android.systemui.R;
import com.android.systemui.R;


public class ExpandableNotificationRow extends FrameLayout {
public class ExpandableNotificationRow extends FrameLayout {
    private int mRowHeight;
    private int mRowMinHeight;
    private int mRowMaxHeight;


    /** does this row contain layouts that can adapt to row expansion */
    /** Does this row contain layouts that can adapt to row expansion */
    private boolean mExpandable;
    private boolean mExpandable;
    /** has the user manually expanded this row */
    /** Has the user actively changed the expansion state of this row */
    private boolean mHasUserChangedExpansion;
    /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
    private boolean mUserExpanded;
    private boolean mUserExpanded;
    /** is the user touching this row */
    /** Is the user touching this row */
    private boolean mUserLocked;
    private boolean mUserLocked;
    /** are we showing the "public" version */
    /** Are we showing the "public" version */
    private boolean mShowingPublic;
    private boolean mShowingPublic;


    /**
     * Is this notification expanded by the system. The expansion state can be overridden by the
     * user expansion.
     */
    private boolean mIsSystemExpanded;
    private SizeAdaptiveLayout mPublicLayout;
    private SizeAdaptiveLayout mPrivateLayout;
    private int mMaxExpandHeight;
    private boolean mMaxHeightNeedsUpdate;

    public ExpandableNotificationRow(Context context, AttributeSet attrs) {
    public ExpandableNotificationRow(Context context, AttributeSet attrs) {
        super(context, attrs);
        super(context, attrs);
    }
    }


    public int getRowHeight() {
    @Override
        return mRowHeight;
    protected void onFinishInflate() {
        super.onFinishInflate();
        mPublicLayout = (SizeAdaptiveLayout) findViewById(R.id.expandedPublic);
        mPrivateLayout = (SizeAdaptiveLayout) findViewById(R.id.expanded);
    }
    }


    public void setRowHeight(int rowHeight) {
    public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
        this.mRowHeight = rowHeight;
        mRowMinHeight = rowMinHeight;
        mRowMaxHeight = rowMaxHeight;
        mMaxHeightNeedsUpdate = true;
    }
    }


    public boolean isExpandable() {
    public boolean isExpandable() {
@@ -56,11 +75,24 @@ public class ExpandableNotificationRow extends FrameLayout {
        mExpandable = expandable;
        mExpandable = expandable;
    }
    }


    /**
     * @return whether the user has changed the expansion state
     */
    public boolean hasUserChangedExpansion() {
        return mHasUserChangedExpansion;
    }

    public boolean isUserExpanded() {
    public boolean isUserExpanded() {
        return mUserExpanded;
        return mUserExpanded;
    }
    }


    /**
     * Set this notification to be expanded by the user
     *
     * @param userExpanded whether the user wants this notification to be expanded
     */
    public void setUserExpanded(boolean userExpanded) {
    public void setUserExpanded(boolean userExpanded) {
        mHasUserChangedExpansion = true;
        mUserExpanded = userExpanded;
        mUserExpanded = userExpanded;
    }
    }


@@ -72,25 +104,102 @@ public class ExpandableNotificationRow extends FrameLayout {
        mUserLocked = userLocked;
        mUserLocked = userLocked;
    }
    }


    public void setExpanded(boolean expand) {
    /**
     * @return has the system set this notification to be expanded
     */
    public boolean isSystemExpanded() {
        return mIsSystemExpanded;
    }

    /**
     * Set this notification to be expanded by the system.
     *
     * @param expand whether the system wants this notification to be expanded.
     */
    public void setSystemExpanded(boolean expand) {
        mIsSystemExpanded = expand;
        applyExpansionToLayout(expand);
    }

    /**
     * Apply an expansion state to the layout.
     *
     * @param expand should the layout be in the expanded state
     */
    public void applyExpansionToLayout(boolean expand) {
        ViewGroup.LayoutParams lp = getLayoutParams();
        ViewGroup.LayoutParams lp = getLayoutParams();
        if (expand && mExpandable) {
        if (expand && mExpandable) {
            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        } else {
        } else {
            lp.height = mRowHeight;
            lp.height = mRowMinHeight;
        }
        }
        setLayoutParams(lp);
        setLayoutParams(lp);
    }
    }


    /**
     * If {@link #isExpanded()} then this is the greatest possible height this view can
     * get and otherwise it is {@link #mRowMinHeight}.
     *
     * @return the maximum allowed expansion height of this view.
     */
    public int getMaximumAllowedExpandHeight() {
        boolean inExpansionState = isExpanded();
        if (!inExpansionState) {
            // not expanded, so we return the collapsed size
            return mRowMinHeight;
        }

        return mShowingPublic ? mRowMinHeight : getMaxExpandHeight();
    }



    private void updateMaxExpandHeight() {
        ViewGroup.LayoutParams lp = getLayoutParams();
        int oldHeight = lp.height;
        lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        setLayoutParams(lp);
        measure(View.MeasureSpec.makeMeasureSpec(getMeasuredWidth(), View.MeasureSpec.EXACTLY),
                View.MeasureSpec.makeMeasureSpec(mRowMaxHeight, View.MeasureSpec.AT_MOST));
        lp.height = oldHeight;
        setLayoutParams(lp);
        mMaxExpandHeight = getMeasuredHeight();
    }

    /**
     * Check whether the view state is currently expanded. This is given by the system in {@link
     * #setSystemExpanded(boolean)} and can be overridden by user expansion or
     * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
     * view can differ from this state, if layout params are modified from outside.
     *
     * @return whether the view state is currently expanded.
     */
    private boolean isExpanded() {
        return !hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mMaxHeightNeedsUpdate = true;
    }

    public void setShowingPublic(boolean show) {
    public void setShowingPublic(boolean show) {
        mShowingPublic = show;
        mShowingPublic = show;
        final ViewGroup publicLayout = (ViewGroup) findViewById(R.id.expandedPublic);


        // bail out if no public version
        // bail out if no public version
        if (publicLayout.getChildCount() == 0) return;
        if (mPublicLayout.getChildCount() == 0) return;


        // TODO: animation?
        // TODO: animation?
        publicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
        mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
        findViewById(R.id.expanded).setVisibility(show ? View.GONE : View.VISIBLE);
        mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
    }

    public int getMaxExpandHeight() {
        if (mMaxHeightNeedsUpdate) {
            updateMaxExpandHeight();
            mMaxHeightNeedsUpdate = false;
        }
        return mMaxExpandHeight;
    }
    }
}
}
+13 −0
Original line number Original line Diff line number Diff line
@@ -139,6 +139,7 @@ public class NotificationPanelView extends PanelView {
     * @param expandedHeight the new expanded height
     * @param expandedHeight the new expanded height
     */
     */
    private void updateNotificationStackHeight(float expandedHeight) {
    private void updateNotificationStackHeight(float expandedHeight) {
        mNotificationStackScroller.setIsExpanded(expandedHeight > 0.0f);
        float childOffset = getRelativeTop(mNotificationStackScroller)
        float childOffset = getRelativeTop(mNotificationStackScroller)
                - mNotificationParent.getTranslationY();
                - mNotificationParent.getTranslationY();
        int newStackHeight = (int) (expandedHeight - childOffset);
        int newStackHeight = (int) (expandedHeight - childOffset);
@@ -168,4 +169,16 @@ public class NotificationPanelView extends PanelView {
    protected int getDesiredMeasureHeight() {
    protected int getDesiredMeasureHeight() {
        return mMaxPanelHeight;
        return mMaxPanelHeight;
    }
    }

    @Override
    protected void onExpandingStarted() {
        super.onExpandingStarted();
        mNotificationStackScroller.onExpansionStarted();
    }

    @Override
    protected void onExpandingFinished() {
        super.onExpandingFinished();
        mNotificationStackScroller.onExpansionStopped();
    }
}
}
+23 −2
Original line number Original line Diff line number Diff line
@@ -216,6 +216,7 @@ public class PanelView extends FrameLayout {
                mTimeAnimator.end();
                mTimeAnimator.end();
                mRubberbanding = false;
                mRubberbanding = false;
                mClosing = false;
                mClosing = false;
                onExpandingFinished();
            }
            }
        }
        }
    };
    };
@@ -230,6 +231,12 @@ public class PanelView extends FrameLayout {
        mRubberbandingEnabled = enable;
        mRubberbandingEnabled = enable;
    }
    }


    protected void onExpandingFinished() {
    }

    protected void onExpandingStarted() {
    }

    private void runPeekAnimation() {
    private void runPeekAnimation() {
        if (DEBUG) logf("peek to height=%.1f", mPeekHeight);
        if (DEBUG) logf("peek to height=%.1f", mPeekHeight);
        if (mTimeAnimator.isStarted()) {
        if (mTimeAnimator.isStarted()) {
@@ -398,7 +405,7 @@ public class PanelView extends FrameLayout {
                initVelocityTracker();
                initVelocityTracker();
                trackMovement(event);
                trackMovement(event);
                mTimeAnimator.cancel(); // end any outstanding animations
                mTimeAnimator.cancel(); // end any outstanding animations
                mBar.onTrackingStarted(PanelView.this);
                onTrackingStarted();
                mInitialOffsetOnTouch = mExpandedHeight;
                mInitialOffsetOnTouch = mExpandedHeight;
                if (mExpandedHeight == 0) {
                if (mExpandedHeight == 0) {
                    mJustPeeked = true;
                    mJustPeeked = true;
@@ -443,7 +450,7 @@ public class PanelView extends FrameLayout {
                    mHandleView.setPressed(false);
                    mHandleView.setPressed(false);
                    postInvalidate(); // catch the press state change
                    postInvalidate(); // catch the press state change
                }
                }
                mBar.onTrackingStopped(PanelView.this);
                onTrackingStopped();
                trackMovement(event);
                trackMovement(event);


                float vel = getCurrentVelocity();
                float vel = getCurrentVelocity();
@@ -458,6 +465,15 @@ public class PanelView extends FrameLayout {
        return true;
        return true;
    }
    }


    protected void onTrackingStopped() {
        mBar.onTrackingStopped(PanelView.this);
    }

    protected void onTrackingStarted() {
        mBar.onTrackingStarted(PanelView.this);
        onExpandingStarted();
    }

    private float getCurrentVelocity() {
    private float getCurrentVelocity() {
        float vel = 0;
        float vel = 0;
        float yVel = 0, xVel = 0;
        float yVel = 0, xVel = 0;
@@ -561,6 +577,7 @@ public class PanelView extends FrameLayout {
                        mInitialOffsetOnTouch = mExpandedHeight;
                        mInitialOffsetOnTouch = mExpandedHeight;
                        mInitialTouchY = y;
                        mInitialTouchY = y;
                        mTracking = true;
                        mTracking = true;
                        onTrackingStarted();
                        return true;
                        return true;
                    }
                    }
                }
                }
@@ -598,6 +615,8 @@ public class PanelView extends FrameLayout {


        if (always||mVel != 0) {
        if (always||mVel != 0) {
            animationTick(0); // begin the animation
            animationTick(0); // begin the animation
        } else {
            onExpandingFinished();
        }
        }
    }
    }


@@ -770,6 +789,7 @@ public class PanelView extends FrameLayout {
        if (!isFullyCollapsed()) {
        if (!isFullyCollapsed()) {
            mTimeAnimator.cancel();
            mTimeAnimator.cancel();
            mClosing = true;
            mClosing = true;
            onExpandingStarted();
            // collapse() should never be a rubberband, even if an animation is already running
            // collapse() should never be a rubberband, even if an animation is already running
            mRubberbanding = false;
            mRubberbanding = false;
            fling(-mSelfCollapseVelocityPx, /*always=*/ true);
            fling(-mSelfCollapseVelocityPx, /*always=*/ true);
@@ -780,6 +800,7 @@ public class PanelView extends FrameLayout {
        if (DEBUG) logf("expand: " + this);
        if (DEBUG) logf("expand: " + this);
        if (isFullyCollapsed()) {
        if (isFullyCollapsed()) {
            mBar.startOpeningPanel(this);
            mBar.startOpeningPanel(this);
            onExpandingStarted();
            fling(mSelfExpandVelocityPx, /*always=*/ true);
            fling(mSelfExpandVelocityPx, /*always=*/ true);
        } else if (DEBUG) {
        } else if (DEBUG) {
            if (DEBUG) logf("skipping expansion: is expanded");
            if (DEBUG) logf("skipping expansion: is expanded");
+2 −1
Original line number Original line Diff line number Diff line
@@ -2641,7 +2641,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
        }
        }


        mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay);
        mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay);
        mRowHeight =  res.getDimensionPixelSize(R.dimen.notification_row_min_height);
        mRowMinHeight =  res.getDimensionPixelSize(R.dimen.notification_row_min_height);
        mRowMaxHeight =  res.getDimensionPixelSize(R.dimen.notification_row_max_height);


        if (false) Log.v(TAG, "updateResources");
        if (false) Log.v(TAG, "updateResources");
    }
    }
Loading