SlidingChallengeLayout.java revision 5be14ded6762bc51fabbbecb1b2ec01a8c758631
1d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller/* 2d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Copyright (C) 2012 The Android Open Source Project 3d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 4d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Licensed under the Apache License, Version 2.0 (the "License"); 5d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * you may not use this file except in compliance with the License. 6d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * You may obtain a copy of the License at 7d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 8d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * http://www.apache.org/licenses/LICENSE-2.0 9d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 10d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Unless required by applicable law or agreed to in writing, software 11d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * distributed under the License is distributed on an "AS IS" BASIS, 12d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * See the License for the specific language governing permissions and 14d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * limitations under the License. 15d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 16d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 17d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerpackage com.android.internal.policy.impl.keyguard; 18d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 196f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.animation.ObjectAnimator; 20d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.content.Context; 21d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.content.res.TypedArray; 22d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.graphics.Canvas; 231bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandlerimport android.graphics.Paint; 24d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.graphics.drawable.Drawable; 25d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.util.AttributeSet; 266f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.util.FloatProperty; 27d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.util.Log; 286f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.util.Property; 29d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.MotionEvent; 30d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.VelocityTracker; 31d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.View; 32d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.ViewConfiguration; 33d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.ViewGroup; 34d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.animation.Interpolator; 35d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.widget.Scroller; 36d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 37d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport com.android.internal.R; 38d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 39d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller/** 40d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * This layout handles interaction with the sliding security challenge views 41d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * that overlay/resize other keyguard contents. 42d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 4319a5267003e7dc70100a4bd4f1f449523b2ff38bJim Millerpublic class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout { 44d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final String TAG = "SlidingChallengeLayout"; 451bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler private static final boolean DEBUG = false; 46d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 47c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // The drag handle is measured in dp above & below the top edge of the 48c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // challenge view; these parameters change based on whether the challenge 49c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // is open or closed. 50cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell private static final int DRAG_HANDLE_CLOSED_ABOVE = 64; // dp 51cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp 52c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp 53c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp 54c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 55c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private static final boolean OPEN_ON_CLICK = true; 56c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 57c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private static final int HANDLE_ANIMATE_DURATION = 200; // ms 58c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 59d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Drawn to show the drag handle in closed state; crossfades to the challenge view 60d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // when challenge is fully visible 61d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private Drawable mHandleDrawable; 626f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private Drawable mFrameDrawable; 636f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private Drawable mDragIconDrawable; 64d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 65d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Initialized during measurement from child layoutparams 66d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private View mChallengeView; 67eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private View mScrimView; 68d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 69d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Range: 0 (fully hidden) to 1 (fully visible) 70d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private float mChallengeOffset = 1.f; 71d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mChallengeShowing = true; 72eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private boolean mIsBouncing = false; 73d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 74d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private final Scroller mScroller; 75d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mScrollState; 760b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private OnChallengeScrolledListener mScrollListener; 770b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private OnBouncerStateChangedListener mBouncerListener; 78d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 79d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_IDLE = 0; 80d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_DRAGGING = 1; 81d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_SETTLING = 2; 82d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 83d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final int MAX_SETTLE_DURATION = 600; // ms 84d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 85d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // ID of the pointer in charge of a current drag 86d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mActivePointerId = INVALID_POINTER; 87d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final int INVALID_POINTER = -1; 88d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 89d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if the user is currently dragging the slider 90d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mDragging; 91d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if the user may not drag until a new gesture begins 92d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mBlockDrag; 93d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 94d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private VelocityTracker mVelocityTracker; 95d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mMinVelocity; 96d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mMaxVelocity; 97c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private float mGestureStartX, mGestureStartY; // where did you first touch the screen? 98b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private int mGestureStartChallengeBottom; // where was the challenge at that time? 99c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 100c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleClosedBelow; // handle hitrect extension into the challenge view 101c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleClosedAbove; // extend the handle's hitrect this far above the line 102c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleOpenBelow; // handle hitrect extension into the challenge view 103c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleOpenAbove; // extend the handle's hitrect this far above the line 104c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 1050b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private int mDragHandleEdgeSlop; 10667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell private int mChallengeBottomBound; // Number of pixels from the top of the challenge view 10767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell // that should remain on-screen 108c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 109c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mTouchSlop; 110c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 1116f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell float mHandleAlpha; 1126f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell float mFrameAlpha; 1136f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private ObjectAnimator mHandleAnimation; 1146f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private ObjectAnimator mFrameAnimation; 1156f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1166f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA = 1176f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell new FloatProperty<SlidingChallengeLayout>("handleAlpha") { 1186f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1196f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setValue(SlidingChallengeLayout view, float value) { 1206f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mHandleAlpha = value; 1216f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.invalidate(); 1226f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1236f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1246f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1256f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public Float get(SlidingChallengeLayout view) { 1266f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell return view.mHandleAlpha; 1276f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1286f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell }; 1296f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1306f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell static final Property<SlidingChallengeLayout, Float> FRAME_ALPHA = 1316f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell new FloatProperty<SlidingChallengeLayout>("frameAlpha") { 1326f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1336f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setValue(SlidingChallengeLayout view, float value) { 1346f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (view.mFrameDrawable != null) { 1356f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameAlpha = value; 1366f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameDrawable.setAlpha((int) (value * 0xFF)); 1376f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameDrawable.invalidateSelf(); 1386f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1396f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1406f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1416f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1426f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public Float get(SlidingChallengeLayout view) { 1436f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell return view.mFrameAlpha; 1446f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1456f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell }; 146d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 147d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if at least one layout pass has happened since the view was attached. 148d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mHasLayout; 149d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 150d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final Interpolator sMotionInterpolator = new Interpolator() { 151d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public float getInterpolation(float t) { 152d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller t -= 1.0f; 153d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return t * t * t * t * t + 1.0f; 154d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 155d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 156d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 157d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final Interpolator sHandleFadeInterpolator = new Interpolator() { 158d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public float getInterpolation(float t) { 159d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return t * t; 160d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 161d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 162d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 163d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private final Runnable mEndScrollRunnable = new Runnable () { 164d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void run() { 165d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller completeChallengeScroll(); 166d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 167d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 168d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 169eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private final OnClickListener mScrimClickListener = new OnClickListener() { 170eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 171eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void onClick(View v) { 172eee209313d564be37b8fc068f785b3844cd6597eAdam Powell hideBouncer(); 173eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 174eee209313d564be37b8fc068f785b3844cd6597eAdam Powell }; 175eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 176d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 177d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Listener interface that reports changes in scroll state of the challenge area. 178d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 179d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public interface OnChallengeScrolledListener { 180d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 181d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * The scroll state itself changed. 182d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 183d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>scrollState will be one of the following:</p> 184d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 185d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <ul> 186d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li> 187d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging 188d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * the challenge area.</li> 189d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating 190d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * into place.</li> 191d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * </ul> 192d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 193d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>Do not perform expensive operations (e.g. layout) 194d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p> 195d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 196d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param scrollState The new scroll state of the challenge area. 197d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 198d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onScrollStateChanged(int scrollState); 199d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 200d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 201d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * The precise position of the challenge area has changed. 202d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 203d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>NOTE: It is NOT safe to modify layout or call any View methods that may 204d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * result in a requestLayout anywhere in your view hierarchy as a result of this call. 205d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * It may be called during drawing.</p> 206d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 207d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param scrollPosition New relative position of the challenge area. 208d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 1.f = fully visible/ready to be interacted with. 209d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 0.f = fully invisible/inaccessible to the user. 210d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param challengeTop Position of the top edge of the challenge view in px in the 211d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * SlidingChallengeLayout's coordinate system. 212d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 213d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onScrollPositionChanged(float scrollPosition, int challengeTop); 214d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 215d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 216d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context) { 217d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(context, null); 218d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 219d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 220d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context, AttributeSet attrs) { 221d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(context, attrs, 0); 222d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 223d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 224d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) { 225d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(context, attrs, defStyle); 226d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 227d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final TypedArray a = context.obtainStyledAttributes(attrs, 228d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller R.styleable.SlidingChallengeLayout, defStyle, 0); 2296f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell setDragDrawables(a.getDrawable(R.styleable.SlidingChallengeLayout_dragHandle), 2306f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell a.getDrawable(R.styleable.SlidingChallengeLayout_dragIcon)); 231d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 232d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller a.recycle(); 233d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 234d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller = new Scroller(context, sMotionInterpolator); 235d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 236d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final ViewConfiguration vc = ViewConfiguration.get(context); 237d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mMinVelocity = vc.getScaledMinimumFlingVelocity(); 238d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mMaxVelocity = vc.getScaledMaximumFlingVelocity(); 239d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 2400b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mDragHandleEdgeSlop = getResources().getDimensionPixelSize( 2410b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell R.dimen.kg_edge_swipe_region_size); 2420b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 243c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 244c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 2456f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final float density = getResources().getDisplayMetrics().density; 2461bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 2471bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // top half of the lock icon, plus another 25% to be sure 248c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f); 249c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleClosedBelow = (int) (DRAG_HANDLE_CLOSED_BELOW * density + 0.5f); 250c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleOpenAbove = (int) (DRAG_HANDLE_OPEN_ABOVE * density + 0.5f); 251c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f); 252c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 253c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // how much space to account for in the handle when closed 254cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell mChallengeBottomBound = mDragHandleClosedBelow; 2551bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 256cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell setWillNotDraw(false); 257cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell } 258cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell 259cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell public void setDragDrawables(Drawable handle, Drawable icon) { 2606f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleDrawable = handle; 2616f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable = icon; 2626f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2636f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2646f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setDragIconDrawable(Drawable d) { 2656f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable = d; 2666f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2676f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2686f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void showHandle(boolean visible) { 2696f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (visible) { 2706f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mHandleAnimation != null) { 2716f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.cancel(); 2726f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation = null; 2736f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2746f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAlpha = 1.f; 2756f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell invalidate(); 2766f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } else { 2776f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateHandle(false); 2786f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2796f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2806f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2816f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell void animateHandle(boolean visible) { 2826f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mHandleAnimation != null) { 2836f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.cancel(); 28467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mHandleAnimation = null; 285d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 28667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final float targetAlpha = visible ? 1.f : 0.f; 28767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell if (targetAlpha == mHandleAlpha) { 28867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell return; 28967625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell } 29067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, targetAlpha); 2916f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.setInterpolator(sHandleFadeInterpolator); 2926f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION); 2936f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.start(); 2946f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2956f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2966f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell void animateFrame(boolean visible, boolean full) { 2976f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mFrameDrawable == null) return; 2986f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2996f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mFrameAnimation != null) { 3006f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.cancel(); 30167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mFrameAnimation = null; 30267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell } 30367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final float targetAlpha = visible ? (full ? 1.f : 0.5f) : 0.f; 30467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell if (targetAlpha == mFrameAlpha) { 30567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell return; 306d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 30767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell 30867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mFrameAnimation = ObjectAnimator.ofFloat(this, FRAME_ALPHA, targetAlpha); 3096f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.setInterpolator(sHandleFadeInterpolator); 3106f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.setDuration(HANDLE_ANIMATE_DURATION); 3116f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.start(); 312d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 313d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 314d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void sendInitialListenerUpdates() { 3150b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 316d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0; 3170b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop); 3180b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollStateChanged(mScrollState); 319d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 320d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 321d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 322d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) { 3230b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener = listener; 324d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mHasLayout) { 325d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller sendInitialListenerUpdates(); 326d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 327d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 328d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3290b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) { 3300b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener = listener; 3310b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3320b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 333d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 334d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onAttachedToWindow() { 335d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.onAttachedToWindow(); 336d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 337d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHasLayout = false; 338d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 339d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 340d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 341d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onDetachedFromWindow() { 342d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.onDetachedFromWindow(); 343d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 344d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller removeCallbacks(mEndScrollRunnable); 345d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHasLayout = false; 346d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 347d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3480b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell @Override 3490b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell public void requestChildFocus(View child, View focused) { 3500b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mIsBouncing && child != mChallengeView) { 3510b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell // Clear out of the bouncer if the user tries to move focus outside of 3520b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell // the security challenge view. 3530b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell hideBouncer(); 3540b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3550b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell super.requestChildFocus(child, focused); 3560b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3570b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 358d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We want the duration of the page snap animation to be influenced by the distance that 359d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // the screen has to travel, however, we don't want this duration to be effected in a 360d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // purely linear fashion. Instead, we use this method to moderate the effect that the distance 361d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // of travel has on the overall snap duration. 362d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller float distanceInfluenceForSnapDuration(float f) { 363d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller f -= 0.5f; // center the values about 0. 364d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller f *= 0.3f * Math.PI / 2.0f; 365d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return (float) Math.sin(f); 366d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 367d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 368d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void setScrollState(int state) { 369d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mScrollState != state) { 370d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScrollState = state; 371d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3726f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing); 373e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen animateFrame(false , false); 3740b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 3750b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollStateChanged(state); 376d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 377d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 378d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 379d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 380d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void completeChallengeScroll() { 381d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(mChallengeOffset != 0); 382d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_IDLE); 383d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 384d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 385eee209313d564be37b8fc068f785b3844cd6597eAdam Powell void setScrimView(View scrim) { 386eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 387eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setOnClickListener(null); 388eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 389eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView = scrim; 390eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE); 391eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setFocusable(true); 392eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setOnClickListener(mScrimClickListener); 393eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 394eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 395d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 396d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Animate the bottom edge of the challenge view to the given position. 397d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 398d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param y desired final position for the bottom edge of the challenge view in px 399d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param velocity velocity in 400d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 401d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void animateChallengeTo(int y, int velocity) { 402d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 403d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Nothing to do. 404d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 405d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 40667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int sy = mChallengeView.getBottom(); 40767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int dy = y - sy; 408d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (dy == 0) { 409d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller completeChallengeScroll(); 410d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 411d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 412d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 413d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_SETTLING); 414d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 415d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childHeight = mChallengeView.getHeight(); 416d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int halfHeight = childHeight / 2; 417d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight); 418d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float distance = halfHeight + halfHeight * 419d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller distanceInfluenceForSnapDuration(distanceRatio); 420d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 421d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int duration = 0; 422d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller velocity = Math.abs(velocity); 423d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (velocity > 0) { 424d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 425d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 426d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float childDelta = (float) Math.abs(dy) / childHeight; 427d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = (int) ((childDelta + 1) * 100); 428d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 429d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = Math.min(duration, MAX_SETTLE_DURATION); 430d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 431d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.startScroll(0, sy, 0, dy, duration); 432d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller postInvalidateOnAnimation(); 433d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 434d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 435d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void setChallengeShowing(boolean showChallenge) { 43667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mChallengeShowing = showChallenge; 437d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 438d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 439d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 440d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @return true if the challenge is at all visible. 441d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 442d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean isChallengeShowing() { 443d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mChallengeShowing; 444d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 445d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 446d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 44719a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller public boolean isChallengeOverlapping() { 44819a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller return mChallengeShowing; 44919a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller } 45019a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller 45119a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller @Override 452eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public boolean isBouncing() { 453eee209313d564be37b8fc068f785b3844cd6597eAdam Powell return mIsBouncing; 454eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 455eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 456eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 457eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void showBouncer() { 458eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mIsBouncing) return; 459eee209313d564be37b8fc068f785b3844cd6597eAdam Powell showChallenge(true); 460eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mIsBouncing = true; 461eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 4626f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mScrimView.setVisibility(VISIBLE); 463eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 4646f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateFrame(true, true); 4650b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mBouncerListener != null) { 4660b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener.onBouncerStateChanged(true); 4670b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 468eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 469eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 470eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 471eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void hideBouncer() { 472eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (!mIsBouncing) return; 473eee209313d564be37b8fc068f785b3844cd6597eAdam Powell setChallengeShowing(false); 474eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mIsBouncing = false; 475eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 476eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setVisibility(GONE); 477eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 4786f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateFrame(false, false); 4790b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mBouncerListener != null) { 4800b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener.onBouncerStateChanged(false); 4810b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 482eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 483eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 484eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 485d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void requestDisallowInterceptTouchEvent(boolean allowIntercept) { 486d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We'll intercept whoever we feel like! ...as long as it isn't a challenge view. 487d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // If there are one or more pointers in the challenge view before we take over 488d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // touch events, onInterceptTouchEvent will set mBlockDrag. 489d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 490d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 491d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 492d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean onInterceptTouchEvent(MotionEvent ev) { 493d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mVelocityTracker == null) { 494d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = VelocityTracker.obtain(); 495d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 496d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.addMovement(ev); 497d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 498c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler //Log.v(TAG, "onIntercept: " + ev); 499c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 500d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int action = ev.getActionMasked(); 501d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller switch (action) { 502022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller case MotionEvent.ACTION_DOWN: 503c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = ev.getX(); 504b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartY = ev.getY(); 505995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = false; 506022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller break; 507022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 508d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_CANCEL: 509d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_UP: 510d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 511d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 512d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 513d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_MOVE: 514d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = ev.getPointerCount(); 515d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 516d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float x = ev.getX(i); 517d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float y = ev.getY(i); 518d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 5196f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (!mIsBouncing && 520b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler (isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) || 521d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) && 522d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId == INVALID_POINTER) { 523d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = ev.getPointerId(i); 524c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = x; 525c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartY = y; 526b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartChallengeBottom = getChallengeBottom(); 527d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = true; 528d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else if (isInChallengeView(x, y)) { 529d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mBlockDrag = true; 530d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 531d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 532d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 533d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 534d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 535d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mBlockDrag) { 536d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = INVALID_POINTER; 537d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = false; 538d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 539d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 540d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mDragging; 541d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 542d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 543d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void resetTouch() { 544d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.recycle(); 545d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = null; 546d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = INVALID_POINTER; 547d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = mBlockDrag = false; 548d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 549d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 550d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 551d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean onTouchEvent(MotionEvent ev) { 552d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mVelocityTracker == null) { 553d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = VelocityTracker.obtain(); 554d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 555d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.addMovement(ev); 556d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 557d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int action = ev.getActionMasked(); 558d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller switch (action) { 559995270f01175234d0615a0e1900576f142a3b4adAdam Powell case MotionEvent.ACTION_DOWN: 560995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = false; 561c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = ev.getX(); 562995270f01175234d0615a0e1900576f142a3b4adAdam Powell mGestureStartY = ev.getY(); 563995270f01175234d0615a0e1900576f142a3b4adAdam Powell break; 564995270f01175234d0615a0e1900576f142a3b4adAdam Powell 565d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_CANCEL: 566d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mDragging) { 567d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(0); 568d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 569d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 570d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 571d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 572d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_POINTER_UP: 573d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) { 574d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 575d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 576d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_UP: 577c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler if (OPEN_ON_CLICK 578c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler && isInDragHandle(mGestureStartX, mGestureStartY) 579c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler && Math.abs(ev.getX() - mGestureStartX) <= mTouchSlop 580c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler && Math.abs(ev.getY() - mGestureStartY) <= mTouchSlop) { 581c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler showChallenge(true); 582c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler } else if (mDragging) { 583d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); 584d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId)); 585d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 586d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 587d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 588d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 589d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_MOVE: 5906f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (!mDragging && !mBlockDrag && !mIsBouncing) { 591d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = ev.getPointerCount(); 592d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 593d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float x = ev.getX(i); 594d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float y = ev.getY(i); 595d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 596b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) || 597d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) 598d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller && mActivePointerId == INVALID_POINTER) { 599c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = x; 600b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartY = y; 601d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = ev.getPointerId(i); 602b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartChallengeBottom = getChallengeBottom(); 603d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = true; 604d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 605d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 606d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 607d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 608d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Not an else; this can be set above. 609d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mDragging) { 610d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // No-op if already in this state, but set it here in case we arrived 611d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // at this point from either intercept or the above. 612d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_DRAGGING); 613d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 614d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int index = ev.findPointerIndex(mActivePointerId); 615d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (index < 0) { 616d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Oops, bogus state. We lost some touch events somewhere. 617d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Just drop it with no velocity and let things settle. 618d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 619d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(0); 620d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 621d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 622b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final float y = ev.getY(index); 623b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final float pos = Math.min(y - mGestureStartY, 62467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell getLayoutBottom() - mChallengeBottomBound); 625b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 626b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler moveChallengeTo(mGestureStartChallengeBottom + (int) pos); 627d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 628d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 629d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 630d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 631d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 632d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 633b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 634b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * We only want to add additional vertical space to the drag handle when the panel is fully 635b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * closed. 636b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 637c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int getDragHandleSizeAbove() { 638c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler return isChallengeShowing() ? mDragHandleOpenAbove : mDragHandleClosedAbove; 639c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler } 640c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int getDragHandleSizeBelow() { 641c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler return isChallengeShowing() ? mDragHandleOpenBelow : mDragHandleClosedBelow; 642b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler } 643b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 644d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean isInChallengeView(float x, float y) { 645d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return false; 646d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 647d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return x >= mChallengeView.getLeft() && y >= mChallengeView.getTop() && 648d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller x < mChallengeView.getRight() && y < mChallengeView.getBottom(); 649d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 650d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 651d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean isInDragHandle(float x, float y) { 652d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return false; 653d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 6540b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell return x >= mDragHandleEdgeSlop && 655c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler y >= mChallengeView.getTop() - getDragHandleSizeAbove() && 6560b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell x < getWidth() - mDragHandleEdgeSlop && 657c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler y < mChallengeView.getTop() + getDragHandleSizeBelow(); 658d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 659d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 660b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private boolean crossedDragHandle(float x, float y, float initialY) { 661022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller final int challengeTop = mChallengeView.getTop(); 6621bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler return x >= 0 && 6631bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler x < getWidth() && 664c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler initialY < (challengeTop - getDragHandleSizeAbove()) && 665c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler y > challengeTop + getDragHandleSizeBelow(); 666022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller } 667022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 668d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 669d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected void onMeasure(int widthSpec, int heightSpec) { 670d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY || 671d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) { 672d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller throw new IllegalArgumentException( 673d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller "SlidingChallengeLayout must be measured with an exact size"); 674d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 675d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 676d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int width = MeasureSpec.getSize(widthSpec); 677d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int height = MeasureSpec.getSize(heightSpec); 678d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setMeasuredDimension(width, height); 679d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 680d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Find one and only one challenge view. 681d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View oldChallengeView = mChallengeView; 682d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView = null; 683d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = getChildCount(); 6848a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen 6858a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // First iteration through the children finds special children and sets any associated 6868a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // state. 687d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 688d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View child = getChildAt(i); 689d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 690d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 691eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { 692d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != null) { 693d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller throw new IllegalStateException( 694d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller "There may only be one child with layout_isChallenge=\"true\""); 695d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 696d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView = child; 697d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != oldChallengeView) { 698d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE); 699d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 7006f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell // We're going to play silly games with the frame's background drawable later. 7016f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameDrawable = mChallengeView.getBackground(); 702eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) { 703eee209313d564be37b8fc068f785b3844cd6597eAdam Powell setScrimView(child); 704d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 7055be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen 706d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (child.getVisibility() == GONE) continue; 7078a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen } 7088a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen 7095be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen // We want to measure the challenge view first, since the KeyguardWidgetPager 7105be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen // needs to do things its measure pass that are dependent on the challenge view 7115be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen // having been measured. 7128a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen if (mChallengeView != null) { 7138a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen measureChildWithMargins(mChallengeView, widthSpec, 0, heightSpec, 0); 7148a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen } 715d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 7168a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // Measure the rest of the children 7178a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen for (int i = 0; i < count; i++) { 7188a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen final View child = getChildAt(i); 7198a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // Don't measure the challenge view twice! 7208a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen if (child != mChallengeView) { 7218a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen measureChildWithMargins(child, widthSpec, 0, heightSpec, 0); 7228a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen } 723d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 724d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 725d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 726d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 727d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected void onLayout(boolean changed, int l, int t, int r, int b) { 728d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingLeft = getPaddingLeft(); 729d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingTop = getPaddingTop(); 730d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingRight = getPaddingRight(); 731d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingBottom = getPaddingBottom(); 732d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int width = r - l; 733d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int height = b - t; 734d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 735d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = getChildCount(); 736d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 737d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View child = getChildAt(i); 738d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 739d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (child.getVisibility() == GONE) continue; 740d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 741d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 742d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 743eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { 744d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Challenge views pin to the bottom, offset by a portion of their height, 745d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // and center horizontally. 746d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int center = (paddingLeft + width - paddingRight) / 2; 747d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childWidth = child.getMeasuredWidth(); 748d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childHeight = child.getMeasuredHeight(); 749d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int left = center - childWidth / 2; 750d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int layoutBottom = height - paddingBottom - lp.bottomMargin; 751d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We use the top of the challenge view to position the handle, so 752d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // we never want less than the handle size showing at the bottom. 75367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound) 754d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * (1 - mChallengeOffset)); 75567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell child.setAlpha(mChallengeOffset / 2 + 0.5f); 756d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.layout(left, bottom - childHeight, left + childWidth, bottom); 757d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 758d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Non-challenge views lay out from the upper left, layered. 759d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.layout(paddingLeft + lp.leftMargin, 760d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingTop + lp.topMargin, 761d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingLeft + child.getMeasuredWidth(), 762d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingTop + child.getMeasuredHeight()); 763d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 764d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 765d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 766d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (!mHasLayout) { 76767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell if (mFrameDrawable != null) { 76867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mFrameDrawable.setAlpha(0); 76967625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell } 7706f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHasLayout = true; 771d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 772d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 773d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 774d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void computeScroll() { 775d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.computeScroll(); 776d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 777d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (!mScroller.isFinished()) { 778d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 779d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Can't scroll if the view is missing. 780d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller Log.e(TAG, "Challenge view missing in computeScroll"); 781d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.abortAnimation(); 782d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 783d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 784d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 785d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.computeScrollOffset(); 786d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller moveChallengeTo(mScroller.getCurrY()); 787d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 788d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mScroller.isFinished()) { 789d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller post(mEndScrollRunnable); 790d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 791d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 792d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 793d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 794d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 795d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void draw(Canvas c) { 796d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.draw(c); 7971bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 7981bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler final Paint debugPaint; 7991bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 8001bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint = new Paint(); 8011bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0x40FF00CC); 8021bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // show the isInDragHandle() rect 8031bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(mDragHandleEdgeSlop, 804c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mChallengeView.getTop() - getDragHandleSizeAbove(), 8051bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler getWidth() - mDragHandleEdgeSlop, 806c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mChallengeView.getTop() + getDragHandleSizeBelow(), 8071bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint); 8081bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 8091bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 810c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler if (mChallengeView != null && mHandleAlpha > 0) { 811d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int top = mChallengeView.getTop(); 812c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler final int handleHeight; 8136f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int challengeLeft = mChallengeView.getLeft(); 8146f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int challengeRight = mChallengeView.getRight(); 815c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler if (mHandleDrawable != null) { 816c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler handleHeight = mHandleDrawable.getIntrinsicHeight(); 817c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mHandleDrawable.setBounds(challengeLeft, top, challengeRight, top + handleHeight); 818c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mHandleDrawable.setAlpha((int) (mHandleAlpha * 0xFF)); 819c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mHandleDrawable.draw(c); 820c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler } else { 821c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler handleHeight = 0; 822c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler } 8236f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 8241bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 8251bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // now show the actual drag handle 8261bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setStyle(Paint.Style.STROKE); 8271bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setStrokeWidth(1); 8281bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0xFF80FF00); 8291bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(challengeLeft, top, challengeRight, top + handleHeight, debugPaint); 8301bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 8311bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 8326f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mDragIconDrawable != null) { 833cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell final int closedTop = getLayoutBottom() - mChallengeBottomBound; 8346f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconWidth = mDragIconDrawable.getIntrinsicWidth(); 8356f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconHeight = mDragIconDrawable.getIntrinsicHeight(); 8366f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconLeft = (challengeLeft + challengeRight - iconWidth) / 2; 837cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell final int iconTop = closedTop + 838cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell (mDragHandleClosedBelow - mDragHandleClosedAbove - iconHeight) / 2; 8396f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable.setBounds(iconLeft, iconTop, iconLeft + iconWidth, 8406f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell iconTop + iconHeight); 8416f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable.setAlpha((int) (mHandleAlpha * 0xFF)); 8426f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable.draw(c); 8431bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 8441bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 8451bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0xFF00FF00); 8461bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(iconLeft, iconTop, iconLeft + iconWidth, 8471bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler iconTop + iconHeight, debugPaint); 8481bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 8496f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 850d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 851d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 852d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 853e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen public int getMaxChallengeTop() { 854e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen if (mChallengeView == null) return 0; 855e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen 856e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen final int layoutBottom = getLayoutBottom(); 8578a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen final int challengeHeight = mChallengeView.getMeasuredHeight(); 858e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen return layoutBottom - challengeHeight; 859e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen } 860e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen 861d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 862d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Move the bottom edge of mChallengeView to a new position and notify the listener 863d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * if it represents a change in position. Changes made through this method will 864d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * be stable across layout passes. If this method is called before first layout of 865d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * this SlidingChallengeLayout it will have no effect. 866d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 867d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system. 868d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @return true if the challenge view was moved 869d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 870d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean moveChallengeTo(int bottom) { 871d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null || !mHasLayout) { 872d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return false; 873d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 874d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 875b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final int layoutBottom = getLayoutBottom(); 876d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int challengeHeight = mChallengeView.getHeight(); 877d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 878d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller bottom = Math.max(layoutBottom, 87967625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell Math.min(bottom, layoutBottom + challengeHeight - mChallengeBottomBound)); 880d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 88167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell float offset = 1.f - (float) (bottom - layoutBottom) / 88267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell (challengeHeight - mChallengeBottomBound); 883d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeOffset = offset; 884d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (offset > 0 && !mChallengeShowing) { 885d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(true); 886d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 887d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 888d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.layout(mChallengeView.getLeft(), 889d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom); 890d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 89167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mChallengeView.setAlpha(offset / 2 + 0.5f); 8920b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 8930b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop()); 894d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 895d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller postInvalidateOnAnimation(); 896d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 897d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 898d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 899b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 900b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * The bottom edge of this SlidingChallengeLayout's coordinate system; will coincide with 901b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * the bottom edge of mChallengeView when the challenge is fully opened. 902b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 903b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private int getLayoutBottom() { 904b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final int bottomMargin = (mChallengeView == null) 905b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler ? 0 906b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler : ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin; 9078a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen final int layoutBottom = getMeasuredHeight() - getPaddingBottom() - bottomMargin; 908b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler return layoutBottom; 909b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler } 910b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 911b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 912b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * The bottom edge of mChallengeView; essentially, where the sliding challenge 'is'. 913b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 914d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int getChallengeBottom() { 915d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return 0; 916d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 917d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mChallengeView.getBottom(); 918d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 919d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 920b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 921d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Show or hide the challenge view, animating it if necessary. 922d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param show true to show, false to hide 923d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 924d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void showChallenge(boolean show) { 925d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(show, 0); 926995270f01175234d0615a0e1900576f142a3b4adAdam Powell if (!show) { 927995270f01175234d0615a0e1900576f142a3b4adAdam Powell // Block any drags in progress so that callers can use this to disable dragging 928995270f01175234d0615a0e1900576f142a3b4adAdam Powell // for other touch interactions. 929995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = true; 930995270f01175234d0615a0e1900576f142a3b4adAdam Powell } 931d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 932d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 933d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void showChallenge(int velocity) { 934d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller boolean show = false; 935d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (Math.abs(velocity) > mMinVelocity) { 936d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller show = velocity < 0; 937d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 938d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller show = mChallengeOffset >= 0.5f; 939d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 940d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(show, velocity); 941d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 942d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 943d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void showChallenge(boolean show, int velocity) { 944d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 945d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(false); 946d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 947d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 948d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 949d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mHasLayout) { 95067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int layoutBottom = getLayoutBottom(); 951d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller animateChallengeTo(show ? layoutBottom : 95267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell layoutBottom + mChallengeView.getHeight() - mChallengeBottomBound, velocity); 953d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 954d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 955d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 95619a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller @Override 957d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 958d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return new LayoutParams(getContext(), attrs); 959d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 960d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 961d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 962d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 963d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : 964d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) : 965d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller new LayoutParams(p); 966d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 967d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 968d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 969d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 970d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return new LayoutParams(); 971d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 972d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 973d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 974d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 975d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return p instanceof LayoutParams; 976d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 977d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 978d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static class LayoutParams extends MarginLayoutParams { 979eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public int childType = CHILD_TYPE_NONE; 980eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_NONE = 0; 981eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_CHALLENGE = 2; 982eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_SCRIM = 4; 983d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 984d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams() { 985d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(MATCH_PARENT, WRAP_CONTENT); 986d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 987d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 988d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(int width, int height) { 989d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(width, height); 990d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 991d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 992d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(android.view.ViewGroup.LayoutParams source) { 993d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 994d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 995d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 996d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(MarginLayoutParams source) { 997d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 998d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 999d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1000d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(LayoutParams source) { 1001d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 1002d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1003eee209313d564be37b8fc068f785b3844cd6597eAdam Powell childType = source.childType; 1004d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1005d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1006d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(Context c, AttributeSet attrs) { 1007d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(c, attrs); 1008d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1009d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final TypedArray a = c.obtainStyledAttributes(attrs, 1010d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller R.styleable.SlidingChallengeLayout_Layout); 1011eee209313d564be37b8fc068f785b3844cd6597eAdam Powell childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType, 1012eee209313d564be37b8fc068f785b3844cd6597eAdam Powell CHILD_TYPE_NONE); 1013d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller a.recycle(); 1014d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1015d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1016d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller} 1017