SlidingChallengeLayout.java revision 1bfcc82184824c8dc648a0948303f4b3611ac087
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; 85d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private float mLastTouchY; 861bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler private int mDragHandleSize; // handle hitrect extension into the challenge view 871bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler private int mDragHandleHeadroom; // extend the handle's hitrect this far above the line 880b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private int mDragHandleEdgeSlop; 896f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell float mHandleAlpha; 906f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell float mFrameAlpha; 916f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private ObjectAnimator mHandleAnimation; 926f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private ObjectAnimator mFrameAnimation; 936f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 946f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA = 956f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell new FloatProperty<SlidingChallengeLayout>("handleAlpha") { 966f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 976f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setValue(SlidingChallengeLayout view, float value) { 986f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mHandleAlpha = value; 996f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.invalidate(); 1006f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1016f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1026f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1036f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public Float get(SlidingChallengeLayout view) { 1046f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell return view.mHandleAlpha; 1056f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1066f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell }; 1076f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1086f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell static final Property<SlidingChallengeLayout, Float> FRAME_ALPHA = 1096f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell new FloatProperty<SlidingChallengeLayout>("frameAlpha") { 1106f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1116f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setValue(SlidingChallengeLayout view, float value) { 1126f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (view.mFrameDrawable != null) { 1136f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameAlpha = value; 1146f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameDrawable.setAlpha((int) (value * 0xFF)); 1156f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameDrawable.invalidateSelf(); 1166f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1176f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1186f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1196f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1206f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public Float get(SlidingChallengeLayout view) { 1216f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell return view.mFrameAlpha; 1226f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1236f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell }; 124d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 125d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final int DRAG_HANDLE_DEFAULT_SIZE = 32; // dp 1266f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private static final int HANDLE_ANIMATE_DURATION = 200; // ms 127d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 128d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if at least one layout pass has happened since the view was attached. 129d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mHasLayout; 130d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 131d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final Interpolator sMotionInterpolator = new Interpolator() { 132d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public float getInterpolation(float t) { 133d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller t -= 1.0f; 134d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return t * t * t * t * t + 1.0f; 135d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 136d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 137d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 138d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final Interpolator sHandleFadeInterpolator = new Interpolator() { 139d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public float getInterpolation(float t) { 140d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return t * t; 141d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 142d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 143d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 144d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private final Runnable mEndScrollRunnable = new Runnable () { 145d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void run() { 146d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller completeChallengeScroll(); 147d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 148d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 149d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 150eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private final OnClickListener mScrimClickListener = new OnClickListener() { 151eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 152eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void onClick(View v) { 153eee209313d564be37b8fc068f785b3844cd6597eAdam Powell hideBouncer(); 154eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 155eee209313d564be37b8fc068f785b3844cd6597eAdam Powell }; 156eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 157d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 158d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Listener interface that reports changes in scroll state of the challenge area. 159d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 160d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public interface OnChallengeScrolledListener { 161d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 162d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * The scroll state itself changed. 163d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 164d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>scrollState will be one of the following:</p> 165d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 166d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <ul> 167d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li> 168d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging 169d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * the challenge area.</li> 170d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating 171d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * into place.</li> 172d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * </ul> 173d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 174d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>Do not perform expensive operations (e.g. layout) 175d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p> 176d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 177d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param scrollState The new scroll state of the challenge area. 178d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 179d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onScrollStateChanged(int scrollState); 180d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 181d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 182d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * The precise position of the challenge area has changed. 183d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 184d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>NOTE: It is NOT safe to modify layout or call any View methods that may 185d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * result in a requestLayout anywhere in your view hierarchy as a result of this call. 186d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * It may be called during drawing.</p> 187d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 188d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param scrollPosition New relative position of the challenge area. 189d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 1.f = fully visible/ready to be interacted with. 190d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 0.f = fully invisible/inaccessible to the user. 191d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param challengeTop Position of the top edge of the challenge view in px in the 192d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * SlidingChallengeLayout's coordinate system. 193d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 194d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onScrollPositionChanged(float scrollPosition, int challengeTop); 195d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 196d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 197d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context) { 198d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(context, null); 199d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 200d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 201d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context, AttributeSet attrs) { 202d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(context, attrs, 0); 203d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 204d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 205d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) { 206d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(context, attrs, defStyle); 207d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 208d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final TypedArray a = context.obtainStyledAttributes(attrs, 209d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller R.styleable.SlidingChallengeLayout, defStyle, 0); 2106f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell setDragDrawables(a.getDrawable(R.styleable.SlidingChallengeLayout_dragHandle), 2116f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell a.getDrawable(R.styleable.SlidingChallengeLayout_dragIcon)); 212d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 213d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller a.recycle(); 214d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 215d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller = new Scroller(context, sMotionInterpolator); 216d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 217d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final ViewConfiguration vc = ViewConfiguration.get(context); 218d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mMinVelocity = vc.getScaledMinimumFlingVelocity(); 219d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mMaxVelocity = vc.getScaledMaximumFlingVelocity(); 220d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 2210b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mDragHandleEdgeSlop = getResources().getDimensionPixelSize( 2220b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell R.dimen.kg_edge_swipe_region_size); 2230b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 224d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setWillNotDraw(false); 225d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 226d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 2276f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setDragDrawables(Drawable handle, Drawable icon) { 2286f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final float density = getResources().getDisplayMetrics().density; 2296f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int defaultSize = (int) (DRAG_HANDLE_DEFAULT_SIZE * density + 0.5f); 2306f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragHandleSize = Math.max(handle != null ? handle.getIntrinsicHeight() : defaultSize, 2316f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell icon != null ? icon.getIntrinsicHeight() : defaultSize); 2321bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 2331bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // top half of the lock icon, plus another 25% to be sure 2341bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler mDragHandleHeadroom = (icon != null) ? (int)(icon.getIntrinsicHeight() * 0.75f) : 0; 2351bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 2366f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleDrawable = handle; 2376f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable = icon; 2386f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2396f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2406f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setDragIconDrawable(Drawable d) { 2416f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable = d; 2426f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2436f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2446f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void showHandle(boolean visible) { 2456f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (visible) { 2466f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mHandleAnimation != null) { 2476f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.cancel(); 2486f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation = null; 2496f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2506f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAlpha = 1.f; 2516f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell invalidate(); 2526f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } else { 2536f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateHandle(false); 2546f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2556f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2566f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2576f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell void animateHandle(boolean visible) { 2586f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mHandleAnimation != null) { 2596f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.cancel(); 260d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 2616f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, visible ? 1.f : 0.f); 2626f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.setInterpolator(sHandleFadeInterpolator); 2636f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION); 2646f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.start(); 2656f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2666f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2676f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell void animateFrame(boolean visible, boolean full) { 2686f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mFrameDrawable == null) return; 2696f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 2706f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mFrameAnimation != null) { 2716f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.cancel(); 272d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 2736f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation = ObjectAnimator.ofFloat(this, FRAME_ALPHA, 2746f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell visible ? (full ? 1.f : 0.5f) : 0.f); 2756f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.setInterpolator(sHandleFadeInterpolator); 2766f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.setDuration(HANDLE_ANIMATE_DURATION); 2776f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.start(); 278d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 279d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 280d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void sendInitialListenerUpdates() { 2810b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 282d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0; 2830b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop); 2840b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollStateChanged(mScrollState); 285d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 286d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 287d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 288d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) { 2890b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener = listener; 290d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mHasLayout) { 291d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller sendInitialListenerUpdates(); 292d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 293d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 294d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 2950b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) { 2960b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener = listener; 2970b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 2980b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 299d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 300d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onAttachedToWindow() { 301d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.onAttachedToWindow(); 302d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 303d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHasLayout = false; 304d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 305d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 306d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 307d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onDetachedFromWindow() { 308d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.onDetachedFromWindow(); 309d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 310d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller removeCallbacks(mEndScrollRunnable); 311d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHasLayout = false; 312d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 313d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3140b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell @Override 3150b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell public void requestChildFocus(View child, View focused) { 3160b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mIsBouncing && child != mChallengeView) { 3170b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell // Clear out of the bouncer if the user tries to move focus outside of 3180b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell // the security challenge view. 3190b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell hideBouncer(); 3200b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3210b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell super.requestChildFocus(child, focused); 3220b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3230b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 324d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We want the duration of the page snap animation to be influenced by the distance that 325d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // the screen has to travel, however, we don't want this duration to be effected in a 326d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // purely linear fashion. Instead, we use this method to moderate the effect that the distance 327d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // of travel has on the overall snap duration. 328d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller float distanceInfluenceForSnapDuration(float f) { 329d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller f -= 0.5f; // center the values about 0. 330d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller f *= 0.3f * Math.PI / 2.0f; 331d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return (float) Math.sin(f); 332d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 333d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 334d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void setScrollState(int state) { 335d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mScrollState != state) { 336d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScrollState = state; 337d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3386f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing); 3396f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateFrame(state == SCROLL_STATE_DRAGGING, false); 3400b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 3410b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollStateChanged(state); 342d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 343d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 344d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 345d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 346d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void completeChallengeScroll() { 347d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(mChallengeOffset != 0); 348d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_IDLE); 349d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 350d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 351eee209313d564be37b8fc068f785b3844cd6597eAdam Powell void setScrimView(View scrim) { 352eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 353eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setOnClickListener(null); 354eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 355eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView = scrim; 356eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE); 357eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setFocusable(true); 358eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setOnClickListener(mScrimClickListener); 359eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 360eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 361d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 362d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Animate the bottom edge of the challenge view to the given position. 363d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 364d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param y desired final position for the bottom edge of the challenge view in px 365d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param velocity velocity in 366d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 367d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void animateChallengeTo(int y, int velocity) { 368d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 369d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Nothing to do. 370d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 371d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 372d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int sy = mChallengeView.getBottom(); 373d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int dy = y - sy; 374d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (dy == 0) { 375d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller completeChallengeScroll(); 376d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 377d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 378d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 379d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_SETTLING); 380d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 381d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childHeight = mChallengeView.getHeight(); 382d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int halfHeight = childHeight / 2; 383d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight); 384d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float distance = halfHeight + halfHeight * 385d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller distanceInfluenceForSnapDuration(distanceRatio); 386d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 387d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int duration = 0; 388d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller velocity = Math.abs(velocity); 389d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (velocity > 0) { 390d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 391d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 392d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float childDelta = (float) Math.abs(dy) / childHeight; 393d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = (int) ((childDelta + 1) * 100); 394d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 395d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = Math.min(duration, MAX_SETTLE_DURATION); 396d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 397d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.startScroll(0, sy, 0, dy, duration); 398d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller postInvalidateOnAnimation(); 399d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 400d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 401d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void setChallengeShowing(boolean showChallenge) { 402d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeShowing != showChallenge) { 403d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeShowing = showChallenge; 404d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != null) { 405d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.setVisibility(showChallenge ? VISIBLE : INVISIBLE); 406d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 407d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 408d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 409d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 410d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 411d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @return true if the challenge is at all visible. 412d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 413d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean isChallengeShowing() { 414d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mChallengeShowing; 415d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 416d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 417d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 41819a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller public boolean isChallengeOverlapping() { 41919a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller return mChallengeShowing; 42019a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller } 42119a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller 42219a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller @Override 423eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public boolean isBouncing() { 424eee209313d564be37b8fc068f785b3844cd6597eAdam Powell return mIsBouncing; 425eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 426eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 427eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 428eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void showBouncer() { 429eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mIsBouncing) return; 430eee209313d564be37b8fc068f785b3844cd6597eAdam Powell showChallenge(true); 431eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mIsBouncing = true; 432eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 4336f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mScrimView.setVisibility(VISIBLE); 434eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 4356f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateFrame(true, true); 4360b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mBouncerListener != null) { 4370b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener.onBouncerStateChanged(true); 4380b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 439eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 440eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 441eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 442eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void hideBouncer() { 443eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (!mIsBouncing) return; 444eee209313d564be37b8fc068f785b3844cd6597eAdam Powell setChallengeShowing(false); 445eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mIsBouncing = false; 446eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 447eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setVisibility(GONE); 448eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 4496f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateFrame(false, false); 4500b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mBouncerListener != null) { 4510b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener.onBouncerStateChanged(false); 4520b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 453eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 454eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 455eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 456d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void requestDisallowInterceptTouchEvent(boolean allowIntercept) { 457d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We'll intercept whoever we feel like! ...as long as it isn't a challenge view. 458d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // If there are one or more pointers in the challenge view before we take over 459d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // touch events, onInterceptTouchEvent will set mBlockDrag. 460d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 461d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 462d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 463d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean onInterceptTouchEvent(MotionEvent ev) { 464d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mVelocityTracker == null) { 465d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = VelocityTracker.obtain(); 466d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 467d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.addMovement(ev); 468d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 469d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int action = ev.getActionMasked(); 470d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller switch (action) { 471022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller case MotionEvent.ACTION_DOWN: 472022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller mLastTouchY = ev.getY(); 473022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller break; 474022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 475d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_CANCEL: 476d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_UP: 477d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 478d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 479d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 480d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_MOVE: 481d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = ev.getPointerCount(); 482d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 483d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float x = ev.getX(i); 484d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float y = ev.getY(i); 485d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 4866f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (!mIsBouncing && 4876f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell (isInDragHandle(x, y) || crossedDragHandle(x, y, mLastTouchY) || 488d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) && 489d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId == INVALID_POINTER) { 490d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = ev.getPointerId(i); 491d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mLastTouchY = y; 492d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = true; 493d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else if (isInChallengeView(x, y)) { 494d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mBlockDrag = true; 495d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 496d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 497d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 498d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 499d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 500d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mBlockDrag) { 501d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = INVALID_POINTER; 502d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = false; 503d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 504d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 505d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mDragging; 506d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 507d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 508d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void resetTouch() { 509d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.recycle(); 510d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = null; 511d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = INVALID_POINTER; 512d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = mBlockDrag = false; 513d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 514d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 515d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 516d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean onTouchEvent(MotionEvent ev) { 517d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mVelocityTracker == null) { 518d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = VelocityTracker.obtain(); 519d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 520d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.addMovement(ev); 521d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 522d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int action = ev.getActionMasked(); 523d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller switch (action) { 524d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_CANCEL: 525d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mDragging) { 526d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(0); 527d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 528d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 529d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 530d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 531d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_POINTER_UP: 532d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) { 533d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 534d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 535d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_UP: 536d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mDragging) { 537d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); 538d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId)); 539d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 540d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 541d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 542d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 543d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_MOVE: 5446f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (!mDragging && !mBlockDrag && !mIsBouncing) { 545d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = ev.getPointerCount(); 546d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 547d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float x = ev.getX(i); 548d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float y = ev.getY(i); 549d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 550022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mLastTouchY) || 551d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) 552d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller && mActivePointerId == INVALID_POINTER) { 553d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = ev.getPointerId(i); 554d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = true; 555d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 556d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 557d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 558d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 559d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Not an else; this can be set above. 560d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mDragging) { 561d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // No-op if already in this state, but set it here in case we arrived 562d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // at this point from either intercept or the above. 563d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_DRAGGING); 564d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 565d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int index = ev.findPointerIndex(mActivePointerId); 566d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (index < 0) { 567d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Oops, bogus state. We lost some touch events somewhere. 568d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Just drop it with no velocity and let things settle. 569d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 570d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(0); 571d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 572d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 5731bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler final float y = Math.max(ev.getY(index), 5741bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler getChallengeOpenedTop() - mDragHandleHeadroom); 575d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float delta = y - mLastTouchY; 576d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int idelta = (int) delta; 577d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Don't lose the rounded component 578d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mLastTouchY = y + delta - idelta; 579d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 580d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller moveChallengeBy(idelta); 581d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 582d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 583d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 584d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 585d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 586d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 587d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean isInChallengeView(float x, float y) { 588d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return false; 589d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 590d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return x >= mChallengeView.getLeft() && y >= mChallengeView.getTop() && 591d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller x < mChallengeView.getRight() && y < mChallengeView.getBottom(); 592d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 593d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 594d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean isInDragHandle(float x, float y) { 595d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return false; 596d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 5970b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell return x >= mDragHandleEdgeSlop && 5981bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler y >= mChallengeView.getTop() - mDragHandleHeadroom && 5990b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell x < getWidth() - mDragHandleEdgeSlop && 600d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller y < mChallengeView.getTop() + mDragHandleSize; 601d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 602d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 603022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller private boolean crossedDragHandle(float x, float y, float lastY) { 604022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller final int challengeTop = mChallengeView.getTop(); 6051bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler return x >= 0 && 6061bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler x < getWidth() && 6071bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler lastY < (challengeTop - mDragHandleHeadroom) && 608022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller y > challengeTop + mDragHandleSize; 609022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller } 610022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 611d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 612d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected void onMeasure(int widthSpec, int heightSpec) { 613d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY || 614d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) { 615d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller throw new IllegalArgumentException( 616d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller "SlidingChallengeLayout must be measured with an exact size"); 617d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 618d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 619d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int width = MeasureSpec.getSize(widthSpec); 620d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int height = MeasureSpec.getSize(heightSpec); 621d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setMeasuredDimension(width, height); 622d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 623d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Find one and only one challenge view. 624d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View oldChallengeView = mChallengeView; 625d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView = null; 626d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = getChildCount(); 627d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 628d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View child = getChildAt(i); 629d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 630d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 631eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { 632d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != null) { 633d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller throw new IllegalStateException( 634d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller "There may only be one child with layout_isChallenge=\"true\""); 635d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 636d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView = child; 637d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != oldChallengeView) { 638d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE); 639d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 6406f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell // We're going to play silly games with the frame's background drawable later. 6416f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameDrawable = mChallengeView.getBackground(); 6426f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameDrawable.setAlpha(0); 643eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) { 644eee209313d564be37b8fc068f785b3844cd6597eAdam Powell setScrimView(child); 645d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 646d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 647d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (child.getVisibility() == GONE) continue; 648d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 649d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller measureChildWithMargins(child, widthSpec, 0, heightSpec, 0); 650d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 651d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 652d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 653d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 654d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected void onLayout(boolean changed, int l, int t, int r, int b) { 655d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingLeft = getPaddingLeft(); 656d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingTop = getPaddingTop(); 657d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingRight = getPaddingRight(); 658d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingBottom = getPaddingBottom(); 659d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int width = r - l; 660d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int height = b - t; 661d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 662d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = getChildCount(); 663d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 664d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View child = getChildAt(i); 665d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 666d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (child.getVisibility() == GONE) continue; 667d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 668d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 669d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 670eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { 671d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Challenge views pin to the bottom, offset by a portion of their height, 672d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // and center horizontally. 673d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int center = (paddingLeft + width - paddingRight) / 2; 674d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childWidth = child.getMeasuredWidth(); 675d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childHeight = child.getMeasuredHeight(); 676d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int left = center - childWidth / 2; 677d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int layoutBottom = height - paddingBottom - lp.bottomMargin; 678d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We use the top of the challenge view to position the handle, so 679d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // we never want less than the handle size showing at the bottom. 680d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int bottom = layoutBottom + (int) ((childHeight - mDragHandleSize) 681d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * (1 - mChallengeOffset)); 682d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller float offset = 1.f - (bottom - layoutBottom) / childHeight; 683d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.setAlpha(offset); 684d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.layout(left, bottom - childHeight, left + childWidth, bottom); 685d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 686d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Non-challenge views lay out from the upper left, layered. 687d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.layout(paddingLeft + lp.leftMargin, 688d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingTop + lp.topMargin, 689d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingLeft + child.getMeasuredWidth(), 690d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingTop + child.getMeasuredHeight()); 691d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 692d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 693d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 694d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (!mHasLayout) { 695d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We want to trigger the initial listener updates outside of layout pass, 696d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // in case the listeners trigger requestLayout(). 697d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller post(new Runnable() { 698d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 699d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void run() { 700d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller sendInitialListenerUpdates(); 701d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 702d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }); 7036f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHasLayout = true; 704d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 705d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 706d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 707d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void computeScroll() { 708d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.computeScroll(); 709d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 710d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (!mScroller.isFinished()) { 711d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 712d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Can't scroll if the view is missing. 713d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller Log.e(TAG, "Challenge view missing in computeScroll"); 714d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.abortAnimation(); 715d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 716d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 717d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 718d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.computeScrollOffset(); 719d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller moveChallengeTo(mScroller.getCurrY()); 720d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 721d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mScroller.isFinished()) { 722d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller post(mEndScrollRunnable); 723d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 724d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 725d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 726d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 727d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 728d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void draw(Canvas c) { 729d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.draw(c); 7301bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 7311bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler final Paint debugPaint; 7321bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 7331bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint = new Paint(); 7341bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0x40FF00CC); 7351bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // show the isInDragHandle() rect 7361bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(mDragHandleEdgeSlop, 7371bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler mChallengeView.getTop() - mDragHandleHeadroom, 7381bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler getWidth() - mDragHandleEdgeSlop, 7391bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler mChallengeView.getTop() + mDragHandleSize, 7401bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint); 7411bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 7421bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 7436f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mChallengeView != null && mHandleAlpha > 0 && mHandleDrawable != null) { 744d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int top = mChallengeView.getTop(); 7456f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int handleHeight = mHandleDrawable.getIntrinsicHeight(); 7466f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int challengeLeft = mChallengeView.getLeft(); 7476f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int challengeRight = mChallengeView.getRight(); 7486f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleDrawable.setBounds(challengeLeft, top, challengeRight, top + handleHeight); 7496f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleDrawable.setAlpha((int) (mHandleAlpha * 0xFF)); 750d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHandleDrawable.draw(c); 7516f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 7521bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 7531bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // now show the actual drag handle 7541bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setStyle(Paint.Style.STROKE); 7551bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setStrokeWidth(1); 7561bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0xFF80FF00); 7571bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(challengeLeft, top, challengeRight, top + handleHeight, debugPaint); 7581bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 7591bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 7606f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mDragIconDrawable != null) { 7616f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconWidth = mDragIconDrawable.getIntrinsicWidth(); 7626f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconHeight = mDragIconDrawable.getIntrinsicHeight(); 7636f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconLeft = (challengeLeft + challengeRight - iconWidth) / 2; 7646f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell final int iconTop = top + (handleHeight - iconHeight) / 2; 7656f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable.setBounds(iconLeft, iconTop, iconLeft + iconWidth, 7666f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell iconTop + iconHeight); 7676f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable.setAlpha((int) (mHandleAlpha * 0xFF)); 7686f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mDragIconDrawable.draw(c); 7691bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 7701bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 7711bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0xFF00FF00); 7721bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(iconLeft, iconTop, iconLeft + iconWidth, 7731bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler iconTop + iconHeight, debugPaint); 7741bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 7756f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 776d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 777d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 778d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 779d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 780d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Move the bottom edge of mChallengeView to a new position and notify the listener 781d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * if it represents a change in position. Changes made through this method will 782d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * be stable across layout passes. If this method is called before first layout of 783d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * this SlidingChallengeLayout it will have no effect. 784d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 785d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system. 786d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @return true if the challenge view was moved 787d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 788d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean moveChallengeTo(int bottom) { 789d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null || !mHasLayout) { 790d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return false; 791d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 792d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 793d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int bottomMargin = ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin; 794d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int layoutBottom = getHeight() - getPaddingBottom() - bottomMargin; 795d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int challengeHeight = mChallengeView.getHeight(); 796d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 797d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller bottom = Math.max(layoutBottom, 798d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller Math.min(bottom, layoutBottom + challengeHeight - mDragHandleSize)); 799d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 800d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller float offset = 1.f - (float) (bottom - layoutBottom) / (challengeHeight - mDragHandleSize); 801d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeOffset = offset; 802d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (offset > 0 && !mChallengeShowing) { 803d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(true); 804d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 805d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 806d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.layout(mChallengeView.getLeft(), 807d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom); 808d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 809d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.setAlpha(offset); 8100b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 8110b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop()); 812d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 813d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller postInvalidateOnAnimation(); 814d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 815d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 816d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 817d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int getChallengeBottom() { 818d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return 0; 819d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 820d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mChallengeView.getBottom(); 821d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 822d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 823022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller private int getChallengeOpenedTop() { 824022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller final int paddedBottom = getHeight() - getPaddingBottom(); 825022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller if (mChallengeView == null) return paddedBottom; 826022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 827022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller final int bottomMargin = ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin; 828022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller final int layoutBottom = paddedBottom - bottomMargin; 829022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 830022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller return layoutBottom - mChallengeView.getHeight(); 831022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller } 832022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 833d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void moveChallengeBy(int delta) { 834d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller moveChallengeTo(getChallengeBottom() + delta); 835d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 836d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 837d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 838d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Show or hide the challenge view, animating it if necessary. 839d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param show true to show, false to hide 840d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 841d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void showChallenge(boolean show) { 842d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(show, 0); 843d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 844d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 845d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void showChallenge(int velocity) { 846d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller boolean show = false; 847d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (Math.abs(velocity) > mMinVelocity) { 848d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller show = velocity < 0; 849d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 850d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller show = mChallengeOffset >= 0.5f; 851d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 852d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(show, velocity); 853d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 854d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 855d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void showChallenge(boolean show, int velocity) { 856d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 857d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(false); 858d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 859d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 860d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 861d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mHasLayout) { 862d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int bottomMargin = ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin; 863d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int layoutBottom = getHeight() - getPaddingBottom() - bottomMargin; 864d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller animateChallengeTo(show ? layoutBottom : 865d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller layoutBottom + mChallengeView.getHeight() - mDragHandleSize, velocity); 866d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 867d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 868d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 86919a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller @Override 870d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 871d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return new LayoutParams(getContext(), attrs); 872d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 873d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 874d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 875d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 876d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : 877d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) : 878d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller new LayoutParams(p); 879d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 880d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 881d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 882d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 883d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return new LayoutParams(); 884d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 885d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 886d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 887d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 888d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return p instanceof LayoutParams; 889d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 890d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 891d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static class LayoutParams extends MarginLayoutParams { 892eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public int childType = CHILD_TYPE_NONE; 893eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_NONE = 0; 894eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_CHALLENGE = 2; 895eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_SCRIM = 4; 896d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 897d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams() { 898d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(MATCH_PARENT, WRAP_CONTENT); 899d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 900d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 901d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(int width, int height) { 902d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(width, height); 903d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 904d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 905d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(android.view.ViewGroup.LayoutParams source) { 906d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 907d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 908d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 909d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(MarginLayoutParams source) { 910d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 911d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 912d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 913d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(LayoutParams source) { 914d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 915d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 916eee209313d564be37b8fc068f785b3844cd6597eAdam Powell childType = source.childType; 917d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 918d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 919d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(Context c, AttributeSet attrs) { 920d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(c, attrs); 921d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 922d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final TypedArray a = c.obtainStyledAttributes(attrs, 923d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller R.styleable.SlidingChallengeLayout_Layout); 924eee209313d564be37b8fc068f785b3844cd6597eAdam Powell childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType, 925eee209313d564be37b8fc068f785b3844cd6597eAdam Powell CHILD_TYPE_NONE); 926d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller a.recycle(); 927d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 928d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 929d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller} 930