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

Commit 67eab790 authored by Daniel Sandler's avatar Daniel Sandler
Browse files

Panel physics changes.

- You can start pulling down another panel before the first
  one has fully expanded. (Protip: tap many times on the
  statusbar to invoke Schwarzenegger Mode.)
- When starting to pull down a panel, other panels are
  immediately sent running (rather than placing them on a
  literal seesaw).
- Rubberbanding is a little less aggressive: if it looks
  like you're moving your finger upward, we'll just close
  the panel outright rather than sticking to the bottom of
  the visible content. (tablets only)
- This has some implications for the background fade; you'll
  see a brief increase in brightness as you swap panels
  because the fade fraction is based on the sum of all the
  panels' fractional visibility. At times there will not be
  enough "panel" visible, in the aggregate, to justify
  holding the fade steady.

Bug: 7260868 // can't pull down panel, possibly fixed
Bug: 7204435 // double-swipe for QS
Bug: 7179458 // fling & rubberbanding heuristics
Bug: 7172453 // collapse other panels when dragging a new one
Bug: 7221970 // grabbing a flying panel causes twitching
Change-Id: Iad7c1f92c4edab9102cdda45605ef0ead4cc16c5
parent 151f00d8
Loading
Loading
Loading
Loading
+25 −16
Original line number Diff line number Diff line
@@ -21,14 +21,16 @@ public class PanelBar extends FrameLayout {
    public static final int STATE_OPENING = 1;
    public static final int STATE_OPEN = 2;

    private PanelHolder mPanelHolder;
    private ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
    protected PanelView mTouchingPanel;
    PanelHolder mPanelHolder;
    ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
    PanelView mTouchingPanel;
    private int mState = STATE_CLOSED;
    private boolean mTracking;

    float mPanelExpandedFractionSum;

    public void go(int state) {
        LOG("go state: %d -> %d", mState, state);
        if (DEBUG) LOG("go state: %d -> %d", mState, state);
        mState = state;
    }

@@ -84,7 +86,7 @@ public class PanelBar extends FrameLayout {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            final PanelView panel = selectPanelForTouchX(event.getX());
            boolean enabled = panel.isEnabled();
            LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
            if (DEBUG) LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
                    (enabled ? "" : " (disabled)"));
            if (!enabled)
                return false;
@@ -96,15 +98,21 @@ public class PanelBar extends FrameLayout {

    // called from PanelView when self-expanding, too
    public void startOpeningPanel(PanelView panel) {
        LOG("startOpeningPanel: " + panel);
        if (DEBUG) LOG("startOpeningPanel: " + panel);
        mTouchingPanel = panel;
        mPanelHolder.setSelectedPanel(mTouchingPanel);
        for (PanelView pv : mPanels) {
            if (pv != panel) {
                pv.collapse();
            }
        }
    }

    public void panelExpansionChanged(PanelView panel, float frac) {
        boolean fullyClosed = true;
        PanelView fullyOpenedPanel = null;
        LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
        if (DEBUG) LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
        mPanelExpandedFractionSum = 0f;
        for (PanelView pv : mPanels) {
            final boolean visible = pv.getVisibility() == View.VISIBLE;
            // adjust any other panels that may be partially visible
@@ -115,11 +123,10 @@ public class PanelBar extends FrameLayout {
                }
                fullyClosed = false;
                final float thisFrac = pv.getExpandedFraction();
                LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
                mPanelExpandedFractionSum += (visible ? thisFrac : 0);
                if (DEBUG) LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
                if (panel == pv) {
                    if (thisFrac == 1f) fullyOpenedPanel = panel;
                } else {
                    pv.setExpandedFraction(1f-frac);
                }
            }
            if (pv.getExpandedHeight() > 0f) {
@@ -128,6 +135,7 @@ public class PanelBar extends FrameLayout {
                if (visible) pv.setVisibility(View.GONE);
            }
        }
        mPanelExpandedFractionSum /= mPanels.size();
        if (fullyOpenedPanel != null && !mTracking) {
            go(STATE_OPEN);
            onPanelFullyOpened(fullyOpenedPanel);
@@ -136,7 +144,7 @@ public class PanelBar extends FrameLayout {
            onAllPanelsCollapsed();
        }

        LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
        if (DEBUG) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
                (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
    }

@@ -148,9 +156,10 @@ public class PanelBar extends FrameLayout {
                waiting = true;
            } else {
                pv.setExpandedFraction(0); // just in case
            }
                pv.setVisibility(View.GONE);
            }
        }
        if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
        if (!waiting) {
            // it's possible that nothing animated, so we replicate the termination 
            // conditions of panelExpansionChanged here
@@ -160,20 +169,20 @@ public class PanelBar extends FrameLayout {
    }

    public void onPanelPeeked() {
        LOG("onPanelPeeked");
        if (DEBUG) LOG("onPanelPeeked");
    }

    public void onAllPanelsCollapsed() {
        LOG("onAllPanelsCollapsed");
        if (DEBUG) LOG("onAllPanelsCollapsed");
    }

    public void onPanelFullyOpened(PanelView openPanel) {
        LOG("onPanelFullyOpened");
        if (DEBUG) LOG("onPanelFullyOpened");
    }

    public void onTrackingStarted(PanelView panel) {
        mTracking = true;
        if (panel != mTouchingPanel) {
        if (DEBUG && panel != mTouchingPanel) {
            LOG("shouldn't happen: onTrackingStarted(%s) != mTouchingPanel(%s)",
                    panel, mTouchingPanel);
        }
+2 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ import android.widget.FrameLayout;

public class PanelHolder extends FrameLayout {

    private int mSelectedPanelIndex;
    private int mSelectedPanelIndex = -1;
    private PanelBar mBar;

    public PanelHolder(Context context, AttributeSet attrs) {
@@ -53,6 +53,7 @@ public class PanelHolder extends FrameLayout {
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                PanelBar.LOG("PanelHolder got touch in open air, closing panels");
                mBar.collapseAllPanels(true);
                break;
        }
+41 −33
Original line number Diff line number Diff line
@@ -9,14 +9,9 @@ import android.util.Slog;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import com.android.systemui.R;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;

public class PanelView extends FrameLayout {
    public static final boolean DEBUG = PanelBar.DEBUG;
@@ -70,12 +65,16 @@ public class PanelView extends FrameLayout {
        }
    };

    private final Runnable mStopAnimator = new Runnable() { public void run() {
    private final Runnable mStopAnimator = new Runnable() {
        @Override
        public void run() {
            if (mTimeAnimator.isStarted()) {
                mTimeAnimator.end();
                mRubberbanding = false;
                mClosing = false;
            }
        }
    }};
    };

    private float mVel, mAccel;
    private int mFullHeight = 0;
@@ -91,7 +90,9 @@ public class PanelView extends FrameLayout {

            mTimeAnimator.start();

            mRubberbanding = STRETCH_PAST_CONTENTS && mExpandedHeight > getFullHeight();
            mRubberbanding = STRETCH_PAST_CONTENTS // is it enabled at all?
                    && mExpandedHeight > getFullHeight() // are we past the end?
                    && mVel >= -mFlingGestureMinDistPx; // was this not possibly a "close" gesture?
            if (mRubberbanding) {
                mClosing = true;
            } else if (mVel == 0) {
@@ -102,8 +103,8 @@ public class PanelView extends FrameLayout {
            }
        } else if (dtms > 0) {
            final float dt = dtms * 0.001f;                  // ms -> s
            LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
            LOG("tick: before: h=%d", (int) mExpandedHeight);
            if (DEBUG) LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
            if (DEBUG) LOG("tick: before: h=%d", (int) mExpandedHeight);

            final float fh = getFullHeight();
            boolean braking = false;
@@ -141,7 +142,7 @@ public class PanelView extends FrameLayout {
                h = fh;
            }

            LOG("tick: new h=%d closing=%s", (int) h, mClosing?"true":"false");
            if (DEBUG) LOG("tick: new h=%d closing=%s", (int) h, mClosing?"true":"false");

            setExpandedHeightInternal(h);

@@ -205,14 +206,14 @@ public class PanelView extends FrameLayout {
        loadDimens();

        mHandleView = findViewById(R.id.handle);
        LOG("handle view: " + mHandleView);
        if (DEBUG) LOG("handle view: " + mHandleView);
        if (mHandleView != null) {
            mHandleView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    final float y = event.getY();
                    final float rawY = event.getRawY();
                    LOG("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f",
                    if (DEBUG) LOG("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f",
                            MotionEvent.actionToString(event.getAction()),
                            y, rawY, mTouchOffset);
                    PanelView.this.getLocationOnScreen(mAbsPos);
@@ -224,6 +225,7 @@ public class PanelView extends FrameLayout {
                            mInitialTouchY = y;
                            mVelocityTracker = VelocityTracker.obtain();
                            trackMovement(event);
                            mTimeAnimator.cancel(); // end any outstanding animations
                            mBar.onTrackingStarted(PanelView.this);
                            mTouchOffset = (rawY - mAbsPos[1]) - PanelView.this.getExpandedHeight();
                            break;
@@ -263,7 +265,7 @@ public class PanelView extends FrameLayout {

                            // if you've barely moved your finger, we treat the velocity as 0
                            // preventing spurious flings due to touch screen jitter
                            final float deltaY = (float)Math.abs(mFinalTouchY - mInitialTouchY);
                            final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
                            if (deltaY < mFlingGestureMinDistPx
                                    || vel < mFlingGestureMinDistPx) {
                                vel = 0;
@@ -273,7 +275,7 @@ public class PanelView extends FrameLayout {
                                vel = -vel;
                            }

                            LOG("gesture: dy=%f vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
                            if (DEBUG) LOG("gesture: dy=%f vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
                                    deltaY,
                                    mVelocityTracker.getXVelocity(),
                                    mVelocityTracker.getYVelocity(),
@@ -312,7 +314,7 @@ public class PanelView extends FrameLayout {

    @Override
    protected void onViewAdded(View child) {
        LOG("onViewAdded: " + child);
        if (DEBUG) LOG("onViewAdded: " + child);
    }

    public View getHandle() {
@@ -324,7 +326,7 @@ public class PanelView extends FrameLayout {
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        LOG("onMeasure(%d, %d) -> (%d, %d)",
        if (DEBUG) LOG("onMeasure(%d, %d) -> (%d, %d)",
                widthMeasureSpec, heightMeasureSpec, getMeasuredWidth(), getMeasuredHeight());

        // Did one of our children change size?
@@ -351,7 +353,7 @@ public class PanelView extends FrameLayout {

    @Override
    protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
        LOG("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, (int)mFullHeight);
        if (DEBUG) LOG("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, mFullHeight);
        super.onLayout(changed, left, top, right, bottom);
    }

@@ -365,7 +367,7 @@ public class PanelView extends FrameLayout {
        if (!(STRETCH_PAST_CONTENTS && (mTracking || mRubberbanding)) && h > fh) h = fh;
        mExpandedHeight = h;

        LOG("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
        if (DEBUG) LOG("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");

        requestLayout();
//        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
@@ -377,9 +379,9 @@ public class PanelView extends FrameLayout {

    private float getFullHeight() {
        if (mFullHeight <= 0) {
            LOG("Forcing measure() since fullHeight=" + mFullHeight);
            measure(MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
            if (DEBUG) LOG("Forcing measure() since fullHeight=" + mFullHeight);
            measure(MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
        }
        return mFullHeight;
    }
@@ -397,11 +399,15 @@ public class PanelView extends FrameLayout {
    }

    public boolean isFullyExpanded() {
        return mExpandedHeight == getFullHeight();
        return mExpandedHeight >= getFullHeight();
    }

    public boolean isFullyCollapsed() {
        return mExpandedHeight == 0;
        return mExpandedHeight <= 0;
    }

    public boolean isCollapsing() {
        return mClosing;
    }

    public void setBar(PanelBar panelBar) {
@@ -411,6 +417,8 @@ public class PanelView extends FrameLayout {
    public void collapse() {
        // TODO: abort animation or ongoing touch
        if (!isFullyCollapsed()) {
            // collapse() should never be a rubberband, even if an animation is already running
            mRubberbanding = false;
            fling(-mSelfCollapseVelocityPx, /*always=*/ true);
        }
    }
@@ -418,10 +426,10 @@ public class PanelView extends FrameLayout {
    public void expand() {
        if (isFullyCollapsed()) {
            mBar.startOpeningPanel(this);
            LOG("expand: calling fling(%s, true)", mSelfExpandVelocityPx);
            if (DEBUG) LOG("expand: calling fling(%s, true)", mSelfExpandVelocityPx);
            fling (mSelfExpandVelocityPx, /*always=*/ true);
        } else if (DEBUG) {
            LOG("skipping expansion: is expanded");
            if (DEBUG) LOG("skipping expansion: is expanded");
        }
    }
}
+26 −28
Original line number Diff line number Diff line
@@ -19,27 +19,14 @@ package com.android.systemui.statusbar.phone;
import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;

import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.policy.FixedSizeDrawable;

public class PhoneStatusBarView extends PanelBar {
    private static final String TAG = "PhoneStatusBarView";
@@ -53,6 +40,7 @@ public class PhoneStatusBarView extends PanelBar {
    boolean mFullWidthNotifications;
    PanelView mFadingPanel = null;
    PanelView mNotificationPanel, mSettingsPanel;
    private boolean mShouldFade;

    public PhoneStatusBarView(Context context, AttributeSet attrs) {
        super(context, attrs);
@@ -112,7 +100,7 @@ public class PhoneStatusBarView extends PanelBar {
            if (DEBUG) {
                Slog.v(TAG, "notif frac=" + mNotificationPanel.getExpandedFraction());
            }
            return (mNotificationPanel.getExpandedFraction() == 1.0f)
            return (mNotificationPanel.getExpandedFraction() > 0f)
                ? mSettingsPanel : mNotificationPanel;
        }

@@ -120,7 +108,7 @@ public class PhoneStatusBarView extends PanelBar {
        // right 1/3 for quick settings. If you pull the status bar down a second time you'll
        // toggle panels no matter where you pull it down.

        final float w = (float) getMeasuredWidth();
        final float w = getMeasuredWidth();
        float region = (w * mSettingsPanelDragzoneFrac);

        if (DEBUG) {
@@ -138,9 +126,18 @@ public class PhoneStatusBarView extends PanelBar {
    public void onPanelPeeked() {
        super.onPanelPeeked();
        mBar.makeExpandedVisible(true);
        if (mFadingPanel == null) {
            mFadingPanel = mTouchingPanel;
    }

    @Override
    public void startOpeningPanel(PanelView panel) {
        super.startOpeningPanel(panel);
        // we only want to start fading if this is the "first" or "last" panel,
        // which is kind of tricky to determine
        mShouldFade = (mFadingPanel == null || mFadingPanel.isFullyExpanded());
        if (DEBUG) {
            Slog.v(TAG, "start opening: " + panel + " shouldfade=" + mShouldFade);
        }
        mFadingPanel = panel;
    }

    @Override
@@ -153,6 +150,7 @@ public class PhoneStatusBarView extends PanelBar {
    @Override
    public void onPanelFullyOpened(PanelView openPanel) {
        mFadingPanel = openPanel;
        mShouldFade = true; // now you own the fade, mister
    }

    @Override
@@ -166,24 +164,24 @@ public class PhoneStatusBarView extends PanelBar {
    }

    @Override
    public void panelExpansionChanged(PanelView pv, float frac) {
        super.panelExpansionChanged(pv, frac);
    public void panelExpansionChanged(PanelView panel, float frac) {
        super.panelExpansionChanged(panel, frac);

        if (DEBUG) {
            Slog.v(TAG, "panelExpansionChanged: f=" + frac);
        }

        if (mFadingPanel == pv
                && mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
        if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
            if (mShouldFade) {
                frac = mPanelExpandedFractionSum; // don't judge me
                // woo, special effects
                final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2.2f))));
                // attenuate background color alpha by k
            final int color = (int) ((float)(mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF);
                final int color = (int) ((mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF);
                mBar.mStatusBarWindow.setBackgroundColor(color);
            }
        }

        mBar.updateCarrierLabelVisibility(false);
    }


}