SlidingChallengeLayout.java revision c238af5112bee38b3143a65849bd41785c3744b0
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
19cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powellimport android.animation.Animator;
20cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powellimport android.animation.AnimatorListenerAdapter;
216f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.animation.ObjectAnimator;
22d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.content.Context;
23fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powellimport android.content.res.Resources;
24d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.content.res.TypedArray;
25d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.graphics.Canvas;
261bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandlerimport android.graphics.Paint;
27cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powellimport android.graphics.Rect;
28d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.graphics.drawable.Drawable;
29d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.util.AttributeSet;
306f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.util.FloatProperty;
31d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.util.Log;
3274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganovimport android.util.MathUtils;
336f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.util.Property;
34d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.MotionEvent;
35d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.VelocityTracker;
36d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.View;
37d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.ViewConfiguration;
38d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.ViewGroup;
3974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganovimport android.view.accessibility.AccessibilityManager;
40d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.animation.Interpolator;
41d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.widget.Scroller;
42d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
43d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport com.android.internal.R;
44d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
45d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller/**
46d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * This layout handles interaction with the sliding security challenge views
47d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * that overlay/resize other keyguard contents.
48d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */
4919a5267003e7dc70100a4bd4f1f449523b2ff38bJim Millerpublic class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout {
50d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private static final String TAG = "SlidingChallengeLayout";
511bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler    private static final boolean DEBUG = false;
52d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
53c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    // The drag handle is measured in dp above & below the top edge of the
54c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    // challenge view; these parameters change based on whether the challenge
55c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    // is open or closed.
56cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell    private static final int DRAG_HANDLE_CLOSED_ABOVE = 64; // dp
57cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell    private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp
58c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp
59c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp
60c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
61c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private static final int HANDLE_ANIMATE_DURATION = 200; // ms
62c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
63d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // Drawn to show the drag handle in closed state; crossfades to the challenge view
64d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // when challenge is fully visible
656f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    private Drawable mFrameDrawable;
66cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private boolean mEdgeCaptured;
67d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
68d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // Initialized during measurement from child layoutparams
6974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    private View mExpandChallengeView;
70d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private View mChallengeView;
71eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    private View mScrimView;
72cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private View mWidgetsView;
73d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
74d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // Range: 0 (fully hidden) to 1 (fully visible)
75d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private float mChallengeOffset = 1.f;
76d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean mChallengeShowing = true;
77eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    private boolean mIsBouncing = false;
78d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
79d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private final Scroller mScroller;
80d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private int mScrollState;
810b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    private OnChallengeScrolledListener mScrollListener;
820b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    private OnBouncerStateChangedListener mBouncerListener;
83d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
84d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public static final int SCROLL_STATE_IDLE = 0;
85d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public static final int SCROLL_STATE_DRAGGING = 1;
86d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public static final int SCROLL_STATE_SETTLING = 2;
87d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
88d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private static final int MAX_SETTLE_DURATION = 600; // ms
89d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
90d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // ID of the pointer in charge of a current drag
91d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private int mActivePointerId = INVALID_POINTER;
92d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private static final int INVALID_POINTER = -1;
93d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
94d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // True if the user is currently dragging the slider
95d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean mDragging;
96d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // True if the user may not drag until a new gesture begins
97d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean mBlockDrag;
98d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
99d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private VelocityTracker mVelocityTracker;
100d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private int mMinVelocity;
101d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private int mMaxVelocity;
102c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private float mGestureStartX, mGestureStartY; // where did you first touch the screen?
103b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    private int mGestureStartChallengeBottom; // where was the challenge at that time?
104c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
105c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int mDragHandleClosedBelow; // handle hitrect extension into the challenge view
106c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int mDragHandleClosedAbove; // extend the handle's hitrect this far above the line
107c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int mDragHandleOpenBelow; // handle hitrect extension into the challenge view
108c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int mDragHandleOpenAbove; // extend the handle's hitrect this far above the line
109c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
1100b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    private int mDragHandleEdgeSlop;
11167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell    private int mChallengeBottomBound; // Number of pixels from the top of the challenge view
11267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                                       // that should remain on-screen
113c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
114c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int mTouchSlop;
11574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    private int mTouchSlopSquare;
116c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
1176f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    float mHandleAlpha;
1186f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    float mFrameAlpha;
119cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    float mFrameAnimationTarget = Float.MIN_VALUE;
1206f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    private ObjectAnimator mHandleAnimation;
1216f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    private ObjectAnimator mFrameAnimation;
1226f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
123cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private final Rect mTempRect = new Rect();
124cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
125cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private boolean mHasGlowpad;
126cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
1276f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA =
1286f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            new FloatProperty<SlidingChallengeLayout>("handleAlpha") {
1296f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        @Override
1306f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        public void setValue(SlidingChallengeLayout view, float value) {
1316f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            view.mHandleAlpha = value;
1326f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            view.invalidate();
1336f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        }
1346f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
1356f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        @Override
1366f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        public Float get(SlidingChallengeLayout view) {
1376f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            return view.mHandleAlpha;
1386f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        }
1396f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    };
1406f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
1416f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    static final Property<SlidingChallengeLayout, Float> FRAME_ALPHA =
1426f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            new FloatProperty<SlidingChallengeLayout>("frameAlpha") {
1436f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        @Override
1446f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        public void setValue(SlidingChallengeLayout view, float value) {
1456f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            if (view.mFrameDrawable != null) {
1466f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell                view.mFrameAlpha = value;
1476f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell                view.mFrameDrawable.setAlpha((int) (value * 0xFF));
1486f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell                view.mFrameDrawable.invalidateSelf();
1496f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            }
1506f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        }
1516f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
1526f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        @Override
1536f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        public Float get(SlidingChallengeLayout view) {
1546f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            return view.mFrameAlpha;
1556f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        }
1566f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    };
157d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
158d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // True if at least one layout pass has happened since the view was attached.
159d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean mHasLayout;
160d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
161d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private static final Interpolator sMotionInterpolator = new Interpolator() {
162d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public float getInterpolation(float t) {
163d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            t -= 1.0f;
164d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return t * t * t * t * t + 1.0f;
165d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
166d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    };
167d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
168d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private static final Interpolator sHandleFadeInterpolator = new Interpolator() {
169d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public float getInterpolation(float t) {
170d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return t * t;
171d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
172d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    };
173d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
174d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private final Runnable mEndScrollRunnable = new Runnable () {
175d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public void run() {
176d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            completeChallengeScroll();
177d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
178d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    };
179d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
180eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    private final OnClickListener mScrimClickListener = new OnClickListener() {
181eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        @Override
182eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        public void onClick(View v) {
183eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            hideBouncer();
184eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        }
185eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    };
186eee209313d564be37b8fc068f785b3844cd6597eAdam Powell
18774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    private final OnClickListener mExpandChallengeClickListener = new OnClickListener() {
18874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        @Override
18974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        public void onClick(View v) {
19074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (!isChallengeShowing()) {
19174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                showChallenge(true);
19274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            }
19374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        }
19474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    };
19574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov
196d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    /**
197d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * Listener interface that reports changes in scroll state of the challenge area.
198d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     */
199d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public interface OnChallengeScrolledListener {
200d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        /**
201d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * The scroll state itself changed.
202d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
203d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <p>scrollState will be one of the following:</p>
204d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
205d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <ul>
206d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li>
207d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging
208d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * the challenge area.</li>
209d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating
210d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * into place.</li>
211d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * </ul>
212d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
213d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <p>Do not perform expensive operations (e.g. layout)
214d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p>
215d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
216d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * @param scrollState The new scroll state of the challenge area.
217d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         */
218d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public void onScrollStateChanged(int scrollState);
219d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
220d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        /**
221d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * The precise position of the challenge area has changed.
222d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
223d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <p>NOTE: It is NOT safe to modify layout or call any View methods that may
224d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * result in a requestLayout anywhere in your view hierarchy as a result of this call.
225d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * It may be called during drawing.</p>
226d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
227d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * @param scrollPosition New relative position of the challenge area.
228d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *                       1.f = fully visible/ready to be interacted with.
229d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *                       0.f = fully invisible/inaccessible to the user.
230d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * @param challengeTop Position of the top edge of the challenge view in px in the
231d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *                     SlidingChallengeLayout's coordinate system.
232d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         */
233d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public void onScrollPositionChanged(float scrollPosition, int challengeTop);
234d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
235d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
236d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public SlidingChallengeLayout(Context context) {
237d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        this(context, null);
238d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
239d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
240d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public SlidingChallengeLayout(Context context, AttributeSet attrs) {
241d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        this(context, attrs, 0);
242d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
243d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
244d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) {
245d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        super(context, attrs, defStyle);
246d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
247d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mScroller = new Scroller(context, sMotionInterpolator);
248d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
249d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final ViewConfiguration vc = ViewConfiguration.get(context);
250d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mMinVelocity = vc.getScaledMinimumFlingVelocity();
251d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mMaxVelocity = vc.getScaledMaximumFlingVelocity();
252d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
253fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        final Resources res = getResources();
254fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        mDragHandleEdgeSlop = res.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
2550b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell
256c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
25774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        mTouchSlopSquare = mTouchSlop * mTouchSlop;
258c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
259fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        final float density = res.getDisplayMetrics().density;
2601bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler
2611bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler        // top half of the lock icon, plus another 25% to be sure
262c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f);
263c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        mDragHandleClosedBelow = (int) (DRAG_HANDLE_CLOSED_BELOW * density + 0.5f);
264c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        mDragHandleOpenAbove = (int) (DRAG_HANDLE_OPEN_ABOVE * density + 0.5f);
265c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f);
266c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
267c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        // how much space to account for in the handle when closed
268fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        mChallengeBottomBound = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding);
2691bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler
270cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell        setWillNotDraw(false);
271cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell    }
272cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell
2736e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock    public void setHandleAlpha(float alpha) {
2746e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock        if (mExpandChallengeView != null) {
2756e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock            mExpandChallengeView.setAlpha(alpha);
2766f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        }
2776f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    }
2786f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
2796f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    void animateHandle(boolean visible) {
2806f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        if (mHandleAnimation != null) {
2816f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            mHandleAnimation.cancel();
28267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell            mHandleAnimation = null;
283d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
28467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        final float targetAlpha = visible ? 1.f : 0.f;
28567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        if (targetAlpha == mHandleAlpha) {
28667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell            return;
28767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        }
28867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, targetAlpha);
2896f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        mHandleAnimation.setInterpolator(sHandleFadeInterpolator);
2906f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION);
2916f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        mHandleAnimation.start();
2926f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    }
2936f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
294cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    void animateFrame(final boolean visible, final boolean full) {
2956f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        if (mFrameDrawable == null) return;
2966f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
297cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        final float targetAlpha = visible ? (full ? 1.f : 0.5f) : 0.f;
298cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (mFrameAnimation != null && targetAlpha != mFrameAnimationTarget) {
2996f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            mFrameAnimation.cancel();
300cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            mFrameAnimationTarget = Float.MIN_VALUE;
30167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        }
302cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (targetAlpha == mFrameAlpha || targetAlpha == mFrameAnimationTarget) {
30367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell            return;
304d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
305cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        mFrameAnimationTarget = targetAlpha;
30667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell
30767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        mFrameAnimation = ObjectAnimator.ofFloat(this, FRAME_ALPHA, targetAlpha);
3086f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        mFrameAnimation.setInterpolator(sHandleFadeInterpolator);
3096f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        mFrameAnimation.setDuration(HANDLE_ANIMATE_DURATION);
310cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        mFrameAnimation.addListener(new AnimatorListenerAdapter() {
311cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            @Override
312cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            public void onAnimationEnd(Animator animation) {
313cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                mFrameAnimationTarget = Float.MIN_VALUE;
314cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
315cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                if (!visible && full && mChallengeView != null) {
316cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    // Mess with padding/margin to remove insets on the bouncer frame.
317cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    mChallengeView.setPadding(0, 0, 0, 0);
318cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams();
319cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    lp.leftMargin = lp.rightMargin = getChallengeMargin(true);
320cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    mChallengeView.setLayoutParams(lp);
321cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                }
322cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                mFrameAnimation = null;
323cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            }
324cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
325cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            @Override
326cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            public void onAnimationCancel(Animator animation) {
327cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                mFrameAnimationTarget = Float.MIN_VALUE;
328cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                mFrameAnimation = null;
329cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            }
330cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        });
3316f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        mFrameAnimation.start();
332d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
333d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
334d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private void sendInitialListenerUpdates() {
3350b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        if (mScrollListener != null) {
336d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0;
3370b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop);
3380b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            mScrollListener.onScrollStateChanged(mScrollState);
339d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
340d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
341d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
342d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) {
3430b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        mScrollListener = listener;
344d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mHasLayout) {
345d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            sendInitialListenerUpdates();
346d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
347d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
348d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
3490b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) {
3500b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        mBouncerListener = listener;
3510b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    }
3520b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell
353d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
354d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void onAttachedToWindow() {
355d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        super.onAttachedToWindow();
356d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
357d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mHasLayout = false;
358d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
359d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
360d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
361d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void onDetachedFromWindow() {
362d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        super.onDetachedFromWindow();
363d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
364d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        removeCallbacks(mEndScrollRunnable);
365d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mHasLayout = false;
366d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
367d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
3680b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    @Override
3690b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    public void requestChildFocus(View child, View focused) {
3700b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        if (mIsBouncing && child != mChallengeView) {
3710b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            // Clear out of the bouncer if the user tries to move focus outside of
3720b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            // the security challenge view.
3730b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            hideBouncer();
3740b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        }
3750b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        super.requestChildFocus(child, focused);
3760b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    }
3770b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell
378d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // We want the duration of the page snap animation to be influenced by the distance that
379d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // the screen has to travel, however, we don't want this duration to be effected in a
380d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
381d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // of travel has on the overall snap duration.
382d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    float distanceInfluenceForSnapDuration(float f) {
383d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        f -= 0.5f; // center the values about 0.
384d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        f *= 0.3f * Math.PI / 2.0f;
385d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return (float) Math.sin(f);
386d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
387d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
388d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    void setScrollState(int state) {
389d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mScrollState != state) {
390d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            mScrollState = state;
391d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
3926f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing);
393cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            if (!mIsBouncing) {
394cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                animateFrame(false, false);
395cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            }
3960b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            if (mScrollListener != null) {
3970b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell                mScrollListener.onScrollStateChanged(state);
398d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            }
399d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
400d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
401d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
402d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    void completeChallengeScroll() {
403d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        setChallengeShowing(mChallengeOffset != 0);
404d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        setScrollState(SCROLL_STATE_IDLE);
405cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
406d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
407d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
408eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    void setScrimView(View scrim) {
409eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        if (mScrimView != null) {
410eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            mScrimView.setOnClickListener(null);
411eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        }
412eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        mScrimView = scrim;
413eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE);
414eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        mScrimView.setFocusable(true);
415eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        mScrimView.setOnClickListener(mScrimClickListener);
416eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    }
417eee209313d564be37b8fc068f785b3844cd6597eAdam Powell
418d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    /**
419d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * Animate the bottom edge of the challenge view to the given position.
420d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     *
421d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @param y desired final position for the bottom edge of the challenge view in px
422d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @param velocity velocity in
423d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     */
424d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    void animateChallengeTo(int y, int velocity) {
425d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mChallengeView == null) {
426d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            // Nothing to do.
427d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return;
428d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
42967625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        final int sy = mChallengeView.getBottom();
43067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        final int dy = y - sy;
431d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (dy == 0) {
432d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            completeChallengeScroll();
433d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return;
434d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
435d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
436d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        setScrollState(SCROLL_STATE_SETTLING);
437d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
438d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int childHeight = mChallengeView.getHeight();
439d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int halfHeight = childHeight / 2;
440d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight);
441d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final float distance = halfHeight + halfHeight *
442d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                distanceInfluenceForSnapDuration(distanceRatio);
443d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
444d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        int duration = 0;
445d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        velocity = Math.abs(velocity);
446d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (velocity > 0) {
447d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
448d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        } else {
449d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final float childDelta = (float) Math.abs(dy) / childHeight;
450d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            duration = (int) ((childDelta + 1) * 100);
451d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
452d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        duration = Math.min(duration, MAX_SETTLE_DURATION);
453d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
454d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mScroller.startScroll(0, sy, 0, dy, duration);
455d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        postInvalidateOnAnimation();
456d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
457d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
458d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private void setChallengeShowing(boolean showChallenge) {
45974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        if (mChallengeShowing == showChallenge) {
46074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            return;
46174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        }
46267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        mChallengeShowing = showChallenge;
46374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        if (mChallengeShowing) {
46474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            mExpandChallengeView.setVisibility(View.INVISIBLE);
46574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            mChallengeView.setVisibility(View.VISIBLE);
46674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
46774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mChallengeView.requestAccessibilityFocus();
46874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mChallengeView.announceForAccessibility(mContext.getString(
46974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                        R.string.keyguard_accessibility_unlock_area_expanded));
47074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            }
47174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        } else {
47274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            mExpandChallengeView.setVisibility(View.VISIBLE);
47374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            mChallengeView.setVisibility(View.INVISIBLE);
47474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
47574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mExpandChallengeView.requestAccessibilityFocus();
47674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mChallengeView.announceForAccessibility(mContext.getString(
47774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                        R.string.keyguard_accessibility_unlock_area_collapsed));
47874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            }
47974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        }
480d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
481d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
482d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    /**
483d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @return true if the challenge is at all visible.
484d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     */
485d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public boolean isChallengeShowing() {
486d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return mChallengeShowing;
487d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
488d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
489d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
49019a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller    public boolean isChallengeOverlapping() {
49119a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller        return mChallengeShowing;
49219a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller    }
49319a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller
49419a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller    @Override
495eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    public boolean isBouncing() {
496eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        return mIsBouncing;
497eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    }
498eee209313d564be37b8fc068f785b3844cd6597eAdam Powell
499eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    @Override
500eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    public void showBouncer() {
501eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        if (mIsBouncing) return;
502eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        showChallenge(true);
503eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        mIsBouncing = true;
504eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        if (mScrimView != null) {
5056f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            mScrimView.setVisibility(VISIBLE);
506eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        }
507cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
508cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        // Mess with padding/margin to inset the bouncer frame.
509cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        // We have more space available to us otherwise.
510cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (mChallengeView != null) {
511cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            if (mFrameDrawable == null || !mFrameDrawable.getPadding(mTempRect)) {
512cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                mTempRect.set(0, 0, 0, 0);
513cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            }
514cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            mChallengeView.setPadding(mTempRect.left, mTempRect.top, mTempRect.right,
515cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    mTempRect.bottom);
516cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams();
517cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            lp.leftMargin = lp.rightMargin = getChallengeMargin(false);
518cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            mChallengeView.setLayoutParams(lp);
519cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
520cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
5216f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        animateFrame(true, true);
522cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
5230b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        if (mBouncerListener != null) {
5240b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            mBouncerListener.onBouncerStateChanged(true);
5250b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        }
526eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    }
527eee209313d564be37b8fc068f785b3844cd6597eAdam Powell
528eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    @Override
529eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    public void hideBouncer() {
530eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        if (!mIsBouncing) return;
531cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        showChallenge(false);
532eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        mIsBouncing = false;
533eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        if (mScrimView != null) {
534eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            mScrimView.setVisibility(GONE);
535eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        }
536cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        animateFrame(false, true);
5370b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        if (mBouncerListener != null) {
5380b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            mBouncerListener.onBouncerStateChanged(false);
5390b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        }
540eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    }
541eee209313d564be37b8fc068f785b3844cd6597eAdam Powell
542cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private int getChallengeMargin(boolean expanded) {
543cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop;
544cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    }
545cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
546fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell    private float getChallengeAlpha() {
547fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        float x = mChallengeOffset - 1;
548fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        return x * x * x + 1.f;
549fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell    }
550fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell
551eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    @Override
552d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void requestDisallowInterceptTouchEvent(boolean allowIntercept) {
553d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        // We'll intercept whoever we feel like! ...as long as it isn't a challenge view.
554d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        // If there are one or more pointers in the challenge view before we take over
555d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        // touch events, onInterceptTouchEvent will set mBlockDrag.
556d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
557d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
558d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
559d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public boolean onInterceptTouchEvent(MotionEvent ev) {
560d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mVelocityTracker == null) {
561d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            mVelocityTracker = VelocityTracker.obtain();
562d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
563d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mVelocityTracker.addMovement(ev);
564d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
565d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int action = ev.getActionMasked();
566d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        switch (action) {
567022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller            case MotionEvent.ACTION_DOWN:
568c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                mGestureStartX = ev.getX();
569b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                mGestureStartY = ev.getY();
570995270f01175234d0615a0e1900576f142a3b4adAdam Powell                mBlockDrag = false;
571022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller                break;
572022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller
573d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_CANCEL:
574d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_UP:
575d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                resetTouch();
576d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                break;
577d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
578d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_MOVE:
579d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int count = ev.getPointerCount();
580d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                for (int i = 0; i < count; i++) {
581d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    final float x = ev.getX(i);
582d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    final float y = ev.getY(i);
58374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                    if (!mIsBouncing && mActivePointerId == INVALID_POINTER
584c238af5112bee38b3143a65849bd41785c3744b0Adam Powell                                && ((isInDragHandle(x, y) && MathUtils.sq(x - mGestureStartX)
585c238af5112bee38b3143a65849bd41785c3744b0Adam Powell                                        + MathUtils.sq(y - mGestureStartY) > mTouchSlopSquare)
586c238af5112bee38b3143a65849bd41785c3744b0Adam Powell                                || crossedDragHandle(x, y, mGestureStartY)
587c238af5112bee38b3143a65849bd41785c3744b0Adam Powell                                || (isInChallengeView(x, y) &&
588c238af5112bee38b3143a65849bd41785c3744b0Adam Powell                                       mScrollState == SCROLL_STATE_SETTLING))) {
589d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        mActivePointerId = ev.getPointerId(i);
590c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                        mGestureStartX = x;
591c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                        mGestureStartY = y;
592b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                        mGestureStartChallengeBottom = getChallengeBottom();
593d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        mDragging = true;
594cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                        mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
595d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    } else if (isInChallengeView(x, y)) {
596d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        mBlockDrag = true;
597d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    }
598d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
599d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                break;
600d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
601d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
602d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mBlockDrag) {
603d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            mActivePointerId = INVALID_POINTER;
604d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            mDragging = false;
605d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
606d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
607d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return mDragging;
608d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
609d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
610d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private void resetTouch() {
611d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mVelocityTracker.recycle();
612d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mVelocityTracker = null;
613d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mActivePointerId = INVALID_POINTER;
614d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mDragging = mBlockDrag = false;
615d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
616d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
617d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
618d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public boolean onTouchEvent(MotionEvent ev) {
619d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mVelocityTracker == null) {
620d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            mVelocityTracker = VelocityTracker.obtain();
621d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
622d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mVelocityTracker.addMovement(ev);
623d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
624d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int action = ev.getActionMasked();
625d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        switch (action) {
626995270f01175234d0615a0e1900576f142a3b4adAdam Powell            case MotionEvent.ACTION_DOWN:
627995270f01175234d0615a0e1900576f142a3b4adAdam Powell                mBlockDrag = false;
628c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                mGestureStartX = ev.getX();
629995270f01175234d0615a0e1900576f142a3b4adAdam Powell                mGestureStartY = ev.getY();
630995270f01175234d0615a0e1900576f142a3b4adAdam Powell                break;
631995270f01175234d0615a0e1900576f142a3b4adAdam Powell
632d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_CANCEL:
633d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                if (mDragging) {
634d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    showChallenge(0);
635d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
636d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                resetTouch();
637d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                break;
638d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
639d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_POINTER_UP:
640d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) {
641d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    break;
642d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
643d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_UP:
64474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                if (mDragging) {
645d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
646d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId));
647d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
648d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                resetTouch();
649d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                break;
650d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
651d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_MOVE:
6526f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell                if (!mDragging && !mBlockDrag && !mIsBouncing) {
653d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    final int count = ev.getPointerCount();
654d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    for (int i = 0; i < count; i++) {
655d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        final float x = ev.getX(i);
656d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        final float y = ev.getY(i);
657d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
658b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                        if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) ||
659d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                                (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING))
660d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                                && mActivePointerId == INVALID_POINTER) {
661c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                            mGestureStartX = x;
662b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                            mGestureStartY = y;
663d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                            mActivePointerId = ev.getPointerId(i);
664b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                            mGestureStartChallengeBottom = getChallengeBottom();
665d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                            mDragging = true;
666cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                            mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
667d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                            break;
668d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        }
669d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    }
670d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
671d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // Not an else; this can be set above.
672d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                if (mDragging) {
673d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    // No-op if already in this state, but set it here in case we arrived
674d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    // at this point from either intercept or the above.
675d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    setScrollState(SCROLL_STATE_DRAGGING);
676d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
677d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    final int index = ev.findPointerIndex(mActivePointerId);
678d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    if (index < 0) {
679d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        // Oops, bogus state. We lost some touch events somewhere.
680d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        // Just drop it with no velocity and let things settle.
681d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        resetTouch();
682d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        showChallenge(0);
683d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        return true;
684d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    }
685b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                    final float y = ev.getY(index);
686b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                    final float pos = Math.min(y - mGestureStartY,
68767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                            getLayoutBottom() - mChallengeBottomBound);
688b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler
689b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                    moveChallengeTo(mGestureStartChallengeBottom + (int) pos);
690d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
691d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                break;
692d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
693d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return true;
694d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
695d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
696b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    /**
697cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     * The lifecycle of touch events is subtle and it's very easy to do something
698cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     * that will cause bugs that will be nasty to track when overriding this method.
699cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     * Normally one should always override onInterceptTouchEvent instead.
700cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     *
701cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     * To put it another way, don't try this at home.
702cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     */
703cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    @Override
704cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    public boolean dispatchTouchEvent(MotionEvent ev) {
705cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        final int action = ev.getActionMasked();
706cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        boolean handled = false;
707cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (action == MotionEvent.ACTION_DOWN) {
708cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // Defensive programming: if we didn't get the UP or CANCEL, reset anyway.
709cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            mEdgeCaptured = false;
710cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
711cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) {
712cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // Normally we would need to do a lot of extra stuff here.
713cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // We can only get away with this because we haven't padded in
714cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // the widget pager or otherwise transformed it during layout.
715cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // We also don't support things like splitting MotionEvents.
716cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
717cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // We set handled to captured even if dispatch is returning false here so that
718cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // we don't send a different view a busted or incomplete event stream.
719cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev);
720cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
721cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
722cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (!handled && !mEdgeCaptured) {
723cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            handled = super.dispatchTouchEvent(ev);
724cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
725cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
726cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
727cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            mEdgeCaptured = false;
728cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
729cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
730cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        return handled;
731cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    }
732cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
733cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private boolean isEdgeSwipeBeginEvent(MotionEvent ev) {
734cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
735cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            return false;
736cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
737cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
738cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        final float x = ev.getX();
739cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop;
740cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    }
741cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
742cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    /**
743b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     * We only want to add additional vertical space to the drag handle when the panel is fully
744b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     * closed.
745b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     */
746c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int getDragHandleSizeAbove() {
747c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        return isChallengeShowing() ? mDragHandleOpenAbove : mDragHandleClosedAbove;
748c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    }
749c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int getDragHandleSizeBelow() {
750c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        return isChallengeShowing() ? mDragHandleOpenBelow : mDragHandleClosedBelow;
751b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    }
752b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler
753d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean isInChallengeView(float x, float y) {
75474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        return isPointInView(x, y, mChallengeView);
755d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
756d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
757d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean isInDragHandle(float x, float y) {
75874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        return isPointInView(x, y, mExpandChallengeView);
75974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    }
760d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
76174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    private boolean isPointInView(float x, float y, View view) {
76274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        if (view == null) {
76374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            return false;
76474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        }
76574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        return x >= view.getLeft() && y >= view.getTop()
76674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                && x < view.getRight() && y < view.getBottom();
767d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
768d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
769b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    private boolean crossedDragHandle(float x, float y, float initialY) {
770022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller        final int challengeTop = mChallengeView.getTop();
7711bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler        return  x >= 0 &&
7721bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler                x < getWidth() &&
773c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                initialY < (challengeTop - getDragHandleSizeAbove()) &&
774c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                y > challengeTop + getDragHandleSizeBelow();
775022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller    }
776022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller
777d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
778d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    protected void onMeasure(int widthSpec, int heightSpec) {
779d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY ||
780d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) {
781d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            throw new IllegalArgumentException(
782d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    "SlidingChallengeLayout must be measured with an exact size");
783d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
784d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
785d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int width = MeasureSpec.getSize(widthSpec);
786d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int height = MeasureSpec.getSize(heightSpec);
787d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        setMeasuredDimension(width, height);
788d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
789d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        // Find one and only one challenge view.
790d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final View oldChallengeView = mChallengeView;
79174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        final View oldExpandChallengeView = mChallengeView;
792d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mChallengeView = null;
79374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        mExpandChallengeView = null;
794d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int count = getChildCount();
7958a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen
7968a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        // First iteration through the children finds special children and sets any associated
7978a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        // state.
798d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        for (int i = 0; i < count; i++) {
799d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final View child = getChildAt(i);
800d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
801eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
802d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                if (mChallengeView != null) {
803d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    throw new IllegalStateException(
804d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                            "There may only be one child with layout_isChallenge=\"true\"");
805d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
806d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                mChallengeView = child;
807d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                if (mChallengeView != oldChallengeView) {
808d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE);
809d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
8106f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell                // We're going to play silly games with the frame's background drawable later.
8116f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell                mFrameDrawable = mChallengeView.getBackground();
812cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                if (!mHasLayout) {
813cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    // Set up the margin correctly based on our content for the first run.
814cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null;
815cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    lp.leftMargin = lp.rightMargin = getChallengeMargin(true);
816cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                }
81774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) {
81874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                if (mExpandChallengeView != null) {
81974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                    throw new IllegalStateException(
82074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                            "There may only be one child with layout_childType"
82174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                            + "=\"expandChallengeHandle\"");
82274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                }
82374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mExpandChallengeView = child;
82474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                if (mExpandChallengeView != oldExpandChallengeView) {
82574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                    mExpandChallengeView.setVisibility(mChallengeShowing ? INVISIBLE : VISIBLE);
82674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                    mExpandChallengeView.setOnClickListener(mExpandChallengeClickListener);
82774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                }
828eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
829eee209313d564be37b8fc068f785b3844cd6597eAdam Powell                setScrimView(child);
830cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
831cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                mWidgetsView = child;
832d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            }
8338a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        }
8348a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen
8355be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen        // We want to measure the challenge view first, since the KeyguardWidgetPager
8365be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen        // needs to do things its measure pass that are dependent on the challenge view
8375be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen        // having been measured.
83874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        if (mChallengeView != null && mChallengeView.getVisibility() != View.GONE) {
8398a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen            measureChildWithMargins(mChallengeView, widthSpec, 0, heightSpec, 0);
8408a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        }
841d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
8428a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        // Measure the rest of the children
8438a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        for (int i = 0; i < count; i++) {
8448a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen            final View child = getChildAt(i);
84574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (child.getVisibility() == GONE) {
84674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                continue;
84774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            }
8488a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen            // Don't measure the challenge view twice!
8498a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen            if (child != mChallengeView) {
8508a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen                measureChildWithMargins(child, widthSpec, 0, heightSpec, 0);
8518a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen            }
852d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
853d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
854d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
855d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
856d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    protected void onLayout(boolean changed, int l, int t, int r, int b) {
857d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int paddingLeft = getPaddingLeft();
858d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int paddingTop = getPaddingTop();
859d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int paddingRight = getPaddingRight();
860d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int paddingBottom = getPaddingBottom();
861d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int width = r - l;
862d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int height = b - t;
863d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
864d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int count = getChildCount();
865d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        for (int i = 0; i < count; i++) {
866d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final View child = getChildAt(i);
867d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
868d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            if (child.getVisibility() == GONE) continue;
869d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
870d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
871d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
872eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
873d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // Challenge views pin to the bottom, offset by a portion of their height,
874d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // and center horizontally.
875d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int center = (paddingLeft + width - paddingRight) / 2;
876d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int childWidth = child.getMeasuredWidth();
877d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int childHeight = child.getMeasuredHeight();
878d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int left = center - childWidth / 2;
879d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int layoutBottom = height - paddingBottom - lp.bottomMargin;
880d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // We use the top of the challenge view to position the handle, so
881d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // we never want less than the handle size showing at the bottom.
88267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound)
883d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        * (1 - mChallengeOffset));
884fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell                child.setAlpha(getChallengeAlpha());
885d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                child.layout(left, bottom - childHeight, left + childWidth, bottom);
88674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) {
8870f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                final int center = (paddingLeft + width - paddingRight) / 2;
8880f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                final int left = center - child.getMeasuredWidth() / 2;
8890f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                final int right = left + child.getMeasuredWidth();
8900f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                final int bottom = height - paddingBottom - lp.bottomMargin;
8910f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                final int top = bottom - child.getMeasuredHeight();
8920f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                child.layout(left, top, right, bottom);
893d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            } else {
894d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // Non-challenge views lay out from the upper left, layered.
895d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                child.layout(paddingLeft + lp.leftMargin,
896d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        paddingTop + lp.topMargin,
897d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        paddingLeft + child.getMeasuredWidth(),
898d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        paddingTop + child.getMeasuredHeight());
899d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            }
900d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
901d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
902d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (!mHasLayout) {
90367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell            if (mFrameDrawable != null) {
90467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                mFrameDrawable.setAlpha(0);
90567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell            }
9066f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            mHasLayout = true;
907d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
908d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
909d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
910d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
911d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void draw(Canvas c) {
912d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        super.draw(c);
9131bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler        if (DEBUG) {
91474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            final Paint debugPaint = new Paint();
9151bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler            debugPaint.setColor(0x40FF00CC);
9161bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler            // show the isInDragHandle() rect
9171bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler            c.drawRect(mDragHandleEdgeSlop,
918c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                    mChallengeView.getTop() - getDragHandleSizeAbove(),
9191bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler                    getWidth() - mDragHandleEdgeSlop,
920c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                    mChallengeView.getTop() + getDragHandleSizeBelow(),
9211bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler                    debugPaint);
9221bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler        }
92374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    }
9241bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler
92574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    public void computeScroll() {
92674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        super.computeScroll();
9276f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
92874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        if (!mScroller.isFinished()) {
92974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (mChallengeView == null) {
93074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                // Can't scroll if the view is missing.
93174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                Log.e(TAG, "Challenge view missing in computeScroll");
93274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mScroller.abortAnimation();
93374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                return;
9341bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler            }
9351bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler
93674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            mScroller.computeScrollOffset();
93774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            moveChallengeTo(mScroller.getCurrY());
93874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov
93974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (mScroller.isFinished()) {
94074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                post(mEndScrollRunnable);
9416f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            }
942d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
943d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
944d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
945e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen    public int getMaxChallengeTop() {
946e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen        if (mChallengeView == null) return 0;
947e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen
948e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen        final int layoutBottom = getLayoutBottom();
9498a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        final int challengeHeight = mChallengeView.getMeasuredHeight();
950e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen        return layoutBottom - challengeHeight;
951e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen    }
952e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen
953d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    /**
954d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * Move the bottom edge of mChallengeView to a new position and notify the listener
955d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * if it represents a change in position. Changes made through this method will
956d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * be stable across layout passes. If this method is called before first layout of
957d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * this SlidingChallengeLayout it will have no effect.
958d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     *
959d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system.
960d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @return true if the challenge view was moved
961d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     */
962d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean moveChallengeTo(int bottom) {
963d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mChallengeView == null || !mHasLayout) {
964d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return false;
965d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
966d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
967b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler        final int layoutBottom = getLayoutBottom();
968d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int challengeHeight = mChallengeView.getHeight();
969d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
970d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        bottom = Math.max(layoutBottom,
97167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                Math.min(bottom, layoutBottom + challengeHeight - mChallengeBottomBound));
972d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
97367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        float offset = 1.f - (float) (bottom - layoutBottom) /
97467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                (challengeHeight - mChallengeBottomBound);
975d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mChallengeOffset = offset;
976d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (offset > 0 && !mChallengeShowing) {
977d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            setChallengeShowing(true);
978d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
979d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
980d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mChallengeView.layout(mChallengeView.getLeft(),
981d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom);
982d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
983fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        mChallengeView.setAlpha(getChallengeAlpha());
9840b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        if (mScrollListener != null) {
9850b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop());
986d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
987d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        postInvalidateOnAnimation();
988d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return true;
989d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
990d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
991b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    /**
992b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     * The bottom edge of this SlidingChallengeLayout's coordinate system; will coincide with
993b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     * the bottom edge of mChallengeView when the challenge is fully opened.
994b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     */
995b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    private int getLayoutBottom() {
996b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler        final int bottomMargin = (mChallengeView == null)
997b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                ? 0
998b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                : ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin;
9998a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        final int layoutBottom = getMeasuredHeight() - getPaddingBottom() - bottomMargin;
1000b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler        return layoutBottom;
1001b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    }
1002b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler
1003b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    /**
1004b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     * The bottom edge of mChallengeView; essentially, where the sliding challenge 'is'.
1005b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     */
1006d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private int getChallengeBottom() {
1007d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mChallengeView == null) return 0;
1008d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1009d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return mChallengeView.getBottom();
1010d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1011d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1012b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    /**
1013d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * Show or hide the challenge view, animating it if necessary.
1014d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @param show true to show, false to hide
1015d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     */
1016d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void showChallenge(boolean show) {
1017d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        showChallenge(show, 0);
1018995270f01175234d0615a0e1900576f142a3b4adAdam Powell        if (!show) {
1019995270f01175234d0615a0e1900576f142a3b4adAdam Powell            // Block any drags in progress so that callers can use this to disable dragging
1020995270f01175234d0615a0e1900576f142a3b4adAdam Powell            // for other touch interactions.
1021995270f01175234d0615a0e1900576f142a3b4adAdam Powell            mBlockDrag = true;
1022995270f01175234d0615a0e1900576f142a3b4adAdam Powell        }
1023d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1024d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1025d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private void showChallenge(int velocity) {
1026d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        boolean show = false;
1027d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (Math.abs(velocity) > mMinVelocity) {
1028d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            show = velocity < 0;
1029d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        } else {
1030d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            show = mChallengeOffset >= 0.5f;
1031d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1032d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        showChallenge(show, velocity);
1033d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1034d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1035d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private void showChallenge(boolean show, int velocity) {
1036d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mChallengeView == null) {
1037d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            setChallengeShowing(false);
1038d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return;
1039d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1040d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1041d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mHasLayout) {
104267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell            final int layoutBottom = getLayoutBottom();
1043d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            animateChallengeTo(show ? layoutBottom :
104467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                    layoutBottom + mChallengeView.getHeight() - mChallengeBottomBound, velocity);
1045d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1046d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1047d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
104819a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller    @Override
1049d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
1050d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return new LayoutParams(getContext(), attrs);
1051d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1052d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1053d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
1054d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
1055d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) :
1056d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) :
1057d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                new LayoutParams(p);
1058d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1059d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1060d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
1061d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
1062d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return new LayoutParams();
1063d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1064d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1065d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
1066d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1067d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return p instanceof LayoutParams;
1068d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1069d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1070d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public static class LayoutParams extends MarginLayoutParams {
1071eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        public int childType = CHILD_TYPE_NONE;
1072eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        public static final int CHILD_TYPE_NONE = 0;
1073eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        public static final int CHILD_TYPE_CHALLENGE = 2;
1074eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        public static final int CHILD_TYPE_SCRIM = 4;
1075cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        public static final int CHILD_TYPE_WIDGETS = 5;
107674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        public static final int CHILD_TYPE_EXPAND_CHALLENGE_HANDLE = 6;
1077d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1078d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams() {
1079d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            this(MATCH_PARENT, WRAP_CONTENT);
1080d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1081d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1082d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams(int width, int height) {
1083d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            super(width, height);
1084d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1085d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1086d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
1087d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            super(source);
1088d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1089d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1090d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams(MarginLayoutParams source) {
1091d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            super(source);
1092d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1093d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1094d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams(LayoutParams source) {
1095d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            super(source);
1096d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1097eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            childType = source.childType;
1098d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1099d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1100d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams(Context c, AttributeSet attrs) {
1101d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            super(c, attrs);
1102d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1103d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final TypedArray a = c.obtainStyledAttributes(attrs,
1104d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    R.styleable.SlidingChallengeLayout_Layout);
1105eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType,
1106eee209313d564be37b8fc068f785b3844cd6597eAdam Powell                    CHILD_TYPE_NONE);
1107d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            a.recycle();
1108d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1109d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1110d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller}
1111