SlidingChallengeLayout.java revision 995270f01175234d0615a0e1900576f142a3b4ad
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 47d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Drawn to show the drag handle in closed state; crossfades to the challenge view 48d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // when challenge is fully visible 49d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private Drawable mHandleDrawable; 506f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private Drawable mFrameDrawable; 516f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private Drawable mDragIconDrawable; 52d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 53d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Initialized during measurement from child layoutparams 54d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private View mChallengeView; 55eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private View mScrimView; 56d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 57d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Range: 0 (fully hidden) to 1 (fully visible) 58d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private float mChallengeOffset = 1.f; 59d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mChallengeShowing = true; 60eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private boolean mIsBouncing = false; 61d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 62d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private final Scroller mScroller; 63d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mScrollState; 640b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private OnChallengeScrolledListener mScrollListener; 650b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private OnBouncerStateChangedListener mBouncerListener; 66d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 67d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_IDLE = 0; 68d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_DRAGGING = 1; 69d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_SETTLING = 2; 70d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 71d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final int MAX_SETTLE_DURATION = 600; // ms 72d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 73d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // ID of the pointer in charge of a current drag 74d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mActivePointerId = INVALID_POINTER; 75d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final int INVALID_POINTER = -1; 76d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 77d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if the user is currently dragging the slider 78d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mDragging; 79d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if the user may not drag until a new gesture begins 80d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mBlockDrag; 81d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 82d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private VelocityTracker mVelocityTracker; 83d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mMinVelocity; 84d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mMaxVelocity; 85b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private float mGestureStartY; // where did you touch the screen to start this gesture? 86b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private int mGestureStartChallengeBottom; // where was the challenge at that time? 871bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler private int mDragHandleSize; // handle hitrect extension into the challenge view 881bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler private int mDragHandleHeadroom; // extend the handle's hitrect this far above the line 890b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private int mDragHandleEdgeSlop; 9067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell private int mChallengeBottomBound; // Number of pixels from the top of the challenge view 9167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell // that should remain on-screen 926f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell float mHandleAlpha; 936f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell float mFrameAlpha; 946f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private ObjectAnimator mHandleAnimation; 956f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private ObjectAnimator mFrameAnimation; 966f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 976f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA = 986f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell new FloatProperty<SlidingChallengeLayout>("handleAlpha") { 996f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1006f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setValue(SlidingChallengeLayout view, float value) { 1016f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mHandleAlpha = value; 1026f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.invalidate(); 1036f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1046f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1056f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1066f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public Float get(SlidingChallengeLayout view) { 1076f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell return view.mHandleAlpha; 1086f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1096f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell }; 1106f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1116f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell static final Property<SlidingChallengeLayout, Float> FRAME_ALPHA = 1126f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell new FloatProperty<SlidingChallengeLayout>("frameAlpha") { 1136f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1146f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setValue(SlidingChallengeLayout view, float value) { 1156f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (view.mFrameDrawable != null) { 1166f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameAlpha = value; 1176f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameDrawable.setAlpha((int) (value * 0xFF)); 1186f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameDrawable.invalidateSelf(); 1196f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1206f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1216f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1226f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1236f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public Float get(SlidingChallengeLayout view) { 1246f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell return view.mFrameAlpha; 1256f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1266f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell }; 127d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 128d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final int DRAG_HANDLE_DEFAULT_SIZE = 32; // dp 1296f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private static final int HANDLE_ANIMATE_DURATION = 200; // ms 130d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 131d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if at least one layout pass has happened since the view was attached. 132d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mHasLayout; 133d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 134d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final Interpolator sMotionInterpolator = new Interpolator() { 135d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public float getInterpolation(float t) { 136d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller t -= 1.0f; 137d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return t * t * t * t * t + 1.0f; 138d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 139d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 140d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 141d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final Interpolator sHandleFadeInterpolator = new Interpolator() { 142d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public float getInterpolation(float t) { 143d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return t * t; 144d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 145d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 146d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 147d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private final Runnable mEndScrollRunnable = new Runnable () { 148d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void run() { 149d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller completeChallengeScroll(); 150d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 151d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 152d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 153eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private final OnClickListener mScrimClickListener = new OnClickListener() { 154eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 155eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void onClick(View v) { 156eee209313d564be37b8fc068f785b3844cd6597eAdam Powell hideBouncer(); 157eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 158eee209313d564be37b8fc068f785b3844cd6597eAdam Powell }; 159eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 160d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 161d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Listener interface that reports changes in scroll state of the challenge area. 162d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 163d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public interface OnChallengeScrolledListener { 164d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 165d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * The scroll state itself changed. 166d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 167d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>scrollState will be one of the following:</p> 168d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 169d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <ul> 170d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li> 171d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging 172d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * the challenge area.</li> 173d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating 174d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * into place.</li> 175d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * </ul> 176d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 177d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>Do not perform expensive operations (e.g. layout) 178d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p> 179d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 180d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param scrollState The new scroll state of the challenge area. 181d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 182d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onScrollStateChanged(int scrollState); 183d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 184d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 185d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * The precise position of the challenge area has changed. 186d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 187d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>NOTE: It is NOT safe to modify layout or call any View methods that may 188d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * result in a requestLayout anywhere in your view hierarchy as a result of this call. 189d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * It may be called during drawing.</p> 190d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 191d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param scrollPosition New relative position of the challenge area. 192d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 1.f = fully visible/ready to be interacted with. 193d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 0.f = fully invisible/inaccessible to the user. 194d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param challengeTop Position of the top edge of the challenge view in px in the 195d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * SlidingChallengeLayout's coordinate system. 196d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 197d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onScrollPositionChanged(float scrollPosition, int challengeTop); 198d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 199d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 200d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context) { 201d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(context, null); 202d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 203d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 204d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context, AttributeSet attrs) { 205d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(context, attrs, 0); 206d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 207d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 208d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) { 209d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(context, attrs, defStyle); 210d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 211d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final TypedArray a = context.obtainStyledAttributes(attrs, 212d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller R.styleable.SlidingChallengeLayout, defStyle, 0); 2136f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell setDragDrawables(a.getDrawable(R.styleable.SlidingChallengeLayout_dragHandle), 2146f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell a.getDrawable(R.styleable.SlidingChallengeLayout_dragIcon)); 215d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 216d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller a.recycle(); 217d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 218d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller = new Scroller(context, sMotionInterpolator); 219d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 220d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final ViewConfiguration vc = ViewConfiguration.get(context); 221d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mMinVelocity = vc.getScaledMinimumFlingVelocity(); 222d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mMaxVelocity = vc.getScaledMaximumFlingVelocity(); 223d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 2240b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mDragHandleEdgeSlop = getResources().getDimensionPixelSize( 2250b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell R.dimen.kg_edge_swipe_region_size); 2260b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 227d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setWillNotDraw(false); 228d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 229d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 2306f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setDragDrawables(Drawable handle, Drawable icon) { 2316f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final float density = getResources().getDisplayMetrics().density; 2326f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int defaultSize = (int) (DRAG_HANDLE_DEFAULT_SIZE * density + 0.5f); 23367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int handleHeight = handle != null ? handle.getIntrinsicHeight() : 0; 23467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int iconHeight = icon != null ? icon.getIntrinsicHeight() : 0; 23567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mDragHandleSize = Math.max(handleHeight > 0 ? handleHeight : defaultSize, 23667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell iconHeight > 0 ? iconHeight : defaultSize); 2371bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 2381bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // top half of the lock icon, plus another 25% to be sure 23967625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mDragHandleHeadroom = (int) (iconHeight * 0.75f); 24067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mChallengeBottomBound = (mDragHandleSize + mDragHandleHeadroom + handleHeight) / 2; 2411bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 2426f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleDrawable = handle; 2436f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable = icon; 2446f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2456f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2466f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setDragIconDrawable(Drawable d) { 2476f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable = d; 2486f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2496f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2506f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void showHandle(boolean visible) { 2516f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (visible) { 2526f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mHandleAnimation != null) { 2536f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.cancel(); 2546f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation = null; 2556f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2566f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAlpha = 1.f; 2576f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell invalidate(); 2586f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } else { 2596f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateHandle(false); 2606f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2616f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2626f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2636f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell void animateHandle(boolean visible) { 2646f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mHandleAnimation != null) { 2656f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.cancel(); 26667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mHandleAnimation = null; 267d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 26867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final float targetAlpha = visible ? 1.f : 0.f; 26967625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell if (targetAlpha == mHandleAlpha) { 27067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell return; 27167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell } 27267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, targetAlpha); 2736f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.setInterpolator(sHandleFadeInterpolator); 2746f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION); 2756f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.start(); 2766f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2776f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2786f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell void animateFrame(boolean visible, boolean full) { 2796f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mFrameDrawable == null) return; 2806f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2816f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mFrameAnimation != null) { 2826f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.cancel(); 28367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mFrameAnimation = null; 28467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell } 28567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final float targetAlpha = visible ? (full ? 1.f : 0.5f) : 0.f; 28667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell if (targetAlpha == mFrameAlpha) { 28767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell return; 288d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 28967625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell 29067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mFrameAnimation = ObjectAnimator.ofFloat(this, FRAME_ALPHA, targetAlpha); 2916f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.setInterpolator(sHandleFadeInterpolator); 2926f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.setDuration(HANDLE_ANIMATE_DURATION); 2936f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.start(); 294d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 295d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 296d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void sendInitialListenerUpdates() { 2970b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 298d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0; 2990b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop); 3000b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollStateChanged(mScrollState); 301d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 302d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 303d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 304d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) { 3050b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener = listener; 306d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mHasLayout) { 307d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller sendInitialListenerUpdates(); 308d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 309d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 310d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3110b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) { 3120b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener = listener; 3130b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3140b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 315d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 316d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onAttachedToWindow() { 317d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.onAttachedToWindow(); 318d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 319d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHasLayout = false; 320d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 321d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 322d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 323d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onDetachedFromWindow() { 324d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.onDetachedFromWindow(); 325d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 326d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller removeCallbacks(mEndScrollRunnable); 327d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHasLayout = false; 328d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 329d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3300b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell @Override 3310b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell public void requestChildFocus(View child, View focused) { 3320b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mIsBouncing && child != mChallengeView) { 3330b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell // Clear out of the bouncer if the user tries to move focus outside of 3340b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell // the security challenge view. 3350b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell hideBouncer(); 3360b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3370b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell super.requestChildFocus(child, focused); 3380b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3390b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 340d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We want the duration of the page snap animation to be influenced by the distance that 341d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // the screen has to travel, however, we don't want this duration to be effected in a 342d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // purely linear fashion. Instead, we use this method to moderate the effect that the distance 343d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // of travel has on the overall snap duration. 344d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller float distanceInfluenceForSnapDuration(float f) { 345d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller f -= 0.5f; // center the values about 0. 346d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller f *= 0.3f * Math.PI / 2.0f; 347d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return (float) Math.sin(f); 348d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 349d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 350d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void setScrollState(int state) { 351d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mScrollState != state) { 352d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScrollState = state; 353d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3546f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing); 35567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell animateFrame(state != SCROLL_STATE_IDLE, false); 3560b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 3570b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollStateChanged(state); 358d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 359d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 360d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 361d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 362d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void completeChallengeScroll() { 363d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(mChallengeOffset != 0); 364d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_IDLE); 365d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 366d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 367eee209313d564be37b8fc068f785b3844cd6597eAdam Powell void setScrimView(View scrim) { 368eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 369eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setOnClickListener(null); 370eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 371eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView = scrim; 372eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE); 373eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setFocusable(true); 374eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setOnClickListener(mScrimClickListener); 375eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 376eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 377d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 378d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Animate the bottom edge of the challenge view to the given position. 379d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 380d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param y desired final position for the bottom edge of the challenge view in px 381d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param velocity velocity in 382d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 383d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void animateChallengeTo(int y, int velocity) { 384d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 385d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Nothing to do. 386d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 387d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 38867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int sy = mChallengeView.getBottom(); 38967625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int dy = y - sy; 390d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (dy == 0) { 391d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller completeChallengeScroll(); 392d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 393d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 394d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 395d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_SETTLING); 396d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 397d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childHeight = mChallengeView.getHeight(); 398d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int halfHeight = childHeight / 2; 399d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight); 400d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float distance = halfHeight + halfHeight * 401d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller distanceInfluenceForSnapDuration(distanceRatio); 402d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 403d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int duration = 0; 404d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller velocity = Math.abs(velocity); 405d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (velocity > 0) { 406d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 407d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 408d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float childDelta = (float) Math.abs(dy) / childHeight; 409d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = (int) ((childDelta + 1) * 100); 410d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 411d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = Math.min(duration, MAX_SETTLE_DURATION); 412d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 413d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.startScroll(0, sy, 0, dy, duration); 414d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller postInvalidateOnAnimation(); 415d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 416d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 417d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void setChallengeShowing(boolean showChallenge) { 41867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mChallengeShowing = showChallenge; 419d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 420d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 421d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 422d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @return true if the challenge is at all visible. 423d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 424d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean isChallengeShowing() { 425d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mChallengeShowing; 426d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 427d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 428d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 42919a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller public boolean isChallengeOverlapping() { 43019a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller return mChallengeShowing; 43119a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller } 43219a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller 43319a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller @Override 434eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public boolean isBouncing() { 435eee209313d564be37b8fc068f785b3844cd6597eAdam Powell return mIsBouncing; 436eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 437eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 438eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 439eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void showBouncer() { 440eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mIsBouncing) return; 441eee209313d564be37b8fc068f785b3844cd6597eAdam Powell showChallenge(true); 442eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mIsBouncing = true; 443eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 4446f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mScrimView.setVisibility(VISIBLE); 445eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 4466f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateFrame(true, true); 4470b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mBouncerListener != null) { 4480b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener.onBouncerStateChanged(true); 4490b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 450eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 451eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 452eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 453eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void hideBouncer() { 454eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (!mIsBouncing) return; 455eee209313d564be37b8fc068f785b3844cd6597eAdam Powell setChallengeShowing(false); 456eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mIsBouncing = false; 457eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 458eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setVisibility(GONE); 459eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 4606f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateFrame(false, false); 4610b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mBouncerListener != null) { 4620b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener.onBouncerStateChanged(false); 4630b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 464eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 465eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 466eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 467d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void requestDisallowInterceptTouchEvent(boolean allowIntercept) { 468d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We'll intercept whoever we feel like! ...as long as it isn't a challenge view. 469d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // If there are one or more pointers in the challenge view before we take over 470d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // touch events, onInterceptTouchEvent will set mBlockDrag. 471d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 472d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 473d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 474d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean onInterceptTouchEvent(MotionEvent ev) { 475d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mVelocityTracker == null) { 476d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = VelocityTracker.obtain(); 477d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 478d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.addMovement(ev); 479d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 480d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int action = ev.getActionMasked(); 481d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller switch (action) { 482022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller case MotionEvent.ACTION_DOWN: 483b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartY = ev.getY(); 484995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = false; 485022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller break; 486022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 487d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_CANCEL: 488d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_UP: 489d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 490d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 491d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 492d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_MOVE: 493d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = ev.getPointerCount(); 494d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 495d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float x = ev.getX(i); 496d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float y = ev.getY(i); 497d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 4986f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (!mIsBouncing && 499b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler (isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) || 500d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) && 501d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId == INVALID_POINTER) { 502d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = ev.getPointerId(i); 503b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartY = ev.getY(); 504b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartChallengeBottom = getChallengeBottom(); 505d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = true; 506d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else if (isInChallengeView(x, y)) { 507d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mBlockDrag = true; 508d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 509d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 510d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 511d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 512d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 513d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mBlockDrag) { 514d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = INVALID_POINTER; 515d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = false; 516d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 517d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 518d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mDragging; 519d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 520d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 521d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void resetTouch() { 522d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.recycle(); 523d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = null; 524d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = INVALID_POINTER; 525d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = mBlockDrag = false; 526d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 527d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 528d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 529d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean onTouchEvent(MotionEvent ev) { 530d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mVelocityTracker == null) { 531d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = VelocityTracker.obtain(); 532d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 533d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.addMovement(ev); 534d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 535d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int action = ev.getActionMasked(); 536d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller switch (action) { 537995270f01175234d0615a0e1900576f142a3b4adAdam Powell case MotionEvent.ACTION_DOWN: 538995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = false; 539995270f01175234d0615a0e1900576f142a3b4adAdam Powell mGestureStartY = ev.getY(); 540995270f01175234d0615a0e1900576f142a3b4adAdam Powell break; 541995270f01175234d0615a0e1900576f142a3b4adAdam Powell 542d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_CANCEL: 543d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mDragging) { 544d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(0); 545d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 546d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 547d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 548d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 549d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_POINTER_UP: 550d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) { 551d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 552d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 553d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_UP: 554d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mDragging) { 555d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); 556d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId)); 557d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 558d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 559d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 560d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 561d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_MOVE: 5626f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (!mDragging && !mBlockDrag && !mIsBouncing) { 563d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = ev.getPointerCount(); 564d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 565d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float x = ev.getX(i); 566d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float y = ev.getY(i); 567d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 568b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) || 569d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) 570d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller && mActivePointerId == INVALID_POINTER) { 571b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartY = y; 572d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = ev.getPointerId(i); 573b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartChallengeBottom = getChallengeBottom(); 574d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = true; 575d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 576d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 577d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 578d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 579d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Not an else; this can be set above. 580d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mDragging) { 581d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // No-op if already in this state, but set it here in case we arrived 582d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // at this point from either intercept or the above. 583d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_DRAGGING); 584d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 585d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int index = ev.findPointerIndex(mActivePointerId); 586d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (index < 0) { 587d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Oops, bogus state. We lost some touch events somewhere. 588d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Just drop it with no velocity and let things settle. 589d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 590d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(0); 591d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 592d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 593b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final float y = ev.getY(index); 594b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final float pos = Math.min(y - mGestureStartY, 59567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell getLayoutBottom() - mChallengeBottomBound); 596b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 597b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler moveChallengeTo(mGestureStartChallengeBottom + (int) pos); 598d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 599d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 600d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 601d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 602d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 603d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 604b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 605b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * We only want to add additional vertical space to the drag handle when the panel is fully 606b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * closed. 607b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 608b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private int getDragHandleHeadroom() { 609b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler return isChallengeShowing() ? 0 : mDragHandleHeadroom; 610b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler } 611b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 612d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean isInChallengeView(float x, float y) { 613d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return false; 614d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 615d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return x >= mChallengeView.getLeft() && y >= mChallengeView.getTop() && 616d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller x < mChallengeView.getRight() && y < mChallengeView.getBottom(); 617d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 618d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 619d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean isInDragHandle(float x, float y) { 620d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return false; 621d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 6220b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell return x >= mDragHandleEdgeSlop && 623b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler y >= mChallengeView.getTop() - getDragHandleHeadroom() && 6240b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell x < getWidth() - mDragHandleEdgeSlop && 625d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller y < mChallengeView.getTop() + mDragHandleSize; 626d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 627d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 628b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private boolean crossedDragHandle(float x, float y, float initialY) { 629022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller final int challengeTop = mChallengeView.getTop(); 6301bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler return x >= 0 && 6311bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler x < getWidth() && 632b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler initialY < (challengeTop - getDragHandleHeadroom()) && 633022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller y > challengeTop + mDragHandleSize; 634022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller } 635022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 636d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 637d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected void onMeasure(int widthSpec, int heightSpec) { 638d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY || 639d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) { 640d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller throw new IllegalArgumentException( 641d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller "SlidingChallengeLayout must be measured with an exact size"); 642d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 643d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 644d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int width = MeasureSpec.getSize(widthSpec); 645d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int height = MeasureSpec.getSize(heightSpec); 646d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setMeasuredDimension(width, height); 647d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 648d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Find one and only one challenge view. 649d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View oldChallengeView = mChallengeView; 650d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView = null; 651d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = getChildCount(); 652d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 653d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View child = getChildAt(i); 654d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 655d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 656eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { 657d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != null) { 658d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller throw new IllegalStateException( 659d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller "There may only be one child with layout_isChallenge=\"true\""); 660d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 661d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView = child; 662d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != oldChallengeView) { 663d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE); 664d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 6656f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell // We're going to play silly games with the frame's background drawable later. 6666f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameDrawable = mChallengeView.getBackground(); 667eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) { 668eee209313d564be37b8fc068f785b3844cd6597eAdam Powell setScrimView(child); 669d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 670d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 671d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (child.getVisibility() == GONE) continue; 672d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 673d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller measureChildWithMargins(child, widthSpec, 0, heightSpec, 0); 674d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 675d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 676d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 677d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 678d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected void onLayout(boolean changed, int l, int t, int r, int b) { 679d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingLeft = getPaddingLeft(); 680d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingTop = getPaddingTop(); 681d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingRight = getPaddingRight(); 682d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingBottom = getPaddingBottom(); 683d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int width = r - l; 684d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int height = b - t; 685d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 686d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = getChildCount(); 687d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 688d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View child = getChildAt(i); 689d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 690d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (child.getVisibility() == GONE) continue; 691d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 692d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 693d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 694eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { 695d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Challenge views pin to the bottom, offset by a portion of their height, 696d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // and center horizontally. 697d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int center = (paddingLeft + width - paddingRight) / 2; 698d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childWidth = child.getMeasuredWidth(); 699d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childHeight = child.getMeasuredHeight(); 700d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int left = center - childWidth / 2; 701d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int layoutBottom = height - paddingBottom - lp.bottomMargin; 702d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We use the top of the challenge view to position the handle, so 703d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // we never want less than the handle size showing at the bottom. 70467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound) 705d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * (1 - mChallengeOffset)); 70667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell child.setAlpha(mChallengeOffset / 2 + 0.5f); 707d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.layout(left, bottom - childHeight, left + childWidth, bottom); 708d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 709d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Non-challenge views lay out from the upper left, layered. 710d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.layout(paddingLeft + lp.leftMargin, 711d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingTop + lp.topMargin, 712d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingLeft + child.getMeasuredWidth(), 713d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingTop + child.getMeasuredHeight()); 714d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 715d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 716d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 717d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (!mHasLayout) { 718d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We want to trigger the initial listener updates outside of layout pass, 719d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // in case the listeners trigger requestLayout(). 720d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller post(new Runnable() { 721d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 722d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void run() { 723d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller sendInitialListenerUpdates(); 724d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 725d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }); 72667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell if (mFrameDrawable != null) { 72767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mFrameDrawable.setAlpha(0); 72867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell } 7296f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHasLayout = true; 730d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 731d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 732d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 733d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void computeScroll() { 734d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.computeScroll(); 735d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 736d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (!mScroller.isFinished()) { 737d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 738d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Can't scroll if the view is missing. 739d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller Log.e(TAG, "Challenge view missing in computeScroll"); 740d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.abortAnimation(); 741d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 742d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 743d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 744d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.computeScrollOffset(); 745d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller moveChallengeTo(mScroller.getCurrY()); 746d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 747d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mScroller.isFinished()) { 748d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller post(mEndScrollRunnable); 749d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 750d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 751d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 752d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 753d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 754d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void draw(Canvas c) { 755d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.draw(c); 7561bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 7571bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler final Paint debugPaint; 7581bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 7591bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint = new Paint(); 7601bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0x40FF00CC); 7611bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // show the isInDragHandle() rect 7621bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(mDragHandleEdgeSlop, 763b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mChallengeView.getTop() - getDragHandleHeadroom(), 7641bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler getWidth() - mDragHandleEdgeSlop, 7651bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler mChallengeView.getTop() + mDragHandleSize, 7661bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint); 7671bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 7681bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 7696f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mChallengeView != null && mHandleAlpha > 0 && mHandleDrawable != null) { 770d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int top = mChallengeView.getTop(); 7716f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int handleHeight = mHandleDrawable.getIntrinsicHeight(); 7726f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int challengeLeft = mChallengeView.getLeft(); 7736f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int challengeRight = mChallengeView.getRight(); 7746f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleDrawable.setBounds(challengeLeft, top, challengeRight, top + handleHeight); 7756f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleDrawable.setAlpha((int) (mHandleAlpha * 0xFF)); 776d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHandleDrawable.draw(c); 7776f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 7781bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 7791bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // now show the actual drag handle 7801bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setStyle(Paint.Style.STROKE); 7811bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setStrokeWidth(1); 7821bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0xFF80FF00); 7831bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(challengeLeft, top, challengeRight, top + handleHeight, debugPaint); 7841bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 7851bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 7866f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mDragIconDrawable != null) { 7876f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconWidth = mDragIconDrawable.getIntrinsicWidth(); 7886f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconHeight = mDragIconDrawable.getIntrinsicHeight(); 7896f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconLeft = (challengeLeft + challengeRight - iconWidth) / 2; 7906f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconTop = top + (handleHeight - iconHeight) / 2; 7916f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable.setBounds(iconLeft, iconTop, iconLeft + iconWidth, 7926f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell iconTop + iconHeight); 7936f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable.setAlpha((int) (mHandleAlpha * 0xFF)); 7946f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable.draw(c); 7951bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 7961bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 7971bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0xFF00FF00); 7981bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(iconLeft, iconTop, iconLeft + iconWidth, 7991bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler iconTop + iconHeight, debugPaint); 8001bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 8016f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 802d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 803d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 804d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 805d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 806d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Move the bottom edge of mChallengeView to a new position and notify the listener 807d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * if it represents a change in position. Changes made through this method will 808d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * be stable across layout passes. If this method is called before first layout of 809d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * this SlidingChallengeLayout it will have no effect. 810d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 811d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system. 812d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @return true if the challenge view was moved 813d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 814d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean moveChallengeTo(int bottom) { 815d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null || !mHasLayout) { 816d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return false; 817d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 818d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 819b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final int layoutBottom = getLayoutBottom(); 820d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int challengeHeight = mChallengeView.getHeight(); 821d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 822d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller bottom = Math.max(layoutBottom, 82367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell Math.min(bottom, layoutBottom + challengeHeight - mChallengeBottomBound)); 824d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 82567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell float offset = 1.f - (float) (bottom - layoutBottom) / 82667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell (challengeHeight - mChallengeBottomBound); 827d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeOffset = offset; 828d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (offset > 0 && !mChallengeShowing) { 829d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(true); 830d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 831d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 832d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.layout(mChallengeView.getLeft(), 833d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom); 834d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 83567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mChallengeView.setAlpha(offset / 2 + 0.5f); 8360b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 8370b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop()); 838d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 839d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller postInvalidateOnAnimation(); 840d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 841d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 842d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 843b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 844b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * The bottom edge of this SlidingChallengeLayout's coordinate system; will coincide with 845b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * the bottom edge of mChallengeView when the challenge is fully opened. 846b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 847b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private int getLayoutBottom() { 848b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final int bottomMargin = (mChallengeView == null) 849b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler ? 0 850b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler : ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin; 851b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final int layoutBottom = getHeight() - getPaddingBottom() - bottomMargin; 852b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler return layoutBottom; 853b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler } 854b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 855b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 856b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * The bottom edge of mChallengeView; essentially, where the sliding challenge 'is'. 857b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 858d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int getChallengeBottom() { 859d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return 0; 860d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 861d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mChallengeView.getBottom(); 862d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 863d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 864b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 865d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Show or hide the challenge view, animating it if necessary. 866d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param show true to show, false to hide 867d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 868d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void showChallenge(boolean show) { 869d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(show, 0); 870995270f01175234d0615a0e1900576f142a3b4adAdam Powell if (!show) { 871995270f01175234d0615a0e1900576f142a3b4adAdam Powell // Block any drags in progress so that callers can use this to disable dragging 872995270f01175234d0615a0e1900576f142a3b4adAdam Powell // for other touch interactions. 873995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = true; 874995270f01175234d0615a0e1900576f142a3b4adAdam Powell } 875d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 876d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 877d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void showChallenge(int velocity) { 878d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller boolean show = false; 879d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (Math.abs(velocity) > mMinVelocity) { 880d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller show = velocity < 0; 881d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 882d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller show = mChallengeOffset >= 0.5f; 883d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 884d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(show, velocity); 885d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 886d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 887d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void showChallenge(boolean show, int velocity) { 888d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 889d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(false); 890d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 891d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 892d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 893d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mHasLayout) { 89467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int layoutBottom = getLayoutBottom(); 895d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller animateChallengeTo(show ? layoutBottom : 89667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell layoutBottom + mChallengeView.getHeight() - mChallengeBottomBound, velocity); 897d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 898d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 899d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 90019a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller @Override 901d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 902d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return new LayoutParams(getContext(), attrs); 903d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 904d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 905d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 906d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 907d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : 908d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) : 909d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller new LayoutParams(p); 910d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 911d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 912d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 913d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 914d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return new LayoutParams(); 915d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 916d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 917d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 918d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 919d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return p instanceof LayoutParams; 920d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 921d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 922d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static class LayoutParams extends MarginLayoutParams { 923eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public int childType = CHILD_TYPE_NONE; 924eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_NONE = 0; 925eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_CHALLENGE = 2; 926eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_SCRIM = 4; 927d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 928d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams() { 929d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(MATCH_PARENT, WRAP_CONTENT); 930d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 931d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 932d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(int width, int height) { 933d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(width, height); 934d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 935d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 936d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(android.view.ViewGroup.LayoutParams source) { 937d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 938d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 939d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 940d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(MarginLayoutParams source) { 941d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 942d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 943d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 944d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(LayoutParams source) { 945d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 946d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 947eee209313d564be37b8fc068f785b3844cd6597eAdam Powell childType = source.childType; 948d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 949d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 950d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(Context c, AttributeSet attrs) { 951d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(c, attrs); 952d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 953d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final TypedArray a = c.obtainStyledAttributes(attrs, 954d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller R.styleable.SlidingChallengeLayout_Layout); 955eee209313d564be37b8fc068f785b3844cd6597eAdam Powell childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType, 956eee209313d564be37b8fc068f785b3844cd6597eAdam Powell CHILD_TYPE_NONE); 957d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller a.recycle(); 958d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 959d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 960d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller} 961