blob: 0550771dc6b9322b31625748c15a0278e906ed6f [file] [log] [blame]
Daniel Sandler08d05e32012-08-08 16:39:54 -04001package com.android.systemui.statusbar.phone;
2
3import android.animation.TimeAnimator;
4import android.animation.TimeAnimator.TimeListener;
5import android.content.Context;
6import android.content.res.Resources;
7import android.util.AttributeSet;
Daniel Sandlerbf526d12012-09-04 22:56:44 -04008import android.util.Slog;
Daniel Sandler08d05e32012-08-08 16:39:54 -04009import android.view.MotionEvent;
10import android.view.VelocityTracker;
11import android.view.View;
12import android.widget.FrameLayout;
13
14import com.android.systemui.R;
15
16public class PanelView extends FrameLayout {
Daniel Sandler198a0302012-08-17 16:04:31 -040017 public static final boolean DEBUG = PanelBar.DEBUG;
Daniel Sandler08d05e32012-08-08 16:39:54 -040018 public static final String TAG = PanelView.class.getSimpleName();
Daniel Sandler978f8532012-08-15 15:48:16 -040019 public final void LOG(String fmt, Object... args) {
Daniel Sandler08d05e32012-08-08 16:39:54 -040020 if (!DEBUG) return;
Daniel Sandlerbf526d12012-09-04 22:56:44 -040021 Slog.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
Daniel Sandler08d05e32012-08-08 16:39:54 -040022 }
23
24 public static final boolean BRAKES = false;
Daniel Sandler50508132012-08-16 14:10:53 -040025 private static final boolean STRETCH_PAST_CONTENTS = true;
Daniel Sandler08d05e32012-08-08 16:39:54 -040026
27 private float mSelfExpandVelocityPx; // classic value: 2000px/s
28 private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
29 private float mFlingExpandMinVelocityPx; // classic value: 200px/s
30 private float mFlingCollapseMinVelocityPx; // classic value: 200px/s
31 private float mCollapseMinDisplayFraction; // classic value: 0.08 (25px/min(320px,480px) on G1)
32 private float mExpandMinDisplayFraction; // classic value: 0.5 (drag open halfway to expand)
33 private float mFlingGestureMaxXVelocityPx; // classic value: 150px/s
34
Daniel Sandler173bae22012-09-25 14:37:42 -040035 private float mFlingGestureMinDistPx;
36
Daniel Sandler08d05e32012-08-08 16:39:54 -040037 private float mExpandAccelPx; // classic value: 2000px/s/s
38 private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up")
39
40 private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little
41 // faster than mSelfCollapseVelocityPx)
42
43 private float mCollapseBrakingDistancePx = 200; // XXX Resource
44 private float mExpandBrakingDistancePx = 150; // XXX Resource
45 private float mBrakingSpeedPx = 150; // XXX Resource
46
47 private View mHandleView;
48 private float mTouchOffset;
49 private float mExpandedFraction = 0;
50 private float mExpandedHeight = 0;
Daniel Sandler50508132012-08-16 14:10:53 -040051 private boolean mClosing;
52 private boolean mRubberbanding;
53 private boolean mTracking;
Daniel Sandler08d05e32012-08-08 16:39:54 -040054
55 private TimeAnimator mTimeAnimator;
56 private VelocityTracker mVelocityTracker;
57
58 private int[] mAbsPos = new int[2];
59 PanelBar mBar;
60
61 private final TimeListener mAnimationCallback = new TimeListener() {
62 @Override
63 public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
64 animationTick(deltaTime);
65 }
66 };
67
Daniel Sandler67eab792012-10-02 17:08:23 -040068 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 }
Daniel Sandler50508132012-08-16 14:10:53 -040076 }
Daniel Sandler67eab792012-10-02 17:08:23 -040077 };
Daniel Sandler5a35a0d2012-08-16 13:50:40 -040078
Daniel Sandler08d05e32012-08-08 16:39:54 -040079 private float mVel, mAccel;
80 private int mFullHeight = 0;
Daniel Sandler50508132012-08-16 14:10:53 -040081 private String mViewName;
Daniel Sandler173bae22012-09-25 14:37:42 -040082 protected float mInitialTouchY;
83 protected float mFinalTouchY;
Daniel Sandler08d05e32012-08-08 16:39:54 -040084
85 private void animationTick(long dtms) {
86 if (!mTimeAnimator.isStarted()) {
87 // XXX HAX to work around bug in TimeAnimator.end() not resetting its last time
88 mTimeAnimator = new TimeAnimator();
89 mTimeAnimator.setTimeListener(mAnimationCallback);
90
91 mTimeAnimator.start();
Daniel Sandler67eab792012-10-02 17:08:23 -040092
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?
Daniel Sandler173bae22012-09-25 14:37:42 -040096 if (mRubberbanding) {
97 mClosing = true;
98 } else if (mVel == 0) {
Daniel Sandler67eab792012-10-02 17:08:23 -040099 // if the panel is less than halfway open, close it
Daniel Sandler173bae22012-09-25 14:37:42 -0400100 mClosing = (mFinalTouchY / getFullHeight()) < 0.5f;
101 } else {
102 mClosing = mExpandedHeight > 0 && mVel < 0;
103 }
Daniel Sandler978f8532012-08-15 15:48:16 -0400104 } else if (dtms > 0) {
Daniel Sandler08d05e32012-08-08 16:39:54 -0400105 final float dt = dtms * 0.001f; // ms -> s
Daniel Sandler67eab792012-10-02 17:08:23 -0400106 if (DEBUG) LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
107 if (DEBUG) LOG("tick: before: h=%d", (int) mExpandedHeight);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400108
109 final float fh = getFullHeight();
Daniel Sandler08d05e32012-08-08 16:39:54 -0400110 boolean braking = false;
111 if (BRAKES) {
Daniel Sandler50508132012-08-16 14:10:53 -0400112 if (mClosing) {
Daniel Sandler08d05e32012-08-08 16:39:54 -0400113 braking = mExpandedHeight <= mCollapseBrakingDistancePx;
114 mAccel = braking ? 10*mCollapseAccelPx : -mCollapseAccelPx;
115 } else {
116 braking = mExpandedHeight >= (fh-mExpandBrakingDistancePx);
117 mAccel = braking ? 10*-mExpandAccelPx : mExpandAccelPx;
118 }
119 } else {
Daniel Sandler50508132012-08-16 14:10:53 -0400120 mAccel = mClosing ? -mCollapseAccelPx : mExpandAccelPx;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400121 }
122
123 mVel += mAccel * dt;
124
125 if (braking) {
Daniel Sandler50508132012-08-16 14:10:53 -0400126 if (mClosing && mVel > -mBrakingSpeedPx) {
Daniel Sandler08d05e32012-08-08 16:39:54 -0400127 mVel = -mBrakingSpeedPx;
Daniel Sandler50508132012-08-16 14:10:53 -0400128 } else if (!mClosing && mVel < mBrakingSpeedPx) {
Daniel Sandler08d05e32012-08-08 16:39:54 -0400129 mVel = mBrakingSpeedPx;
130 }
131 } else {
Daniel Sandler50508132012-08-16 14:10:53 -0400132 if (mClosing && mVel > -mFlingCollapseMinVelocityPx) {
Daniel Sandler08d05e32012-08-08 16:39:54 -0400133 mVel = -mFlingCollapseMinVelocityPx;
Daniel Sandler50508132012-08-16 14:10:53 -0400134 } else if (!mClosing && mVel > mFlingGestureMaxOutputVelocityPx) {
Daniel Sandler08d05e32012-08-08 16:39:54 -0400135 mVel = mFlingGestureMaxOutputVelocityPx;
136 }
137 }
138
139 float h = mExpandedHeight + mVel * dt;
Daniel Sandler67eab792012-10-02 17:08:23 -0400140
Daniel Sandler50508132012-08-16 14:10:53 -0400141 if (mRubberbanding && h < fh) {
142 h = fh;
143 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400144
Daniel Sandler67eab792012-10-02 17:08:23 -0400145 if (DEBUG) LOG("tick: new h=%d closing=%s", (int) h, mClosing?"true":"false");
Daniel Sandler08d05e32012-08-08 16:39:54 -0400146
147 setExpandedHeightInternal(h);
148
149 mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
150
151 if (mVel == 0
Daniel Sandler50508132012-08-16 14:10:53 -0400152 || (mClosing && mExpandedHeight == 0)
153 || ((mRubberbanding || !mClosing) && mExpandedHeight == fh)) {
Daniel Sandler5a35a0d2012-08-16 13:50:40 -0400154 post(mStopAnimator);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400155 }
156 }
157 }
158
159 public PanelView(Context context, AttributeSet attrs) {
160 super(context, attrs);
161
162 mTimeAnimator = new TimeAnimator();
163 mTimeAnimator.setTimeListener(mAnimationCallback);
164 }
165
166 private void loadDimens() {
167 final Resources res = getContext().getResources();
168
169 mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity);
170 mSelfCollapseVelocityPx = res.getDimension(R.dimen.self_collapse_velocity);
171 mFlingExpandMinVelocityPx = res.getDimension(R.dimen.fling_expand_min_velocity);
172 mFlingCollapseMinVelocityPx = res.getDimension(R.dimen.fling_collapse_min_velocity);
173
Daniel Sandler173bae22012-09-25 14:37:42 -0400174 mFlingGestureMinDistPx = res.getDimension(R.dimen.fling_gesture_min_dist);
175
Daniel Sandler08d05e32012-08-08 16:39:54 -0400176 mCollapseMinDisplayFraction = res.getFraction(R.dimen.collapse_min_display_fraction, 1, 1);
177 mExpandMinDisplayFraction = res.getFraction(R.dimen.expand_min_display_fraction, 1, 1);
178
179 mExpandAccelPx = res.getDimension(R.dimen.expand_accel);
180 mCollapseAccelPx = res.getDimension(R.dimen.collapse_accel);
181
182 mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity);
183
184 mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
185 }
186
187 private void trackMovement(MotionEvent event) {
188 // Add movement to velocity tracker using raw screen X and Y coordinates instead
189 // of window coordinates because the window frame may be moving at the same time.
190 float deltaX = event.getRawX() - event.getX();
191 float deltaY = event.getRawY() - event.getY();
192 event.offsetLocation(deltaX, deltaY);
193 mVelocityTracker.addMovement(event);
194 event.offsetLocation(-deltaX, -deltaY);
195 }
196
Daniel Sandlerbf526d12012-09-04 22:56:44 -0400197 // Pass all touches along to the handle, allowing the user to drag the panel closed from its interior
198 @Override
199 public boolean onTouchEvent(MotionEvent event) {
200 return mHandleView.dispatchTouchEvent(event);
201 }
202
Daniel Sandler08d05e32012-08-08 16:39:54 -0400203 @Override
204 protected void onFinishInflate() {
205 super.onFinishInflate();
206 loadDimens();
207
208 mHandleView = findViewById(R.id.handle);
Daniel Sandler67eab792012-10-02 17:08:23 -0400209 if (DEBUG) LOG("handle view: " + mHandleView);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400210 if (mHandleView != null) {
211 mHandleView.setOnTouchListener(new View.OnTouchListener() {
212 @Override
213 public boolean onTouch(View v, MotionEvent event) {
214 final float y = event.getY();
215 final float rawY = event.getRawY();
Daniel Sandler67eab792012-10-02 17:08:23 -0400216 if (DEBUG) LOG("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f",
Daniel Sandler978f8532012-08-15 15:48:16 -0400217 MotionEvent.actionToString(event.getAction()),
218 y, rawY, mTouchOffset);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400219 PanelView.this.getLocationOnScreen(mAbsPos);
220
221 switch (event.getAction()) {
222 case MotionEvent.ACTION_DOWN:
Daniel Sandler50508132012-08-16 14:10:53 -0400223 mTracking = true;
Daniel Sandler13522a22012-09-27 14:46:58 -0400224 mHandleView.setPressed(true);
Daniel Sandler173bae22012-09-25 14:37:42 -0400225 mInitialTouchY = y;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400226 mVelocityTracker = VelocityTracker.obtain();
227 trackMovement(event);
Daniel Sandler67eab792012-10-02 17:08:23 -0400228 mTimeAnimator.cancel(); // end any outstanding animations
Daniel Sandler978f8532012-08-15 15:48:16 -0400229 mBar.onTrackingStarted(PanelView.this);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400230 mTouchOffset = (rawY - mAbsPos[1]) - PanelView.this.getExpandedHeight();
231 break;
232
233 case MotionEvent.ACTION_MOVE:
Daniel Sandler50508132012-08-16 14:10:53 -0400234 PanelView.this.setExpandedHeightInternal(rawY - mAbsPos[1] - mTouchOffset);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400235
236 mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
237
238 trackMovement(event);
239 break;
240
241 case MotionEvent.ACTION_UP:
242 case MotionEvent.ACTION_CANCEL:
Daniel Sandler173bae22012-09-25 14:37:42 -0400243 mFinalTouchY = y;
Daniel Sandler50508132012-08-16 14:10:53 -0400244 mTracking = false;
Daniel Sandler13522a22012-09-27 14:46:58 -0400245 mHandleView.setPressed(false);
Daniel Sandler978f8532012-08-15 15:48:16 -0400246 mBar.onTrackingStopped(PanelView.this);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400247 trackMovement(event);
248 mVelocityTracker.computeCurrentVelocity(1000);
249
250 float yVel = mVelocityTracker.getYVelocity();
251 boolean negative = yVel < 0;
252
253 float xVel = mVelocityTracker.getXVelocity();
254 if (xVel < 0) {
255 xVel = -xVel;
256 }
257 if (xVel > mFlingGestureMaxXVelocityPx) {
258 xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
259 }
260
261 float vel = (float)Math.hypot(yVel, xVel);
262 if (vel > mFlingGestureMaxOutputVelocityPx) {
263 vel = mFlingGestureMaxOutputVelocityPx;
264 }
Daniel Sandler173bae22012-09-25 14:37:42 -0400265
266 // if you've barely moved your finger, we treat the velocity as 0
267 // preventing spurious flings due to touch screen jitter
Daniel Sandler67eab792012-10-02 17:08:23 -0400268 final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
Daniel Sandler173bae22012-09-25 14:37:42 -0400269 if (deltaY < mFlingGestureMinDistPx
270 || vel < mFlingGestureMinDistPx) {
271 vel = 0;
272 }
273
Daniel Sandler08d05e32012-08-08 16:39:54 -0400274 if (negative) {
275 vel = -vel;
276 }
277
Daniel Sandler67eab792012-10-02 17:08:23 -0400278 if (DEBUG) LOG("gesture: dy=%f vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
Daniel Sandler173bae22012-09-25 14:37:42 -0400279 deltaY,
Daniel Sandler08d05e32012-08-08 16:39:54 -0400280 mVelocityTracker.getXVelocity(),
281 mVelocityTracker.getYVelocity(),
282 xVel, yVel,
283 vel);
284
Daniel Sandlercf591db2012-08-15 16:11:55 -0400285 fling(vel, true);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400286
287 mVelocityTracker.recycle();
288 mVelocityTracker = null;
289
290 break;
291 }
292 return true;
293 }});
294 }
295 }
296
297 public void fling(float vel, boolean always) {
298 mVel = vel;
299
Daniel Sandlercf591db2012-08-15 16:11:55 -0400300 if (always||mVel != 0) {
Daniel Sandler08d05e32012-08-08 16:39:54 -0400301 animationTick(0); // begin the animation
302 }
303 }
304
305 @Override
306 protected void onAttachedToWindow() {
307 super.onAttachedToWindow();
Daniel Sandler978f8532012-08-15 15:48:16 -0400308 mViewName = getResources().getResourceName(getId());
309 }
310
311 public String getName() {
312 return mViewName;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400313 }
314
315 @Override
316 protected void onViewAdded(View child) {
Daniel Sandler67eab792012-10-02 17:08:23 -0400317 if (DEBUG) LOG("onViewAdded: " + child);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400318 }
319
320 public View getHandle() {
321 return mHandleView;
322 }
323
324 // Rubberbands the panel to hold its contents.
325 @Override
326 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
327 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
328
Daniel Sandler67eab792012-10-02 17:08:23 -0400329 if (DEBUG) LOG("onMeasure(%d, %d) -> (%d, %d)",
Daniel Sandler08d05e32012-08-08 16:39:54 -0400330 widthMeasureSpec, heightMeasureSpec, getMeasuredWidth(), getMeasuredHeight());
Daniel Sandler198a0302012-08-17 16:04:31 -0400331
332 // Did one of our children change size?
333 int newHeight = getMeasuredHeight();
334 if (newHeight != mFullHeight) {
335 mFullHeight = newHeight;
336 // If the user isn't actively poking us, let's rubberband to the content
Daniel Sandler67eab792012-10-02 17:08:23 -0400337 if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
Daniel Sandler198a0302012-08-17 16:04:31 -0400338 && mExpandedHeight > 0 && mExpandedHeight != mFullHeight) {
339 mExpandedHeight = mFullHeight;
340 }
Daniel Sandler50508132012-08-16 14:10:53 -0400341 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400342 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
343 (int) mExpandedHeight, MeasureSpec.AT_MOST); // MeasureSpec.getMode(heightMeasureSpec));
344 setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
345 }
346
347
348 public void setExpandedHeight(float height) {
Daniel Sandler198a0302012-08-17 16:04:31 -0400349 mTracking = mRubberbanding = false;
Daniel Sandler5a35a0d2012-08-16 13:50:40 -0400350 post(mStopAnimator);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400351 setExpandedHeightInternal(height);
352 }
353
Daniel Sandler50508132012-08-16 14:10:53 -0400354 @Override
355 protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
Daniel Sandler67eab792012-10-02 17:08:23 -0400356 if (DEBUG) LOG("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, mFullHeight);
Daniel Sandler50508132012-08-16 14:10:53 -0400357 super.onLayout(changed, left, top, right, bottom);
358 }
359
Daniel Sandler08d05e32012-08-08 16:39:54 -0400360 public void setExpandedHeightInternal(float h) {
361 float fh = getFullHeight();
362 if (fh == 0) {
363 // Hmm, full height hasn't been computed yet
364 }
365
Daniel Sandler08d05e32012-08-08 16:39:54 -0400366 if (h < 0) h = 0;
Daniel Sandler50508132012-08-16 14:10:53 -0400367 if (!(STRETCH_PAST_CONTENTS && (mTracking || mRubberbanding)) && h > fh) h = fh;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400368 mExpandedHeight = h;
369
Daniel Sandler67eab792012-10-02 17:08:23 -0400370 if (DEBUG) LOG("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
Daniel Sandler198a0302012-08-17 16:04:31 -0400371
Daniel Sandler08d05e32012-08-08 16:39:54 -0400372 requestLayout();
373// FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
374// lp.height = (int) mExpandedHeight;
375// setLayoutParams(lp);
376
Daniel Sandler198a0302012-08-17 16:04:31 -0400377 mExpandedFraction = Math.min(1f, (fh == 0) ? 0 : h / fh);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400378 }
379
380 private float getFullHeight() {
Daniel Sandler198a0302012-08-17 16:04:31 -0400381 if (mFullHeight <= 0) {
Daniel Sandler67eab792012-10-02 17:08:23 -0400382 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));
Daniel Sandler198a0302012-08-17 16:04:31 -0400385 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400386 return mFullHeight;
387 }
388
389 public void setExpandedFraction(float frac) {
390 setExpandedHeight(getFullHeight() * frac);
391 }
392
393 public float getExpandedHeight() {
394 return mExpandedHeight;
395 }
396
397 public float getExpandedFraction() {
398 return mExpandedFraction;
399 }
400
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700401 public boolean isFullyExpanded() {
Daniel Sandler67eab792012-10-02 17:08:23 -0400402 return mExpandedHeight >= getFullHeight();
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700403 }
404
405 public boolean isFullyCollapsed() {
Daniel Sandler67eab792012-10-02 17:08:23 -0400406 return mExpandedHeight <= 0;
407 }
408
409 public boolean isCollapsing() {
410 return mClosing;
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700411 }
412
Daniel Sandler08d05e32012-08-08 16:39:54 -0400413 public void setBar(PanelBar panelBar) {
414 mBar = panelBar;
415 }
416
Daniel Sandler08d05e32012-08-08 16:39:54 -0400417 public void collapse() {
418 // TODO: abort animation or ongoing touch
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700419 if (!isFullyCollapsed()) {
Daniel Sandler67eab792012-10-02 17:08:23 -0400420 // collapse() should never be a rubberband, even if an animation is already running
421 mRubberbanding = false;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400422 fling(-mSelfCollapseVelocityPx, /*always=*/ true);
423 }
424 }
425
426 public void expand() {
Daniel Sandler198a0302012-08-17 16:04:31 -0400427 if (isFullyCollapsed()) {
428 mBar.startOpeningPanel(this);
Daniel Sandler67eab792012-10-02 17:08:23 -0400429 if (DEBUG) LOG("expand: calling fling(%s, true)", mSelfExpandVelocityPx);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400430 fling (mSelfExpandVelocityPx, /*always=*/ true);
Daniel Sandler198a0302012-08-17 16:04:31 -0400431 } else if (DEBUG) {
Daniel Sandler67eab792012-10-02 17:08:23 -0400432 if (DEBUG) LOG("skipping expansion: is expanded");
Daniel Sandler08d05e32012-08-08 16:39:54 -0400433 }
434 }
435}