Skip to content

Commit 67eab79

Browse files
committed
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
1 parent 151f00d commit 67eab79

File tree

4 files changed

+94
-78
lines changed

4 files changed

+94
-78
lines changed

packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@ public static final void LOG(String fmt, Object... args) {
2121
public static final int STATE_OPENING = 1;
2222
public static final int STATE_OPEN = 2;
2323

24-
private PanelHolder mPanelHolder;
25-
private ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
26-
protected PanelView mTouchingPanel;
24+
PanelHolder mPanelHolder;
25+
ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
26+
PanelView mTouchingPanel;
2727
private int mState = STATE_CLOSED;
2828
private boolean mTracking;
2929

30+
float mPanelExpandedFractionSum;
31+
3032
public void go(int state) {
31-
LOG("go state: %d -> %d", mState, state);
33+
if (DEBUG) LOG("go state: %d -> %d", mState, state);
3234
mState = state;
3335
}
3436

@@ -84,7 +86,7 @@ public boolean onTouchEvent(MotionEvent event) {
8486
if (event.getAction() == MotionEvent.ACTION_DOWN) {
8587
final PanelView panel = selectPanelForTouchX(event.getX());
8688
boolean enabled = panel.isEnabled();
87-
LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
89+
if (DEBUG) LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
8890
(enabled ? "" : " (disabled)"));
8991
if (!enabled)
9092
return false;
@@ -96,15 +98,21 @@ public boolean onTouchEvent(MotionEvent event) {
9698

9799
// called from PanelView when self-expanding, too
98100
public void startOpeningPanel(PanelView panel) {
99-
LOG("startOpeningPanel: " + panel);
101+
if (DEBUG) LOG("startOpeningPanel: " + panel);
100102
mTouchingPanel = panel;
101103
mPanelHolder.setSelectedPanel(mTouchingPanel);
104+
for (PanelView pv : mPanels) {
105+
if (pv != panel) {
106+
pv.collapse();
107+
}
108+
}
102109
}
103110

104111
public void panelExpansionChanged(PanelView panel, float frac) {
105112
boolean fullyClosed = true;
106113
PanelView fullyOpenedPanel = null;
107-
LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
114+
if (DEBUG) LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
115+
mPanelExpandedFractionSum = 0f;
108116
for (PanelView pv : mPanels) {
109117
final boolean visible = pv.getVisibility() == View.VISIBLE;
110118
// adjust any other panels that may be partially visible
@@ -115,11 +123,10 @@ public void panelExpansionChanged(PanelView panel, float frac) {
115123
}
116124
fullyClosed = false;
117125
final float thisFrac = pv.getExpandedFraction();
118-
LOG("panelExpansionChanged: -> %s: f=%.1f", pv.getName(), thisFrac);
126+
mPanelExpandedFractionSum += (visible ? thisFrac : 0);
127+
if (DEBUG) LOG("panelExpansionChanged: -> %s: f=%.1f", pv.getName(), thisFrac);
119128
if (panel == pv) {
120129
if (thisFrac == 1f) fullyOpenedPanel = panel;
121-
} else {
122-
pv.setExpandedFraction(1f-frac);
123130
}
124131
}
125132
if (pv.getExpandedHeight() > 0f) {
@@ -128,6 +135,7 @@ public void panelExpansionChanged(PanelView panel, float frac) {
128135
if (visible) pv.setVisibility(View.GONE);
129136
}
130137
}
138+
mPanelExpandedFractionSum /= mPanels.size();
131139
if (fullyOpenedPanel != null && !mTracking) {
132140
go(STATE_OPEN);
133141
onPanelFullyOpened(fullyOpenedPanel);
@@ -136,7 +144,7 @@ public void panelExpansionChanged(PanelView panel, float frac) {
136144
onAllPanelsCollapsed();
137145
}
138146

139-
LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
147+
if (DEBUG) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
140148
(fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
141149
}
142150

@@ -148,9 +156,10 @@ public void collapseAllPanels(boolean animate) {
148156
waiting = true;
149157
} else {
150158
pv.setExpandedFraction(0); // just in case
159+
pv.setVisibility(View.GONE);
151160
}
152-
pv.setVisibility(View.GONE);
153161
}
162+
if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
154163
if (!waiting) {
155164
// it's possible that nothing animated, so we replicate the termination
156165
// conditions of panelExpansionChanged here
@@ -160,20 +169,20 @@ public void collapseAllPanels(boolean animate) {
160169
}
161170

162171
public void onPanelPeeked() {
163-
LOG("onPanelPeeked");
172+
if (DEBUG) LOG("onPanelPeeked");
164173
}
165174

166175
public void onAllPanelsCollapsed() {
167-
LOG("onAllPanelsCollapsed");
176+
if (DEBUG) LOG("onAllPanelsCollapsed");
168177
}
169178

170179
public void onPanelFullyOpened(PanelView openPanel) {
171-
LOG("onPanelFullyOpened");
180+
if (DEBUG) LOG("onPanelFullyOpened");
172181
}
173182

174183
public void onTrackingStarted(PanelView panel) {
175184
mTracking = true;
176-
if (panel != mTouchingPanel) {
185+
if (DEBUG && panel != mTouchingPanel) {
177186
LOG("shouldn't happen: onTrackingStarted(%s) != mTouchingPanel(%s)",
178187
panel, mTouchingPanel);
179188
}

packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
public class PanelHolder extends FrameLayout {
99

10-
private int mSelectedPanelIndex;
10+
private int mSelectedPanelIndex = -1;
1111
private PanelBar mBar;
1212

1313
public PanelHolder(Context context, AttributeSet attrs) {
@@ -53,6 +53,7 @@ protected int getChildDrawingOrder(int childCount, int i) {
5353
public boolean onTouchEvent(MotionEvent event) {
5454
switch (event.getAction()) {
5555
case MotionEvent.ACTION_DOWN:
56+
PanelBar.LOG("PanelHolder got touch in open air, closing panels");
5657
mBar.collapseAllPanels(true);
5758
break;
5859
}

packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,9 @@
99
import android.view.MotionEvent;
1010
import android.view.VelocityTracker;
1111
import android.view.View;
12-
import android.view.ViewGroup;
1312
import android.widget.FrameLayout;
1413

1514
import com.android.systemui.R;
16-
import com.android.systemui.statusbar.policy.BatteryController;
17-
import com.android.systemui.statusbar.policy.BluetoothController;
18-
import com.android.systemui.statusbar.policy.LocationController;
19-
import com.android.systemui.statusbar.policy.NetworkController;
2015

2116
public class PanelView extends FrameLayout {
2217
public static final boolean DEBUG = PanelBar.DEBUG;
@@ -70,12 +65,16 @@ public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime)
7065
}
7166
};
7267

73-
private final Runnable mStopAnimator = new Runnable() { public void run() {
74-
if (mTimeAnimator.isStarted()) {
75-
mTimeAnimator.end();
76-
mRubberbanding = false;
68+
private final Runnable mStopAnimator = new Runnable() {
69+
@Override
70+
public void run() {
71+
if (mTimeAnimator.isStarted()) {
72+
mTimeAnimator.end();
73+
mRubberbanding = false;
74+
mClosing = false;
75+
}
7776
}
78-
}};
77+
};
7978

8079
private float mVel, mAccel;
8180
private int mFullHeight = 0;
@@ -90,20 +89,22 @@ private void animationTick(long dtms) {
9089
mTimeAnimator.setTimeListener(mAnimationCallback);
9190

9291
mTimeAnimator.start();
93-
94-
mRubberbanding = STRETCH_PAST_CONTENTS && mExpandedHeight > getFullHeight();
92+
93+
mRubberbanding = STRETCH_PAST_CONTENTS // is it enabled at all?
94+
&& mExpandedHeight > getFullHeight() // are we past the end?
95+
&& mVel >= -mFlingGestureMinDistPx; // was this not possibly a "close" gesture?
9596
if (mRubberbanding) {
9697
mClosing = true;
9798
} else if (mVel == 0) {
98-
// if the panel is less than halfway open, close it
99+
// if the panel is less than halfway open, close it
99100
mClosing = (mFinalTouchY / getFullHeight()) < 0.5f;
100101
} else {
101102
mClosing = mExpandedHeight > 0 && mVel < 0;
102103
}
103104
} else if (dtms > 0) {
104105
final float dt = dtms * 0.001f; // ms -> s
105-
LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
106-
LOG("tick: before: h=%d", (int) mExpandedHeight);
106+
if (DEBUG) LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
107+
if (DEBUG) LOG("tick: before: h=%d", (int) mExpandedHeight);
107108

108109
final float fh = getFullHeight();
109110
boolean braking = false;
@@ -136,12 +137,12 @@ private void animationTick(long dtms) {
136137
}
137138

138139
float h = mExpandedHeight + mVel * dt;
139-
140+
140141
if (mRubberbanding && h < fh) {
141142
h = fh;
142143
}
143144

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

146147
setExpandedHeightInternal(h);
147148

@@ -205,14 +206,14 @@ protected void onFinishInflate() {
205206
loadDimens();
206207

207208
mHandleView = findViewById(R.id.handle);
208-
LOG("handle view: " + mHandleView);
209+
if (DEBUG) LOG("handle view: " + mHandleView);
209210
if (mHandleView != null) {
210211
mHandleView.setOnTouchListener(new View.OnTouchListener() {
211212
@Override
212213
public boolean onTouch(View v, MotionEvent event) {
213214
final float y = event.getY();
214215
final float rawY = event.getRawY();
215-
LOG("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f",
216+
if (DEBUG) LOG("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f",
216217
MotionEvent.actionToString(event.getAction()),
217218
y, rawY, mTouchOffset);
218219
PanelView.this.getLocationOnScreen(mAbsPos);
@@ -224,6 +225,7 @@ public boolean onTouch(View v, MotionEvent event) {
224225
mInitialTouchY = y;
225226
mVelocityTracker = VelocityTracker.obtain();
226227
trackMovement(event);
228+
mTimeAnimator.cancel(); // end any outstanding animations
227229
mBar.onTrackingStarted(PanelView.this);
228230
mTouchOffset = (rawY - mAbsPos[1]) - PanelView.this.getExpandedHeight();
229231
break;
@@ -263,7 +265,7 @@ public boolean onTouch(View v, MotionEvent event) {
263265

264266
// if you've barely moved your finger, we treat the velocity as 0
265267
// preventing spurious flings due to touch screen jitter
266-
final float deltaY = (float)Math.abs(mFinalTouchY - mInitialTouchY);
268+
final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
267269
if (deltaY < mFlingGestureMinDistPx
268270
|| vel < mFlingGestureMinDistPx) {
269271
vel = 0;
@@ -273,7 +275,7 @@ public boolean onTouch(View v, MotionEvent event) {
273275
vel = -vel;
274276
}
275277

276-
LOG("gesture: dy=%f vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
278+
if (DEBUG) LOG("gesture: dy=%f vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
277279
deltaY,
278280
mVelocityTracker.getXVelocity(),
279281
mVelocityTracker.getYVelocity(),
@@ -312,7 +314,7 @@ public String getName() {
312314

313315
@Override
314316
protected void onViewAdded(View child) {
315-
LOG("onViewAdded: " + child);
317+
if (DEBUG) LOG("onViewAdded: " + child);
316318
}
317319

318320
public View getHandle() {
@@ -324,15 +326,15 @@ public View getHandle() {
324326
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
325327
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
326328

327-
LOG("onMeasure(%d, %d) -> (%d, %d)",
329+
if (DEBUG) LOG("onMeasure(%d, %d) -> (%d, %d)",
328330
widthMeasureSpec, heightMeasureSpec, getMeasuredWidth(), getMeasuredHeight());
329331

330332
// Did one of our children change size?
331333
int newHeight = getMeasuredHeight();
332334
if (newHeight != mFullHeight) {
333335
mFullHeight = newHeight;
334336
// If the user isn't actively poking us, let's rubberband to the content
335-
if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
337+
if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
336338
&& mExpandedHeight > 0 && mExpandedHeight != mFullHeight) {
337339
mExpandedHeight = mFullHeight;
338340
}
@@ -351,7 +353,7 @@ public void setExpandedHeight(float height) {
351353

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

@@ -365,7 +367,7 @@ public void setExpandedHeightInternal(float h) {
365367
if (!(STRETCH_PAST_CONTENTS && (mTracking || mRubberbanding)) && h > fh) h = fh;
366368
mExpandedHeight = h;
367369

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

370372
requestLayout();
371373
// FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
@@ -377,9 +379,9 @@ public void setExpandedHeightInternal(float h) {
377379

378380
private float getFullHeight() {
379381
if (mFullHeight <= 0) {
380-
LOG("Forcing measure() since fullHeight=" + mFullHeight);
381-
measure(MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
382-
MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
382+
if (DEBUG) LOG("Forcing measure() since fullHeight=" + mFullHeight);
383+
measure(MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
384+
MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
383385
}
384386
return mFullHeight;
385387
}
@@ -397,11 +399,15 @@ public float getExpandedFraction() {
397399
}
398400

399401
public boolean isFullyExpanded() {
400-
return mExpandedHeight == getFullHeight();
402+
return mExpandedHeight >= getFullHeight();
401403
}
402404

403405
public boolean isFullyCollapsed() {
404-
return mExpandedHeight == 0;
406+
return mExpandedHeight <= 0;
407+
}
408+
409+
public boolean isCollapsing() {
410+
return mClosing;
405411
}
406412

407413
public void setBar(PanelBar panelBar) {
@@ -411,17 +417,19 @@ public void setBar(PanelBar panelBar) {
411417
public void collapse() {
412418
// TODO: abort animation or ongoing touch
413419
if (!isFullyCollapsed()) {
420+
// collapse() should never be a rubberband, even if an animation is already running
421+
mRubberbanding = false;
414422
fling(-mSelfCollapseVelocityPx, /*always=*/ true);
415423
}
416424
}
417425

418426
public void expand() {
419427
if (isFullyCollapsed()) {
420428
mBar.startOpeningPanel(this);
421-
LOG("expand: calling fling(%s, true)", mSelfExpandVelocityPx);
429+
if (DEBUG) LOG("expand: calling fling(%s, true)", mSelfExpandVelocityPx);
422430
fling (mSelfExpandVelocityPx, /*always=*/ true);
423431
} else if (DEBUG) {
424-
LOG("skipping expansion: is expanded");
432+
if (DEBUG) LOG("skipping expansion: is expanded");
425433
}
426434
}
427435
}

0 commit comments

Comments
 (0)