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
175ecd81154fa039961f65bb4e36d18ac555b0d1d6Jim Millerpackage com.android.keyguard;
189c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell
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;
27256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlockimport android.graphics.Rect;
28d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.util.AttributeSet;
295da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powellimport android.util.DisplayMetrics;
306f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.util.FloatProperty;
31d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.util.Log;
326f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.util.Property;
33d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.MotionEvent;
34d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.VelocityTracker;
35d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.View;
36d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.ViewConfiguration;
37d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.ViewGroup;
3874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganovimport android.view.accessibility.AccessibilityManager;
39d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.animation.Interpolator;
40d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.widget.Scroller;
41d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
42d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller/**
43d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * This layout handles interaction with the sliding security challenge views
44d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * that overlay/resize other keyguard contents.
45d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */
4619a5267003e7dc70100a4bd4f1f449523b2ff38bJim Millerpublic class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout {
47d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private static final String TAG = "SlidingChallengeLayout";
481bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler    private static final boolean DEBUG = false;
49d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
50c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    // The drag handle is measured in dp above & below the top edge of the
515547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller    // challenge view; these parameters change based on whether the challenge
52c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    // is open or closed.
539c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell    private static final int DRAG_HANDLE_CLOSED_ABOVE = 8; // dp
54cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell    private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp
55c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp
56c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp
57c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
5870c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung    private static final int HANDLE_ANIMATE_DURATION = 250; // ms
59c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
60d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // Drawn to show the drag handle in closed state; crossfades to the challenge view
61d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // when challenge is fully visible
62cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private boolean mEdgeCaptured;
63d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
645da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell    private DisplayMetrics mDisplayMetrics;
655da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell
66d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // Initialized during measurement from child layoutparams
6774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    private View mExpandChallengeView;
68052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren    private KeyguardSecurityContainer mChallengeView;
69eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    private View mScrimView;
70cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private View mWidgetsView;
71d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
72d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // Range: 0 (fully hidden) to 1 (fully visible)
73d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private float mChallengeOffset = 1.f;
74d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean mChallengeShowing = true;
75da8f622b908121efa4c838936fce26c11a74799dChris Wren    private boolean mChallengeShowingTargetState = true;
7603ad0c09502c72c02af464f1e273af3b6ff799ccChris Wren    private boolean mWasChallengeShowing = true;
77eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    private boolean mIsBouncing = false;
78d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
79d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private final Scroller mScroller;
80db1c5d596e91713132131601536aaad32e693325Adam Cohen    private ObjectAnimator mFader;
81d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private int mScrollState;
820b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    private OnChallengeScrolledListener mScrollListener;
830b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    private OnBouncerStateChangedListener mBouncerListener;
845547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller    private boolean mEnableChallengeDragging;
85d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
86d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public static final int SCROLL_STATE_IDLE = 0;
87d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public static final int SCROLL_STATE_DRAGGING = 1;
88d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public static final int SCROLL_STATE_SETTLING = 2;
89db1c5d596e91713132131601536aaad32e693325Adam Cohen    public static final int SCROLL_STATE_FADING = 3;
90db1c5d596e91713132131601536aaad32e693325Adam Cohen
91c162dd049084681711526b219ea997aa23f5ad98Jim Miller    public static final int CHALLENGE_FADE_OUT_DURATION = 100;
92c162dd049084681711526b219ea997aa23f5ad98Jim Miller    public static final int CHALLENGE_FADE_IN_DURATION = 160;
93d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
94d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private static final int MAX_SETTLE_DURATION = 600; // ms
95d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
96d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // ID of the pointer in charge of a current drag
97d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private int mActivePointerId = INVALID_POINTER;
98d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private static final int INVALID_POINTER = -1;
99d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
100d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // True if the user is currently dragging the slider
101d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean mDragging;
102d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // True if the user may not drag until a new gesture begins
103d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean mBlockDrag;
104d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
105d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private VelocityTracker mVelocityTracker;
106d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private int mMinVelocity;
107d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private int mMaxVelocity;
108c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private float mGestureStartX, mGestureStartY; // where did you first touch the screen?
109b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    private int mGestureStartChallengeBottom; // where was the challenge at that time?
110c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
111c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int mDragHandleClosedBelow; // handle hitrect extension into the challenge view
112c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int mDragHandleClosedAbove; // extend the handle's hitrect this far above the line
113c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int mDragHandleOpenBelow; // handle hitrect extension into the challenge view
114c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int mDragHandleOpenAbove; // extend the handle's hitrect this far above the line
115c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
1160b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    private int mDragHandleEdgeSlop;
11767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell    private int mChallengeBottomBound; // Number of pixels from the top of the challenge view
11867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                                       // that should remain on-screen
119c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
120c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int mTouchSlop;
12174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    private int mTouchSlopSquare;
122c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
1236f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    float mHandleAlpha;
1246f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    float mFrameAlpha;
125cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    float mFrameAnimationTarget = Float.MIN_VALUE;
1266f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    private ObjectAnimator mHandleAnimation;
1276f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    private ObjectAnimator mFrameAnimation;
1286f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
129cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private boolean mHasGlowpad;
130256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock    private final Rect mInsets = new Rect();
131db1c5d596e91713132131601536aaad32e693325Adam Cohen
132db1c5d596e91713132131601536aaad32e693325Adam Cohen    // We have an internal and external version, and we and them together.
133db1c5d596e91713132131601536aaad32e693325Adam Cohen    private boolean mChallengeInteractiveExternal = true;
134db1c5d596e91713132131601536aaad32e693325Adam Cohen    private boolean mChallengeInteractiveInternal = true;
135cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
1366f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA =
1376f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            new FloatProperty<SlidingChallengeLayout>("handleAlpha") {
1386f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        @Override
1396f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        public void setValue(SlidingChallengeLayout view, float value) {
1406f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            view.mHandleAlpha = value;
1416f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            view.invalidate();
1426f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        }
1436f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
1446f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        @Override
1456f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        public Float get(SlidingChallengeLayout view) {
1466f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            return view.mHandleAlpha;
1476f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        }
1486f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    };
1496f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
150d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // True if at least one layout pass has happened since the view was attached.
151d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean mHasLayout;
152d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
153d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private static final Interpolator sMotionInterpolator = new Interpolator() {
154d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public float getInterpolation(float t) {
155d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            t -= 1.0f;
156d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return t * t * t * t * t + 1.0f;
157d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
158d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    };
159d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
160d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private static final Interpolator sHandleFadeInterpolator = new Interpolator() {
161d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public float getInterpolation(float t) {
162d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return t * t;
163d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
164d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    };
165d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
166d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private final Runnable mEndScrollRunnable = new Runnable () {
167d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public void run() {
168d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            completeChallengeScroll();
169d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
170d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    };
171d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
172eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    private final OnClickListener mScrimClickListener = new OnClickListener() {
173eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        @Override
174eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        public void onClick(View v) {
175eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            hideBouncer();
176eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        }
177eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    };
178eee209313d564be37b8fc068f785b3844cd6597eAdam Powell
17974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    private final OnClickListener mExpandChallengeClickListener = new OnClickListener() {
18074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        @Override
18174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        public void onClick(View v) {
18278a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock            if (!isChallengeShowing()) {
18374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                showChallenge(true);
18474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            }
18574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        }
18674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    };
18774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov
188d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    /**
189d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * Listener interface that reports changes in scroll state of the challenge area.
190d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     */
191d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public interface OnChallengeScrolledListener {
192d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        /**
193d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * The scroll state itself changed.
194d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
195d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <p>scrollState will be one of the following:</p>
196d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
197d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <ul>
198d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li>
199d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging
200d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * the challenge area.</li>
201d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating
202d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * into place.</li>
203d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * </ul>
204d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
205d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <p>Do not perform expensive operations (e.g. layout)
206d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p>
207d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
208d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * @param scrollState The new scroll state of the challenge area.
209d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         */
210d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public void onScrollStateChanged(int scrollState);
211d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
212d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        /**
213d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * The precise position of the challenge area has changed.
214d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
215d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * <p>NOTE: It is NOT safe to modify layout or call any View methods that may
216d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * result in a requestLayout anywhere in your view hierarchy as a result of this call.
217d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * It may be called during drawing.</p>
218d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *
219d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * @param scrollPosition New relative position of the challenge area.
220d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *                       1.f = fully visible/ready to be interacted with.
221d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *                       0.f = fully invisible/inaccessible to the user.
222d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         * @param challengeTop Position of the top edge of the challenge view in px in the
223d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         *                     SlidingChallengeLayout's coordinate system.
224d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller         */
225d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public void onScrollPositionChanged(float scrollPosition, int challengeTop);
226d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
227d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
228d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public SlidingChallengeLayout(Context context) {
229d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        this(context, null);
230d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
231d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
232d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public SlidingChallengeLayout(Context context, AttributeSet attrs) {
233d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        this(context, attrs, 0);
234d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
235d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
236d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) {
237d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        super(context, attrs, defStyle);
238d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
239d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mScroller = new Scroller(context, sMotionInterpolator);
240d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
241d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final ViewConfiguration vc = ViewConfiguration.get(context);
242d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mMinVelocity = vc.getScaledMinimumFlingVelocity();
243d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mMaxVelocity = vc.getScaledMaximumFlingVelocity();
244d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
245fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        final Resources res = getResources();
246fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        mDragHandleEdgeSlop = res.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
2470b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell
248c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
24974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        mTouchSlopSquare = mTouchSlop * mTouchSlop;
250c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
2515da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell        mDisplayMetrics = res.getDisplayMetrics();
2525da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell        final float density = mDisplayMetrics.density;
2531bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler
2541bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler        // top half of the lock icon, plus another 25% to be sure
255c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f);
256c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        mDragHandleClosedBelow = (int) (DRAG_HANDLE_CLOSED_BELOW * density + 0.5f);
257c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        mDragHandleOpenAbove = (int) (DRAG_HANDLE_OPEN_ABOVE * density + 0.5f);
258c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f);
259c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler
260c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        // how much space to account for in the handle when closed
261fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        mChallengeBottomBound = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding);
2621bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler
263cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell        setWillNotDraw(false);
264bd95740648372449a4d5c164d7050eee352d4c24John Spurlock        setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
265cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell    }
266cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell
2675547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller    public void setEnableChallengeDragging(boolean enabled) {
2685547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller        mEnableChallengeDragging = enabled;
2695547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller    }
2705547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller
271256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock    public void setInsets(Rect insets) {
272256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock        mInsets.set(insets);
273256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock    }
274256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock
2756e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock    public void setHandleAlpha(float alpha) {
2766e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock        if (mExpandChallengeView != null) {
2776e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock            mExpandChallengeView.setAlpha(alpha);
2786f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        }
2796f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    }
2806f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
281bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock    public void setChallengeInteractive(boolean interactive) {
282db1c5d596e91713132131601536aaad32e693325Adam Cohen        mChallengeInteractiveExternal = interactive;
28378a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock        if (mExpandChallengeView != null) {
28478a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock            mExpandChallengeView.setEnabled(interactive);
28578a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock        }
286bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock    }
287bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock
2886f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    void animateHandle(boolean visible) {
2896f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        if (mHandleAnimation != null) {
2906f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            mHandleAnimation.cancel();
29167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell            mHandleAnimation = null;
292d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
29367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        final float targetAlpha = visible ? 1.f : 0.f;
29467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        if (targetAlpha == mHandleAlpha) {
29567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell            return;
29667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        }
29767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, targetAlpha);
2986f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        mHandleAnimation.setInterpolator(sHandleFadeInterpolator);
2996f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION);
3006f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell        mHandleAnimation.start();
3016f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell    }
3026f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
303d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private void sendInitialListenerUpdates() {
3040b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        if (mScrollListener != null) {
305d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0;
3060b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop);
3070b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            mScrollListener.onScrollStateChanged(mScrollState);
308d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
309d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
310d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
311d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) {
3120b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        mScrollListener = listener;
313d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mHasLayout) {
314d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            sendInitialListenerUpdates();
315d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
316d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
317d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
3180b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) {
3190b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        mBouncerListener = listener;
3200b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    }
3210b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell
322d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
323d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void onAttachedToWindow() {
324d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        super.onAttachedToWindow();
325d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
326d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mHasLayout = false;
327d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
328d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
329d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
330d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void onDetachedFromWindow() {
331d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        super.onDetachedFromWindow();
332d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
333d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        removeCallbacks(mEndScrollRunnable);
334d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mHasLayout = false;
335d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
336d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
3370b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    @Override
3380b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    public void requestChildFocus(View child, View focused) {
3390b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        if (mIsBouncing && child != mChallengeView) {
3400b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            // Clear out of the bouncer if the user tries to move focus outside of
3410b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            // the security challenge view.
3420b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            hideBouncer();
3430b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        }
3440b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        super.requestChildFocus(child, focused);
3450b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell    }
3460b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell
347d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // We want the duration of the page snap animation to be influenced by the distance that
348d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // the screen has to travel, however, we don't want this duration to be effected in a
349d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
350d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    // of travel has on the overall snap duration.
351d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    float distanceInfluenceForSnapDuration(float f) {
352d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        f -= 0.5f; // center the values about 0.
353d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        f *= 0.3f * Math.PI / 2.0f;
354d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return (float) Math.sin(f);
355d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
356d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
357d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    void setScrollState(int state) {
358d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mScrollState != state) {
359d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            mScrollState = state;
360d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
3616f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing);
3620b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            if (mScrollListener != null) {
3630b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell                mScrollListener.onScrollStateChanged(state);
364d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            }
365d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
366d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
367d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
368d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    void completeChallengeScroll() {
369da8f622b908121efa4c838936fce26c11a74799dChris Wren        setChallengeShowing(mChallengeShowingTargetState);
370da8f622b908121efa4c838936fce26c11a74799dChris Wren        mChallengeOffset = mChallengeShowing ? 1.f : 0.f;
371d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        setScrollState(SCROLL_STATE_IDLE);
372db1c5d596e91713132131601536aaad32e693325Adam Cohen        mChallengeInteractiveInternal = true;
373cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
374d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
375d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
376eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    void setScrimView(View scrim) {
377eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        if (mScrimView != null) {
378eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            mScrimView.setOnClickListener(null);
379eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        }
380eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        mScrimView = scrim;
381257f283b0e4cc1c1fa4e7f2472d3ee4ab3b451d0John Spurlock        if (mScrimView != null) {
382257f283b0e4cc1c1fa4e7f2472d3ee4ab3b451d0John Spurlock            mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE);
383257f283b0e4cc1c1fa4e7f2472d3ee4ab3b451d0John Spurlock            mScrimView.setFocusable(true);
384257f283b0e4cc1c1fa4e7f2472d3ee4ab3b451d0John Spurlock            mScrimView.setOnClickListener(mScrimClickListener);
385257f283b0e4cc1c1fa4e7f2472d3ee4ab3b451d0John Spurlock        }
386eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    }
387eee209313d564be37b8fc068f785b3844cd6597eAdam Powell
388d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    /**
389d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * Animate the bottom edge of the challenge view to the given position.
390d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     *
391d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @param y desired final position for the bottom edge of the challenge view in px
392d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @param velocity velocity in
393d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     */
394d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    void animateChallengeTo(int y, int velocity) {
395d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mChallengeView == null) {
396d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            // Nothing to do.
397d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return;
398d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
399db1c5d596e91713132131601536aaad32e693325Adam Cohen
4008caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        cancelTransitionsInProgress();
401db1c5d596e91713132131601536aaad32e693325Adam Cohen
402db1c5d596e91713132131601536aaad32e693325Adam Cohen        mChallengeInteractiveInternal = false;
4030a4079ec0c11a3fa28ed2a82781a482372015818John Reck        enableHardwareLayerForChallengeView();
40467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        final int sy = mChallengeView.getBottom();
40567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        final int dy = y - sy;
406d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (dy == 0) {
407d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            completeChallengeScroll();
408d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return;
409d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
410d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
411d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        setScrollState(SCROLL_STATE_SETTLING);
412d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
413d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int childHeight = mChallengeView.getHeight();
414d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int halfHeight = childHeight / 2;
415d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight);
416d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final float distance = halfHeight + halfHeight *
417d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                distanceInfluenceForSnapDuration(distanceRatio);
418d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
419d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        int duration = 0;
420d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        velocity = Math.abs(velocity);
421d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (velocity > 0) {
422d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
423d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        } else {
424d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final float childDelta = (float) Math.abs(dy) / childHeight;
425d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            duration = (int) ((childDelta + 1) * 100);
426d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
427d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        duration = Math.min(duration, MAX_SETTLE_DURATION);
428d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
429d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mScroller.startScroll(0, sy, 0, dy, duration);
430d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        postInvalidateOnAnimation();
431d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
432d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
433d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private void setChallengeShowing(boolean showChallenge) {
43474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        if (mChallengeShowing == showChallenge) {
43574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            return;
43674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        }
43767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        mChallengeShowing = showChallenge;
4385a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell
4395a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell        if (mExpandChallengeView == null || mChallengeView == null) {
4405a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell            // These might not be here yet if we haven't been through layout.
4415a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell            // If we haven't, the first layout pass will set everything up correctly
4425a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell            // based on mChallengeShowing as set above.
4435a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell            return;
4445a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell        }
4455a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell
44674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        if (mChallengeShowing) {
44774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            mExpandChallengeView.setVisibility(View.INVISIBLE);
44874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            mChallengeView.setVisibility(View.VISIBLE);
44974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
45074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mChallengeView.requestAccessibilityFocus();
45174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mChallengeView.announceForAccessibility(mContext.getString(
45274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                        R.string.keyguard_accessibility_unlock_area_expanded));
45374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            }
45474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        } else {
45574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            mExpandChallengeView.setVisibility(View.VISIBLE);
45674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            mChallengeView.setVisibility(View.INVISIBLE);
45774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
45874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mExpandChallengeView.requestAccessibilityFocus();
45974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mChallengeView.announceForAccessibility(mContext.getString(
46074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                        R.string.keyguard_accessibility_unlock_area_collapsed));
46174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            }
46274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        }
463d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
464d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
465d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    /**
466d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @return true if the challenge is at all visible.
467d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     */
468d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public boolean isChallengeShowing() {
469d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return mChallengeShowing;
470d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
471d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
472d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
47319a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller    public boolean isChallengeOverlapping() {
47419a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller        return mChallengeShowing;
47519a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller    }
47619a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller
47719a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller    @Override
478eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    public boolean isBouncing() {
479eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        return mIsBouncing;
480eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    }
481eee209313d564be37b8fc068f785b3844cd6597eAdam Powell
482eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    @Override
48370c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung    public int getBouncerAnimationDuration() {
48470c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung        return HANDLE_ANIMATE_DURATION;
48570c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung    }
48670c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung
48770c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung    @Override
488eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    public void showBouncer() {
489eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        if (mIsBouncing) return;
490e657a82ee1a53e42cced3159dd7782ca052ea9f6Jim Miller        setSystemUiVisibility(getSystemUiVisibility() | STATUS_BAR_DISABLE_SEARCH);
49103ad0c09502c72c02af464f1e273af3b6ff799ccChris Wren        mWasChallengeShowing = mChallengeShowing;
49203ad0c09502c72c02af464f1e273af3b6ff799ccChris Wren        mIsBouncing = true;
4936cf53bb3a94ec5a6eebc96a315dac32d042f1945Winson Chung        showChallenge(true);
494eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        if (mScrimView != null) {
49570c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f);
49670c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung            anim.setDuration(HANDLE_ANIMATE_DURATION);
49770c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung            anim.addListener(new AnimatorListenerAdapter() {
49870c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung                @Override
49970c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung                public void onAnimationStart(Animator animation) {
50070c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung                    mScrimView.setVisibility(VISIBLE);
50170c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung                }
50270c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung            });
50370c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung            anim.start();
504eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        }
505052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren        if (mChallengeView != null) {
506052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren            mChallengeView.showBouncer(HANDLE_ANIMATE_DURATION);
507052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren        }
508cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
5090b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        if (mBouncerListener != null) {
5100b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            mBouncerListener.onBouncerStateChanged(true);
5110b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        }
512eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    }
513eee209313d564be37b8fc068f785b3844cd6597eAdam Powell
514eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    @Override
515eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    public void hideBouncer() {
516eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        if (!mIsBouncing) return;
517e657a82ee1a53e42cced3159dd7782ca052ea9f6Jim Miller        setSystemUiVisibility(getSystemUiVisibility() & ~STATUS_BAR_DISABLE_SEARCH);
51803ad0c09502c72c02af464f1e273af3b6ff799ccChris Wren        if (!mWasChallengeShowing) showChallenge(false);
519eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        mIsBouncing = false;
52070c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung
521eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        if (mScrimView != null) {
52270c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f);
52370c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung            anim.setDuration(HANDLE_ANIMATE_DURATION);
52470c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung            anim.addListener(new AnimatorListenerAdapter() {
52570c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung                @Override
52670c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung                public void onAnimationEnd(Animator animation) {
52770c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung                    mScrimView.setVisibility(GONE);
52870c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung                }
52970c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung            });
53070c2f8736437ebb6073c3b6dab2e08e6dd9f39a6Winson Chung            anim.start();
531eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        }
532052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren        if (mChallengeView != null) {
533052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren            mChallengeView.hideBouncer(HANDLE_ANIMATE_DURATION);
534052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren        }
5350b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        if (mBouncerListener != null) {
5360b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            mBouncerListener.onBouncerStateChanged(false);
5370b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        }
538eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    }
539eee209313d564be37b8fc068f785b3844cd6597eAdam Powell
540cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private int getChallengeMargin(boolean expanded) {
541cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop;
542cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    }
543cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
544fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell    private float getChallengeAlpha() {
545fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        float x = mChallengeOffset - 1;
546fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        return x * x * x + 1.f;
547fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell    }
548fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell
549eee209313d564be37b8fc068f785b3844cd6597eAdam Powell    @Override
550d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void requestDisallowInterceptTouchEvent(boolean allowIntercept) {
551d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        // We'll intercept whoever we feel like! ...as long as it isn't a challenge view.
552d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        // If there are one or more pointers in the challenge view before we take over
553d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        // touch events, onInterceptTouchEvent will set mBlockDrag.
554d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
555d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
556d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
557d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public boolean onInterceptTouchEvent(MotionEvent ev) {
558d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mVelocityTracker == null) {
559d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            mVelocityTracker = VelocityTracker.obtain();
560d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
561d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mVelocityTracker.addMovement(ev);
562d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
563d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int action = ev.getActionMasked();
564d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        switch (action) {
565022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller            case MotionEvent.ACTION_DOWN:
566c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                mGestureStartX = ev.getX();
567b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                mGestureStartY = ev.getY();
568995270f01175234d0615a0e1900576f142a3b4adAdam Powell                mBlockDrag = false;
569022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller                break;
570022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller
571d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_CANCEL:
572d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_UP:
573d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                resetTouch();
574d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                break;
575d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
576d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_MOVE:
577d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int count = ev.getPointerCount();
578d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                for (int i = 0; i < count; i++) {
579d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    final float x = ev.getX(i);
580d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    final float y = ev.getY(i);
581db1c5d596e91713132131601536aaad32e693325Adam Cohen                    if (!mIsBouncing && mActivePointerId == INVALID_POINTER
5829c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell                                && (crossedDragHandle(x, y, mGestureStartY)
5835547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller                                        && shouldEnableChallengeDragging()
5845547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller                                        || (isInChallengeView(x, y) &&
5859c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell                                        mScrollState == SCROLL_STATE_SETTLING))) {
586d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        mActivePointerId = ev.getPointerId(i);
587c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                        mGestureStartX = x;
588c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                        mGestureStartY = y;
589b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                        mGestureStartChallengeBottom = getChallengeBottom();
590d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        mDragging = true;
5910a4079ec0c11a3fa28ed2a82781a482372015818John Reck                        enableHardwareLayerForChallengeView();
5925547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller                    } else if (mChallengeShowing && isInChallengeView(x, y)
5935547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller                            && shouldEnableChallengeDragging()) {
594d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        mBlockDrag = true;
595d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    }
596d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
597d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                break;
598d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
599d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
600db1c5d596e91713132131601536aaad32e693325Adam Cohen        if (mBlockDrag || isChallengeInteractionBlocked()) {
601d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            mActivePointerId = INVALID_POINTER;
602d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            mDragging = false;
603d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
604d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
605d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return mDragging;
606d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
607d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
6085547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller    private boolean shouldEnableChallengeDragging() {
6095547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller        return mEnableChallengeDragging || !mChallengeShowing;
6105547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller    }
6115547b55bae92e6674e528d671f7700d7f5a9b3d0Jim Miller
612db1c5d596e91713132131601536aaad32e693325Adam Cohen    private boolean isChallengeInteractionBlocked() {
613db1c5d596e91713132131601536aaad32e693325Adam Cohen        return !mChallengeInteractiveExternal || !mChallengeInteractiveInternal;
614db1c5d596e91713132131601536aaad32e693325Adam Cohen    }
615db1c5d596e91713132131601536aaad32e693325Adam Cohen
616d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private void resetTouch() {
617d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mVelocityTracker.recycle();
618d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mVelocityTracker = null;
619d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mActivePointerId = INVALID_POINTER;
620d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mDragging = mBlockDrag = false;
621d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
622d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
623d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
624d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public boolean onTouchEvent(MotionEvent ev) {
625d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mVelocityTracker == null) {
626d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            mVelocityTracker = VelocityTracker.obtain();
627d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
628d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mVelocityTracker.addMovement(ev);
629d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
630d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int action = ev.getActionMasked();
631d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        switch (action) {
632995270f01175234d0615a0e1900576f142a3b4adAdam Powell            case MotionEvent.ACTION_DOWN:
633995270f01175234d0615a0e1900576f142a3b4adAdam Powell                mBlockDrag = false;
634c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                mGestureStartX = ev.getX();
635995270f01175234d0615a0e1900576f142a3b4adAdam Powell                mGestureStartY = ev.getY();
636995270f01175234d0615a0e1900576f142a3b4adAdam Powell                break;
637995270f01175234d0615a0e1900576f142a3b4adAdam Powell
638d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_CANCEL:
639db1c5d596e91713132131601536aaad32e693325Adam Cohen                if (mDragging && !isChallengeInteractionBlocked()) {
640d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    showChallenge(0);
641d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
642d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                resetTouch();
643d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                break;
644d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
645d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_POINTER_UP:
646d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) {
647d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    break;
648d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
649d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_UP:
650db1c5d596e91713132131601536aaad32e693325Adam Cohen                if (mDragging && !isChallengeInteractionBlocked()) {
651d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
652d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId));
653d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
654d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                resetTouch();
655d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                break;
656d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
657d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            case MotionEvent.ACTION_MOVE:
6586f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell                if (!mDragging && !mBlockDrag && !mIsBouncing) {
659d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    final int count = ev.getPointerCount();
660d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    for (int i = 0; i < count; i++) {
661d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        final float x = ev.getX(i);
662d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        final float y = ev.getY(i);
663d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
664b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                        if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) ||
665d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                                (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING))
6661ec464679f731827f626856084f19643fff64a94John Spurlock                                && mActivePointerId == INVALID_POINTER
667db1c5d596e91713132131601536aaad32e693325Adam Cohen                                && !isChallengeInteractionBlocked()) {
668c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                            mGestureStartX = x;
669b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                            mGestureStartY = y;
670d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                            mActivePointerId = ev.getPointerId(i);
671b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                            mGestureStartChallengeBottom = getChallengeBottom();
672d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                            mDragging = true;
6730a4079ec0c11a3fa28ed2a82781a482372015818John Reck                            enableHardwareLayerForChallengeView();
674d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                            break;
675d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        }
676d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    }
677d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
678d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // Not an else; this can be set above.
679d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                if (mDragging) {
680d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    // No-op if already in this state, but set it here in case we arrived
681d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    // at this point from either intercept or the above.
682d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    setScrollState(SCROLL_STATE_DRAGGING);
683d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
684d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    final int index = ev.findPointerIndex(mActivePointerId);
685d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    if (index < 0) {
686d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        // Oops, bogus state. We lost some touch events somewhere.
687d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        // Just drop it with no velocity and let things settle.
688d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        resetTouch();
689d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        showChallenge(0);
690d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        return true;
691d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    }
692b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                    final float y = ev.getY(index);
693b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                    final float pos = Math.min(y - mGestureStartY,
69467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                            getLayoutBottom() - mChallengeBottomBound);
695b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler
696b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                    moveChallengeTo(mGestureStartChallengeBottom + (int) pos);
697d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
698d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                break;
699d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
700d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return true;
701d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
702d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
703b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    /**
704cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     * The lifecycle of touch events is subtle and it's very easy to do something
705cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     * that will cause bugs that will be nasty to track when overriding this method.
706cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     * Normally one should always override onInterceptTouchEvent instead.
707cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     *
708cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     * To put it another way, don't try this at home.
709cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell     */
710cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    @Override
711cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    public boolean dispatchTouchEvent(MotionEvent ev) {
712cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        final int action = ev.getActionMasked();
713cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        boolean handled = false;
714cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (action == MotionEvent.ACTION_DOWN) {
715cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // Defensive programming: if we didn't get the UP or CANCEL, reset anyway.
716cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            mEdgeCaptured = false;
717cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
718cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) {
719cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // Normally we would need to do a lot of extra stuff here.
720cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // We can only get away with this because we haven't padded in
721cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // the widget pager or otherwise transformed it during layout.
722cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // We also don't support things like splitting MotionEvents.
723cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
724cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // We set handled to captured even if dispatch is returning false here so that
725cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            // we don't send a different view a busted or incomplete event stream.
726cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev);
727cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
728cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
729cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (!handled && !mEdgeCaptured) {
730cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            handled = super.dispatchTouchEvent(ev);
731cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
732cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
733cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
734cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            mEdgeCaptured = false;
735cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
736cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
737cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        return handled;
738cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    }
739cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
740cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    private boolean isEdgeSwipeBeginEvent(MotionEvent ev) {
741cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
742cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            return false;
743cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        }
744cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
745cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        final float x = ev.getX();
746cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop;
747cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    }
748cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell
749cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell    /**
750b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     * We only want to add additional vertical space to the drag handle when the panel is fully
751b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     * closed.
752b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     */
753c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int getDragHandleSizeAbove() {
754c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        return isChallengeShowing() ? mDragHandleOpenAbove : mDragHandleClosedAbove;
755c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    }
756c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler    private int getDragHandleSizeBelow() {
757c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler        return isChallengeShowing() ? mDragHandleOpenBelow : mDragHandleClosedBelow;
758b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    }
759b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler
760d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean isInChallengeView(float x, float y) {
76174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        return isPointInView(x, y, mChallengeView);
762d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
763d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
764d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean isInDragHandle(float x, float y) {
76574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        return isPointInView(x, y, mExpandChallengeView);
76674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    }
767d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
76874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    private boolean isPointInView(float x, float y, View view) {
76974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        if (view == null) {
77074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            return false;
77174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        }
77274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        return x >= view.getLeft() && y >= view.getTop()
77374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                && x < view.getRight() && y < view.getBottom();
774d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
775d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
776b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    private boolean crossedDragHandle(float x, float y, float initialY) {
7779c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell
778022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller        final int challengeTop = mChallengeView.getTop();
7799c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell        final boolean horizOk = x >= 0 && x < getWidth();
7809c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell
7819c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell        final boolean vertOk;
7829c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell        if (mChallengeShowing) {
7839c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell            vertOk = initialY < (challengeTop - getDragHandleSizeAbove()) &&
7849c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell                    y > challengeTop + getDragHandleSizeBelow();
7859c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell        } else {
7869c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell            vertOk = initialY > challengeTop + getDragHandleSizeBelow() &&
7879c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell                    y < challengeTop - getDragHandleSizeAbove();
7889c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell        }
7899c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell        return horizOk && vertOk;
790022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller    }
791022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller
7929799714f6c69efe50e21a6073b879140e5e792b7Adam Powell    private int makeChildMeasureSpec(int maxSize, int childDimen) {
7939799714f6c69efe50e21a6073b879140e5e792b7Adam Powell        final int mode;
7949799714f6c69efe50e21a6073b879140e5e792b7Adam Powell        final int size;
7959799714f6c69efe50e21a6073b879140e5e792b7Adam Powell        switch (childDimen) {
7969799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            case LayoutParams.WRAP_CONTENT:
7979799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                mode = MeasureSpec.AT_MOST;
7989799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                size = maxSize;
7999799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                break;
8009799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            case LayoutParams.MATCH_PARENT:
8019799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                mode = MeasureSpec.EXACTLY;
8029799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                size = maxSize;
8039799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                break;
8049799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            default:
8059799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                mode = MeasureSpec.EXACTLY;
8069799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                size = Math.min(maxSize, childDimen);
8079799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                break;
8089799714f6c69efe50e21a6073b879140e5e792b7Adam Powell        }
8099799714f6c69efe50e21a6073b879140e5e792b7Adam Powell        return MeasureSpec.makeMeasureSpec(size, mode);
8109799714f6c69efe50e21a6073b879140e5e792b7Adam Powell    }
8119799714f6c69efe50e21a6073b879140e5e792b7Adam Powell
812d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
813d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    protected void onMeasure(int widthSpec, int heightSpec) {
814d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY ||
815d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) {
816d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            throw new IllegalArgumentException(
817d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    "SlidingChallengeLayout must be measured with an exact size");
818d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
819d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int width = MeasureSpec.getSize(widthSpec);
820d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int height = MeasureSpec.getSize(heightSpec);
821d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        setMeasuredDimension(width, height);
822d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
823256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock        final int insetHeight = height - mInsets.top - mInsets.bottom;
824256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock        final int insetHeightSpec = MeasureSpec.makeMeasureSpec(insetHeight, MeasureSpec.EXACTLY);
825256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock
826d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        // Find one and only one challenge view.
827d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final View oldChallengeView = mChallengeView;
82874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        final View oldExpandChallengeView = mChallengeView;
829d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mChallengeView = null;
83074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        mExpandChallengeView = null;
831d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int count = getChildCount();
8328a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen
8338a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        // First iteration through the children finds special children and sets any associated
8348a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        // state.
835d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        for (int i = 0; i < count; i++) {
836d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final View child = getChildAt(i);
837d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
838eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
839d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                if (mChallengeView != null) {
840d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    throw new IllegalStateException(
841d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                            "There may only be one child with layout_isChallenge=\"true\"");
842d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
843052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren                if (!(child instanceof KeyguardSecurityContainer)) {
844052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren                            throw new IllegalArgumentException(
845052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren                                    "Challenge must be a KeyguardSecurityContainer");
846052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren                }
847052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren                mChallengeView = (KeyguardSecurityContainer) child;
848d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                if (mChallengeView != oldChallengeView) {
849d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE);
850d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                }
8516f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell                // We're going to play silly games with the frame's background drawable later.
852cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                if (!mHasLayout) {
853cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    // Set up the margin correctly based on our content for the first run.
854cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null;
855cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                    lp.leftMargin = lp.rightMargin = getChallengeMargin(true);
856cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                }
85774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) {
85874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                if (mExpandChallengeView != null) {
85974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                    throw new IllegalStateException(
86074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                            "There may only be one child with layout_childType"
86174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                            + "=\"expandChallengeHandle\"");
86274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                }
86374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mExpandChallengeView = child;
86474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                if (mExpandChallengeView != oldExpandChallengeView) {
86574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                    mExpandChallengeView.setVisibility(mChallengeShowing ? INVISIBLE : VISIBLE);
86674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                    mExpandChallengeView.setOnClickListener(mExpandChallengeClickListener);
86774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                }
868eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
869eee209313d564be37b8fc068f785b3844cd6597eAdam Powell                setScrimView(child);
870cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell            } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
871cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell                mWidgetsView = child;
872d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            }
8738a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        }
8748a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen
8755be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen        // We want to measure the challenge view first, since the KeyguardWidgetPager
8765be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen        // needs to do things its measure pass that are dependent on the challenge view
8775be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen        // having been measured.
87874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        if (mChallengeView != null && mChallengeView.getVisibility() != View.GONE) {
8799799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            // This one's a little funny. If the IME is present - reported in the form
8809799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            // of insets on the root view - we only give the challenge the space it would
8819799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            // have had if the IME wasn't there in order to keep the rest of the layout stable.
8829799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            // We base this on the layout_maxHeight on the challenge view. If it comes out
8839799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            // negative or zero, either we didn't have a maxHeight or we're totally out of space,
8849799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            // so give up and measure as if this rule weren't there.
885256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock            int challengeHeightSpec = insetHeightSpec;
8869799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            final View root = getRootView();
8879799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            if (root != null) {
8889799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams();
889256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                final int windowHeight = mDisplayMetrics.heightPixels
890256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                        - root.getPaddingTop() - mInsets.top;
891256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                final int diff = windowHeight - insetHeight;
8929799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                final int maxChallengeHeight = lp.maxHeight - diff;
8939799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                if (maxChallengeHeight > 0) {
8949799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                    challengeHeightSpec = makeChildMeasureSpec(maxChallengeHeight, lp.height);
8959799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                }
8969799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            }
8979799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            measureChildWithMargins(mChallengeView, widthSpec, 0, challengeHeightSpec, 0);
8988a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        }
899d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
9008a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        // Measure the rest of the children
9018a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        for (int i = 0; i < count; i++) {
9028a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen            final View child = getChildAt(i);
90374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (child.getVisibility() == GONE) {
90474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                continue;
90574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            }
9068a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen            // Don't measure the challenge view twice!
9075da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell            if (child == mChallengeView) continue;
9085da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell
9095da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell            // Measure children. Widget frame measures special, so that we can ignore
9105da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell            // insets for the IME.
911256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock            int parentWidthSpec = widthSpec, parentHeightSpec = insetHeightSpec;
9125da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
9135da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell            if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
9145da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                final View root = getRootView();
9155da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                if (root != null) {
9165da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                    // This calculation is super dodgy and relies on several assumptions.
9175da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                    // Specifically that the root of the window will be padded in for insets
9185da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                    // and that the window is LAYOUT_IN_SCREEN.
9195da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                    final int windowWidth = mDisplayMetrics.widthPixels;
920256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                    final int windowHeight = mDisplayMetrics.heightPixels
921256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                            - root.getPaddingTop() - mInsets.top;
9225da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                    parentWidthSpec = MeasureSpec.makeMeasureSpec(
9235da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                            windowWidth, MeasureSpec.EXACTLY);
9245da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                    parentHeightSpec = MeasureSpec.makeMeasureSpec(
9255da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                            windowHeight, MeasureSpec.EXACTLY);
9265da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell                }
927256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
928256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                // Allow scrim views to extend into the insets
929256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                parentWidthSpec = widthSpec;
930256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                parentHeightSpec = heightSpec;
9318a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen            }
9325da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell            measureChildWithMargins(child, parentWidthSpec, 0, parentHeightSpec, 0);
933d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
934d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
935d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
936d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
937d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    protected void onLayout(boolean changed, int l, int t, int r, int b) {
938d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int paddingLeft = getPaddingLeft();
939d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int paddingTop = getPaddingTop();
940d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int paddingRight = getPaddingRight();
941d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int paddingBottom = getPaddingBottom();
942d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int width = r - l;
943d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int height = b - t;
944d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
945d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int count = getChildCount();
946d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        for (int i = 0; i < count; i++) {
947d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final View child = getChildAt(i);
948d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
949d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            if (child.getVisibility() == GONE) continue;
950d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
951d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
952d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
953eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
954d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // Challenge views pin to the bottom, offset by a portion of their height,
955d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // and center horizontally.
956d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int center = (paddingLeft + width - paddingRight) / 2;
957d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int childWidth = child.getMeasuredWidth();
958d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int childHeight = child.getMeasuredHeight();
959d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                final int left = center - childWidth / 2;
960256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                final int layoutBottom = height - paddingBottom - lp.bottomMargin - mInsets.bottom;
961d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // We use the top of the challenge view to position the handle, so
962d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // we never want less than the handle size showing at the bottom.
96367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound)
964d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        * (1 - mChallengeOffset));
965fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell                child.setAlpha(getChallengeAlpha());
966d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                child.layout(left, bottom - childHeight, left + childWidth, bottom);
96774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) {
9680f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                final int center = (paddingLeft + width - paddingRight) / 2;
9690f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                final int left = center - child.getMeasuredWidth() / 2;
9700f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                final int right = left + child.getMeasuredWidth();
971256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                final int bottom = height - paddingBottom - lp.bottomMargin - mInsets.bottom;
9720f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                final int top = bottom - child.getMeasuredHeight();
9730f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov                child.layout(left, top, right, bottom);
974256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
975256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                // Scrim views use the entire area, including padding & insets
976256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                child.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
977d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            } else {
978d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                // Non-challenge views lay out from the upper left, layered.
979d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                child.layout(paddingLeft + lp.leftMargin,
980256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                        paddingTop + lp.topMargin + mInsets.top,
981d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                        paddingLeft + child.getMeasuredWidth(),
982256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                        paddingTop + child.getMeasuredHeight() + mInsets.top);
983d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            }
984d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
985d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
986d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (!mHasLayout) {
9876f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            mHasLayout = true;
988d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
989d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
990d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
991d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
992d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void draw(Canvas c) {
993d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        super.draw(c);
9941bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler        if (DEBUG) {
99574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            final Paint debugPaint = new Paint();
9961bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler            debugPaint.setColor(0x40FF00CC);
9971bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler            // show the isInDragHandle() rect
9981bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler            c.drawRect(mDragHandleEdgeSlop,
999c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                    mChallengeView.getTop() - getDragHandleSizeAbove(),
10001bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler                    getWidth() - mDragHandleEdgeSlop,
1001c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler                    mChallengeView.getTop() + getDragHandleSizeBelow(),
10021bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler                    debugPaint);
10031bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler        }
100474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    }
10051bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler
1006f83324504e0d62f4cba5355459e17cdf9f1100e7Craig Mautner    @Override
1007f83324504e0d62f4cba5355459e17cdf9f1100e7Craig Mautner    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
1008f83324504e0d62f4cba5355459e17cdf9f1100e7Craig Mautner        // Focus security fileds before widgets.
1009f83324504e0d62f4cba5355459e17cdf9f1100e7Craig Mautner        if (mChallengeView != null &&
1010f83324504e0d62f4cba5355459e17cdf9f1100e7Craig Mautner                mChallengeView.requestFocus(direction, previouslyFocusedRect)) {
1011f83324504e0d62f4cba5355459e17cdf9f1100e7Craig Mautner            return true;
1012f83324504e0d62f4cba5355459e17cdf9f1100e7Craig Mautner        }
1013f83324504e0d62f4cba5355459e17cdf9f1100e7Craig Mautner        return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
1014f83324504e0d62f4cba5355459e17cdf9f1100e7Craig Mautner    }
1015f83324504e0d62f4cba5355459e17cdf9f1100e7Craig Mautner
101674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov    public void computeScroll() {
101774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        super.computeScroll();
10186f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell
101974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        if (!mScroller.isFinished()) {
102074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (mChallengeView == null) {
102174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                // Can't scroll if the view is missing.
102274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                Log.e(TAG, "Challenge view missing in computeScroll");
102374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                mScroller.abortAnimation();
102474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                return;
10251bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler            }
10261bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler
102774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            mScroller.computeScrollOffset();
102874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            moveChallengeTo(mScroller.getCurrY());
102974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov
103074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov            if (mScroller.isFinished()) {
103174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov                post(mEndScrollRunnable);
10326f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell            }
1033d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1034d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1035d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
10368caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    private void cancelTransitionsInProgress() {
10378caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        if (!mScroller.isFinished()) {
10388caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            mScroller.abortAnimation();
10398caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            completeChallengeScroll();
10408caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        }
10418caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        if (mFader != null) {
10428caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            mFader.cancel();
10438caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        }
10448caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    }
10458caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10468caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    public void fadeInChallenge() {
10478caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        fadeChallenge(true);
10488caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    }
10498caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10508caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    public void fadeOutChallenge() {
10518caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        fadeChallenge(false);
10528caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    }
10538caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10548caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    public void fadeChallenge(final boolean show) {
10558caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        if (mChallengeView != null) {
10568caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10578caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            cancelTransitionsInProgress();
10588caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            float alpha = show ? 1f : 0f;
10598caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            int duration = show ? CHALLENGE_FADE_IN_DURATION : CHALLENGE_FADE_OUT_DURATION;
10608caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            mFader = ObjectAnimator.ofFloat(mChallengeView, "alpha", alpha);
10618caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            mFader.addListener(new AnimatorListenerAdapter() {
10628caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen                @Override
10638caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen                public void onAnimationStart(Animator animation) {
10648caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen                    onFadeStart(show);
10658caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen                }
10668caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen                @Override
10678caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen                public void onAnimationEnd(Animator animation) {
10688caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen                    onFadeEnd(show);
10698caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen                }
10708caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            });
10718caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            mFader.setDuration(duration);
10728caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            mFader.start();
10738caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        }
10748caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    }
10758caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10768caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    private int getMaxChallengeBottom() {
10778caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        if (mChallengeView == null) return 0;
10788caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        final int layoutBottom = getLayoutBottom();
10798caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        final int challengeHeight = mChallengeView.getMeasuredHeight();
10808caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10818caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        return (layoutBottom + challengeHeight - mChallengeBottomBound);
10828caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    }
10838caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10848caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    private int getMinChallengeBottom() {
10858caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        return getLayoutBottom();
10868caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    }
10878caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10888caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10898caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    private void onFadeStart(boolean show) {
10908caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        mChallengeInteractiveInternal = false;
10910a4079ec0c11a3fa28ed2a82781a482372015818John Reck        enableHardwareLayerForChallengeView();
10928caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10938caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        if (show) {
10948caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            moveChallengeTo(getMinChallengeBottom());
10958caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        }
10968caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
10978caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        setScrollState(SCROLL_STATE_FADING);
10988caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    }
10998caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
11000a4079ec0c11a3fa28ed2a82781a482372015818John Reck    private void enableHardwareLayerForChallengeView() {
11010a4079ec0c11a3fa28ed2a82781a482372015818John Reck        if (mChallengeView.isHardwareAccelerated()) {
11020a4079ec0c11a3fa28ed2a82781a482372015818John Reck            mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
11030a4079ec0c11a3fa28ed2a82781a482372015818John Reck        }
11040a4079ec0c11a3fa28ed2a82781a482372015818John Reck    }
11050a4079ec0c11a3fa28ed2a82781a482372015818John Reck
11068caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    private void onFadeEnd(boolean show) {
11078caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        mChallengeInteractiveInternal = true;
11088caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        setChallengeShowing(show);
11098caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
11108caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        if (!show) {
11118caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen            moveChallengeTo(getMaxChallengeBottom());
11128caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        }
11138caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
11148caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
11158caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        mFader = null;
11168caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        setScrollState(SCROLL_STATE_IDLE);
11178caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen    }
11188caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen
1119e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen    public int getMaxChallengeTop() {
1120e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen        if (mChallengeView == null) return 0;
1121e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen
1122e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen        final int layoutBottom = getLayoutBottom();
11238a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen        final int challengeHeight = mChallengeView.getMeasuredHeight();
1124256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock        return layoutBottom - challengeHeight - mInsets.top;
1125e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen    }
1126e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen
1127d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    /**
1128d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * Move the bottom edge of mChallengeView to a new position and notify the listener
1129d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * if it represents a change in position. Changes made through this method will
1130d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * be stable across layout passes. If this method is called before first layout of
1131d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * this SlidingChallengeLayout it will have no effect.
1132d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     *
1133d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system.
1134d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @return true if the challenge view was moved
1135d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     */
1136d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private boolean moveChallengeTo(int bottom) {
1137d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mChallengeView == null || !mHasLayout) {
1138d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return false;
1139d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1140d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1141b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler        final int layoutBottom = getLayoutBottom();
1142d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        final int challengeHeight = mChallengeView.getHeight();
1143d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
11448caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen        bottom = Math.max(getMinChallengeBottom(),
11458caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen                Math.min(bottom, getMaxChallengeBottom()));
1146d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
114767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell        float offset = 1.f - (float) (bottom - layoutBottom) /
114867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                (challengeHeight - mChallengeBottomBound);
1149d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mChallengeOffset = offset;
1150d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (offset > 0 && !mChallengeShowing) {
1151d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            setChallengeShowing(true);
1152d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1153d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1154d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        mChallengeView.layout(mChallengeView.getLeft(),
1155d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom);
1156d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1157fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell        mChallengeView.setAlpha(getChallengeAlpha());
11580b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell        if (mScrollListener != null) {
11590b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell            mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop());
1160d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1161d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        postInvalidateOnAnimation();
1162d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return true;
1163d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1164d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1165b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    /**
1166b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     * The bottom edge of this SlidingChallengeLayout's coordinate system; will coincide with
1167b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     * the bottom edge of mChallengeView when the challenge is fully opened.
1168b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     */
1169b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    private int getLayoutBottom() {
1170b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler        final int bottomMargin = (mChallengeView == null)
1171b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                ? 0
1172b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler                : ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin;
1173256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock        final int layoutBottom = getMeasuredHeight() - getPaddingBottom() - bottomMargin
1174256ae67b9a629178b458dfc01102c9c0b9963d03John Spurlock                - mInsets.bottom;
1175b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler        return layoutBottom;
1176b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    }
1177b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler
1178b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    /**
1179b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     * The bottom edge of mChallengeView; essentially, where the sliding challenge 'is'.
1180b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler     */
1181d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private int getChallengeBottom() {
1182d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mChallengeView == null) return 0;
1183d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1184d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return mChallengeView.getBottom();
1185d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1186d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1187b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler    /**
1188d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * Show or hide the challenge view, animating it if necessary.
1189d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     * @param show true to show, false to hide
1190d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller     */
1191d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public void showChallenge(boolean show) {
1192d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        showChallenge(show, 0);
1193995270f01175234d0615a0e1900576f142a3b4adAdam Powell        if (!show) {
1194995270f01175234d0615a0e1900576f142a3b4adAdam Powell            // Block any drags in progress so that callers can use this to disable dragging
1195995270f01175234d0615a0e1900576f142a3b4adAdam Powell            // for other touch interactions.
1196995270f01175234d0615a0e1900576f142a3b4adAdam Powell            mBlockDrag = true;
1197995270f01175234d0615a0e1900576f142a3b4adAdam Powell        }
1198d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1199d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1200d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private void showChallenge(int velocity) {
1201d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        boolean show = false;
1202d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (Math.abs(velocity) > mMinVelocity) {
1203d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            show = velocity < 0;
1204d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        } else {
1205d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            show = mChallengeOffset >= 0.5f;
1206d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1207d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        showChallenge(show, velocity);
1208d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1209d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1210d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    private void showChallenge(boolean show, int velocity) {
1211d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mChallengeView == null) {
1212d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            setChallengeShowing(false);
1213d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            return;
1214d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1215d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1216d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        if (mHasLayout) {
1217da8f622b908121efa4c838936fce26c11a74799dChris Wren            mChallengeShowingTargetState = show;
121867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell            final int layoutBottom = getLayoutBottom();
1219d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            animateChallengeTo(show ? layoutBottom :
122067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell                    layoutBottom + mChallengeView.getHeight() - mChallengeBottomBound, velocity);
1221d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1222d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1223d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
122419a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller    @Override
1225d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
1226d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return new LayoutParams(getContext(), attrs);
1227d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1228d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1229d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
1230d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
1231d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) :
1232d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) :
1233d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                new LayoutParams(p);
1234d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1235d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1236d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
1237d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
1238d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return new LayoutParams();
1239d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1240d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1241d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    @Override
1242d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1243d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        return p instanceof LayoutParams;
1244d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1245d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1246d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    public static class LayoutParams extends MarginLayoutParams {
1247eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        public int childType = CHILD_TYPE_NONE;
1248eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        public static final int CHILD_TYPE_NONE = 0;
1249eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        public static final int CHILD_TYPE_CHALLENGE = 2;
1250eee209313d564be37b8fc068f785b3844cd6597eAdam Powell        public static final int CHILD_TYPE_SCRIM = 4;
1251cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell        public static final int CHILD_TYPE_WIDGETS = 5;
125274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov        public static final int CHILD_TYPE_EXPAND_CHALLENGE_HANDLE = 6;
1253d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
12549799714f6c69efe50e21a6073b879140e5e792b7Adam Powell        public int maxHeight;
12559799714f6c69efe50e21a6073b879140e5e792b7Adam Powell
1256d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams() {
1257d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            this(MATCH_PARENT, WRAP_CONTENT);
1258d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1259d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1260d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams(int width, int height) {
1261d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            super(width, height);
1262d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1263d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1264d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
1265d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            super(source);
1266d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1267d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1268d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams(MarginLayoutParams source) {
1269d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            super(source);
1270d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1271d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1272d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams(LayoutParams source) {
1273d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            super(source);
1274d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1275eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            childType = source.childType;
1276d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1277d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1278d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        public LayoutParams(Context c, AttributeSet attrs) {
1279d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            super(c, attrs);
1280d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller
1281d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            final TypedArray a = c.obtainStyledAttributes(attrs,
1282d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller                    R.styleable.SlidingChallengeLayout_Layout);
1283eee209313d564be37b8fc068f785b3844cd6597eAdam Powell            childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType,
1284eee209313d564be37b8fc068f785b3844cd6597eAdam Powell                    CHILD_TYPE_NONE);
12859799714f6c69efe50e21a6073b879140e5e792b7Adam Powell            maxHeight = a.getDimensionPixelSize(
12869799714f6c69efe50e21a6073b879140e5e792b7Adam Powell                    R.styleable.SlidingChallengeLayout_Layout_layout_maxHeight, 0);
1287d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller            a.recycle();
1288d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller        }
1289d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller    }
1290d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller}
1291