SlidingChallengeLayout.java revision 5a2c5f0efacf5f11a928c8481f6747c3d13ddcfd
1d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller/* 2d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Copyright (C) 2012 The Android Open Source Project 3d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 4d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Licensed under the Apache License, Version 2.0 (the "License"); 5d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * you may not use this file except in compliance with the License. 6d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * You may obtain a copy of the License at 7d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 8d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * http://www.apache.org/licenses/LICENSE-2.0 9d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 10d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Unless required by applicable law or agreed to in writing, software 11d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * distributed under the License is distributed on an "AS IS" BASIS, 12d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * See the License for the specific language governing permissions and 14d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * limitations under the License. 15d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 16d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 17d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerpackage com.android.internal.policy.impl.keyguard; 18d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 199c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powellimport com.android.internal.R; 209c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell 21cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powellimport android.animation.Animator; 22cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powellimport android.animation.AnimatorListenerAdapter; 236f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.animation.ObjectAnimator; 24d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.content.Context; 25fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powellimport android.content.res.Resources; 26d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.content.res.TypedArray; 27d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.graphics.Canvas; 281bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandlerimport android.graphics.Paint; 29cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powellimport android.graphics.Rect; 30d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.graphics.drawable.Drawable; 31d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.util.AttributeSet; 325da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powellimport android.util.DisplayMetrics; 336f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.util.FloatProperty; 34d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.util.Log; 356f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.util.Property; 36d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.MotionEvent; 37d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.VelocityTracker; 38d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.View; 39d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.ViewConfiguration; 40d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.ViewGroup; 4174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganovimport android.view.accessibility.AccessibilityManager; 42d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.animation.Interpolator; 43d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.widget.Scroller; 44d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 45d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller/** 46d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * This layout handles interaction with the sliding security challenge views 47d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * that overlay/resize other keyguard contents. 48d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 4919a5267003e7dc70100a4bd4f1f449523b2ff38bJim Millerpublic class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout { 50d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final String TAG = "SlidingChallengeLayout"; 511bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler private static final boolean DEBUG = false; 52d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 53c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // The drag handle is measured in dp above & below the top edge of the 54c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // challenge view; these parameters change based on whether the challenge 55c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // is open or closed. 569c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell private static final int DRAG_HANDLE_CLOSED_ABOVE = 8; // dp 57cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp 58c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp 59c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp 60c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 61c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private static final int HANDLE_ANIMATE_DURATION = 200; // ms 62c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 63d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Drawn to show the drag handle in closed state; crossfades to the challenge view 64d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // when challenge is fully visible 656f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private Drawable mFrameDrawable; 66cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private boolean mEdgeCaptured; 67d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 685da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell private DisplayMetrics mDisplayMetrics; 695da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell 70d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Initialized during measurement from child layoutparams 7174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov private View mExpandChallengeView; 72052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren private KeyguardSecurityContainer mChallengeView; 73eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private View mScrimView; 74cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private View mWidgetsView; 75d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 76d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Range: 0 (fully hidden) to 1 (fully visible) 77d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private float mChallengeOffset = 1.f; 78d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mChallengeShowing = true; 79eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private boolean mIsBouncing = false; 80d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 81d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private final Scroller mScroller; 82db1c5d596e91713132131601536aaad32e693325Adam Cohen private ObjectAnimator mFader; 83d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mScrollState; 840b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private OnChallengeScrolledListener mScrollListener; 850b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private OnBouncerStateChangedListener mBouncerListener; 86d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 87d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_IDLE = 0; 88d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_DRAGGING = 1; 89d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_SETTLING = 2; 90db1c5d596e91713132131601536aaad32e693325Adam Cohen public static final int SCROLL_STATE_FADING = 3; 91db1c5d596e91713132131601536aaad32e693325Adam Cohen 928caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private static final int CHALLENGE_FADE_OUT_DURATION = 100; 938caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private static final int CHALLENGE_FADE_IN_DURATION = 160; 94d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 95d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final int MAX_SETTLE_DURATION = 600; // ms 96d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 97d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // ID of the pointer in charge of a current drag 98d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mActivePointerId = INVALID_POINTER; 99d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final int INVALID_POINTER = -1; 100d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 101d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if the user is currently dragging the slider 102d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mDragging; 103d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if the user may not drag until a new gesture begins 104d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mBlockDrag; 105d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 106d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private VelocityTracker mVelocityTracker; 107d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mMinVelocity; 108d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mMaxVelocity; 109c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private float mGestureStartX, mGestureStartY; // where did you first touch the screen? 110b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private int mGestureStartChallengeBottom; // where was the challenge at that time? 111c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 112c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleClosedBelow; // handle hitrect extension into the challenge view 113c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleClosedAbove; // extend the handle's hitrect this far above the line 114c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleOpenBelow; // handle hitrect extension into the challenge view 115c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleOpenAbove; // extend the handle's hitrect this far above the line 116c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 1170b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private int mDragHandleEdgeSlop; 11867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell private int mChallengeBottomBound; // Number of pixels from the top of the challenge view 11967625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell // that should remain on-screen 120c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 121c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mTouchSlop; 12274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov private int mTouchSlopSquare; 123c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 1246f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell float mHandleAlpha; 1256f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell float mFrameAlpha; 126cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell float mFrameAnimationTarget = Float.MIN_VALUE; 1276f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private ObjectAnimator mHandleAnimation; 1286f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private ObjectAnimator mFrameAnimation; 1296f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 130cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private final Rect mTempRect = new Rect(); 131cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 132cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private boolean mHasGlowpad; 133db1c5d596e91713132131601536aaad32e693325Adam Cohen 134db1c5d596e91713132131601536aaad32e693325Adam Cohen // We have an internal and external version, and we and them together. 135db1c5d596e91713132131601536aaad32e693325Adam Cohen private boolean mChallengeInteractiveExternal = true; 136db1c5d596e91713132131601536aaad32e693325Adam Cohen private boolean mChallengeInteractiveInternal = true; 137cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 1386f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA = 1396f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell new FloatProperty<SlidingChallengeLayout>("handleAlpha") { 1406f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1416f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setValue(SlidingChallengeLayout view, float value) { 1426f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mHandleAlpha = value; 1436f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.invalidate(); 1446f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1456f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1466f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1476f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public Float get(SlidingChallengeLayout view) { 1486f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell return view.mHandleAlpha; 1496f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1506f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell }; 1516f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1526f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell static final Property<SlidingChallengeLayout, Float> FRAME_ALPHA = 1536f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell new FloatProperty<SlidingChallengeLayout>("frameAlpha") { 1546f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1556f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setValue(SlidingChallengeLayout view, float value) { 1566f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (view.mFrameDrawable != null) { 1576f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameAlpha = value; 1586f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameDrawable.setAlpha((int) (value * 0xFF)); 1596f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mFrameDrawable.invalidateSelf(); 1606f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1616f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1626f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1636f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1646f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public Float get(SlidingChallengeLayout view) { 1656f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell return view.mFrameAlpha; 1666f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1676f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell }; 168d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 169d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if at least one layout pass has happened since the view was attached. 170d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mHasLayout; 171d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 172d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final Interpolator sMotionInterpolator = new Interpolator() { 173d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public float getInterpolation(float t) { 174d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller t -= 1.0f; 175d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return t * t * t * t * t + 1.0f; 176d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 177d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 178d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 179d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final Interpolator sHandleFadeInterpolator = new Interpolator() { 180d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public float getInterpolation(float t) { 181d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return t * t; 182d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 183d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 184d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 185d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private final Runnable mEndScrollRunnable = new Runnable () { 186d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void run() { 187d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller completeChallengeScroll(); 188d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 189d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 190d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 191eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private final OnClickListener mScrimClickListener = new OnClickListener() { 192eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 193eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void onClick(View v) { 194eee209313d564be37b8fc068f785b3844cd6597eAdam Powell hideBouncer(); 195eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 196eee209313d564be37b8fc068f785b3844cd6597eAdam Powell }; 197eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 19874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov private final OnClickListener mExpandChallengeClickListener = new OnClickListener() { 19974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov @Override 20074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov public void onClick(View v) { 20178a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock if (!isChallengeShowing()) { 20274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov showChallenge(true); 20374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 20474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 20574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov }; 20674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov 207d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 208d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Listener interface that reports changes in scroll state of the challenge area. 209d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 210d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public interface OnChallengeScrolledListener { 211d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 212d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * The scroll state itself changed. 213d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 214d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>scrollState will be one of the following:</p> 215d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 216d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <ul> 217d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li> 218d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging 219d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * the challenge area.</li> 220d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating 221d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * into place.</li> 222d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * </ul> 223d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 224d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>Do not perform expensive operations (e.g. layout) 225d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p> 226d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 227d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param scrollState The new scroll state of the challenge area. 228d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 229d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onScrollStateChanged(int scrollState); 230d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 231d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 232d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * The precise position of the challenge area has changed. 233d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 234d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>NOTE: It is NOT safe to modify layout or call any View methods that may 235d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * result in a requestLayout anywhere in your view hierarchy as a result of this call. 236d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * It may be called during drawing.</p> 237d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 238d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param scrollPosition New relative position of the challenge area. 239d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 1.f = fully visible/ready to be interacted with. 240d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 0.f = fully invisible/inaccessible to the user. 241d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param challengeTop Position of the top edge of the challenge view in px in the 242d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * SlidingChallengeLayout's coordinate system. 243d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 244d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onScrollPositionChanged(float scrollPosition, int challengeTop); 245d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 246d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 247d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context) { 248d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(context, null); 249d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 250d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 251d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context, AttributeSet attrs) { 252d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(context, attrs, 0); 253d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 254d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 255d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) { 256d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(context, attrs, defStyle); 257d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 258d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller = new Scroller(context, sMotionInterpolator); 259d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 260d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final ViewConfiguration vc = ViewConfiguration.get(context); 261d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mMinVelocity = vc.getScaledMinimumFlingVelocity(); 262d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mMaxVelocity = vc.getScaledMaximumFlingVelocity(); 263d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 264fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell final Resources res = getResources(); 265fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell mDragHandleEdgeSlop = res.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size); 2660b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 267c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 26874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mTouchSlopSquare = mTouchSlop * mTouchSlop; 269c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 2705da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell mDisplayMetrics = res.getDisplayMetrics(); 2715da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell final float density = mDisplayMetrics.density; 2721bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 2731bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // top half of the lock icon, plus another 25% to be sure 274c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f); 275c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleClosedBelow = (int) (DRAG_HANDLE_CLOSED_BELOW * density + 0.5f); 276c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleOpenAbove = (int) (DRAG_HANDLE_OPEN_ABOVE * density + 0.5f); 277c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f); 278c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 279c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // how much space to account for in the handle when closed 280fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell mChallengeBottomBound = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding); 2811bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 282cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell setWillNotDraw(false); 283cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell } 284cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell 2856e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock public void setHandleAlpha(float alpha) { 2866e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock if (mExpandChallengeView != null) { 2876e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock mExpandChallengeView.setAlpha(alpha); 2886f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2896f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2906f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 291bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock public void setChallengeInteractive(boolean interactive) { 292db1c5d596e91713132131601536aaad32e693325Adam Cohen mChallengeInteractiveExternal = interactive; 29378a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock if (mExpandChallengeView != null) { 29478a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock mExpandChallengeView.setEnabled(interactive); 29578a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock } 296bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock } 297bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock 2986f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell void animateHandle(boolean visible) { 2996f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mHandleAnimation != null) { 3006f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.cancel(); 30167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mHandleAnimation = null; 302d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 30367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final float targetAlpha = visible ? 1.f : 0.f; 30467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell if (targetAlpha == mHandleAlpha) { 30567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell return; 30667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell } 30767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, targetAlpha); 3086f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.setInterpolator(sHandleFadeInterpolator); 3096f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION); 3106f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.start(); 3116f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 3126f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 313cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell void animateFrame(final boolean visible, final boolean full) { 3146f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mFrameDrawable == null) return; 3156f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 316cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell final float targetAlpha = visible ? (full ? 1.f : 0.5f) : 0.f; 317cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (mFrameAnimation != null && targetAlpha != mFrameAnimationTarget) { 3186f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.cancel(); 319cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mFrameAnimationTarget = Float.MIN_VALUE; 32067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell } 321cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (targetAlpha == mFrameAlpha || targetAlpha == mFrameAnimationTarget) { 32267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell return; 323d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 324cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mFrameAnimationTarget = targetAlpha; 32567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell 32667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mFrameAnimation = ObjectAnimator.ofFloat(this, FRAME_ALPHA, targetAlpha); 3276f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.setInterpolator(sHandleFadeInterpolator); 3286f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.setDuration(HANDLE_ANIMATE_DURATION); 329cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mFrameAnimation.addListener(new AnimatorListenerAdapter() { 330cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell @Override 331cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell public void onAnimationEnd(Animator animation) { 332cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mFrameAnimationTarget = Float.MIN_VALUE; 333cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 334cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (!visible && full && mChallengeView != null) { 335cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // Mess with padding/margin to remove insets on the bouncer frame. 336cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setPadding(0, 0, 0, 0); 337cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams(); 338cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell lp.leftMargin = lp.rightMargin = getChallengeMargin(true); 339cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setLayoutParams(lp); 340cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 341cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mFrameAnimation = null; 342cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 343cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 344cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell @Override 345cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell public void onAnimationCancel(Animator animation) { 346cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mFrameAnimationTarget = Float.MIN_VALUE; 347cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mFrameAnimation = null; 348cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 349cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell }); 3506f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameAnimation.start(); 351d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 352d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 353d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void sendInitialListenerUpdates() { 3540b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 355d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0; 3560b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop); 3570b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollStateChanged(mScrollState); 358d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 359d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 360d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 361d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) { 3620b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener = listener; 363d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mHasLayout) { 364d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller sendInitialListenerUpdates(); 365d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 366d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 367d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3680b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) { 3690b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener = listener; 3700b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3710b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 372d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 373d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onAttachedToWindow() { 374d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.onAttachedToWindow(); 375d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 376d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHasLayout = false; 377d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 378d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 379d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 380d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onDetachedFromWindow() { 381d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.onDetachedFromWindow(); 382d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 383d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller removeCallbacks(mEndScrollRunnable); 384d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHasLayout = false; 385d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 386d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3870b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell @Override 3880b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell public void requestChildFocus(View child, View focused) { 3890b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mIsBouncing && child != mChallengeView) { 3900b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell // Clear out of the bouncer if the user tries to move focus outside of 3910b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell // the security challenge view. 3920b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell hideBouncer(); 3930b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3940b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell super.requestChildFocus(child, focused); 3950b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3960b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 397d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We want the duration of the page snap animation to be influenced by the distance that 398d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // the screen has to travel, however, we don't want this duration to be effected in a 399d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // purely linear fashion. Instead, we use this method to moderate the effect that the distance 400d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // of travel has on the overall snap duration. 401d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller float distanceInfluenceForSnapDuration(float f) { 402d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller f -= 0.5f; // center the values about 0. 403d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller f *= 0.3f * Math.PI / 2.0f; 404d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return (float) Math.sin(f); 405d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 406d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 407d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void setScrollState(int state) { 408d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mScrollState != state) { 409d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScrollState = state; 410d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 4116f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing); 412cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (!mIsBouncing) { 413cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell animateFrame(false, false); 414cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 4150b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 4160b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollStateChanged(state); 417d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 418d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 419d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 420d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 421d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void completeChallengeScroll() { 422d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(mChallengeOffset != 0); 423d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_IDLE); 424db1c5d596e91713132131601536aaad32e693325Adam Cohen mChallengeInteractiveInternal = true; 425cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setLayerType(LAYER_TYPE_NONE, null); 426d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 427d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 428eee209313d564be37b8fc068f785b3844cd6597eAdam Powell void setScrimView(View scrim) { 429eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 430eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setOnClickListener(null); 431eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 432eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView = scrim; 433eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE); 434eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setFocusable(true); 435eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setOnClickListener(mScrimClickListener); 436eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 437eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 438d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 439d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Animate the bottom edge of the challenge view to the given position. 440d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 441d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param y desired final position for the bottom edge of the challenge view in px 442d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param velocity velocity in 443d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 444d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void animateChallengeTo(int y, int velocity) { 445d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 446d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Nothing to do. 447d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 448d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 449db1c5d596e91713132131601536aaad32e693325Adam Cohen 4508caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen cancelTransitionsInProgress(); 451db1c5d596e91713132131601536aaad32e693325Adam Cohen 452db1c5d596e91713132131601536aaad32e693325Adam Cohen mChallengeInteractiveInternal = false; 453db1c5d596e91713132131601536aaad32e693325Adam Cohen mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); 45467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int sy = mChallengeView.getBottom(); 45567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int dy = y - sy; 456d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (dy == 0) { 457d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller completeChallengeScroll(); 458d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 459d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 460d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 461d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_SETTLING); 462d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 463d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childHeight = mChallengeView.getHeight(); 464d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int halfHeight = childHeight / 2; 465d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight); 466d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float distance = halfHeight + halfHeight * 467d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller distanceInfluenceForSnapDuration(distanceRatio); 468d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 469d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int duration = 0; 470d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller velocity = Math.abs(velocity); 471d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (velocity > 0) { 472d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 473d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 474d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float childDelta = (float) Math.abs(dy) / childHeight; 475d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = (int) ((childDelta + 1) * 100); 476d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 477d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = Math.min(duration, MAX_SETTLE_DURATION); 478d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 479d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.startScroll(0, sy, 0, dy, duration); 480d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller postInvalidateOnAnimation(); 481d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 482d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 483d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void setChallengeShowing(boolean showChallenge) { 48474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mChallengeShowing == showChallenge) { 48574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return; 48674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 48767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mChallengeShowing = showChallenge; 4885a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell 4895a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell if (mExpandChallengeView == null || mChallengeView == null) { 4905a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell // These might not be here yet if we haven't been through layout. 4915a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell // If we haven't, the first layout pass will set everything up correctly 4925a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell // based on mChallengeShowing as set above. 4935a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell return; 4945a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell } 4955a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell 49674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mChallengeShowing) { 49774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView.setVisibility(View.INVISIBLE); 49874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mChallengeView.setVisibility(View.VISIBLE); 49974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 50074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mChallengeView.requestAccessibilityFocus(); 50174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mChallengeView.announceForAccessibility(mContext.getString( 50274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov R.string.keyguard_accessibility_unlock_area_expanded)); 50374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 50474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } else { 50574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView.setVisibility(View.VISIBLE); 50674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mChallengeView.setVisibility(View.INVISIBLE); 50774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 50874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView.requestAccessibilityFocus(); 50974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mChallengeView.announceForAccessibility(mContext.getString( 51074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov R.string.keyguard_accessibility_unlock_area_collapsed)); 51174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 51274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 513d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 514d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 515d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 516d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @return true if the challenge is at all visible. 517d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 518d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean isChallengeShowing() { 519d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mChallengeShowing; 520d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 521d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 522d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 52319a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller public boolean isChallengeOverlapping() { 52419a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller return mChallengeShowing; 52519a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller } 52619a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller 52719a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller @Override 528eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public boolean isBouncing() { 529eee209313d564be37b8fc068f785b3844cd6597eAdam Powell return mIsBouncing; 530eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 531eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 532eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 533eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void showBouncer() { 534eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mIsBouncing) return; 535eee209313d564be37b8fc068f785b3844cd6597eAdam Powell showChallenge(true); 536eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mIsBouncing = true; 537eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 5386f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mScrimView.setVisibility(VISIBLE); 539eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 540052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren if (mChallengeView != null) { 541052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren mChallengeView.showBouncer(HANDLE_ANIMATE_DURATION); 542052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren } 543cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // Mess with padding/margin to inset the bouncer frame. 544cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // We have more space available to us otherwise. 545cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (mChallengeView != null) { 546cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (mFrameDrawable == null || !mFrameDrawable.getPadding(mTempRect)) { 547cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mTempRect.set(0, 0, 0, 0); 548cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 549cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setPadding(mTempRect.left, mTempRect.top, mTempRect.right, 550cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mTempRect.bottom); 551cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams(); 552cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell lp.leftMargin = lp.rightMargin = getChallengeMargin(false); 553cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setLayoutParams(lp); 554cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 555cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 5566f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateFrame(true, true); 557cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 5580b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mBouncerListener != null) { 5590b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener.onBouncerStateChanged(true); 5600b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 561eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 562eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 563eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 564eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void hideBouncer() { 565eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (!mIsBouncing) return; 566cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell showChallenge(false); 567eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mIsBouncing = false; 568eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 569eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setVisibility(GONE); 570eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 571052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren if (mChallengeView != null) { 572052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren mChallengeView.hideBouncer(HANDLE_ANIMATE_DURATION); 573052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren } 574cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell animateFrame(false, true); 5750b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mBouncerListener != null) { 5760b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener.onBouncerStateChanged(false); 5770b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 578eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 579eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 580cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private int getChallengeMargin(boolean expanded) { 581cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop; 582cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 583cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 584fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell private float getChallengeAlpha() { 585fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell float x = mChallengeOffset - 1; 586fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell return x * x * x + 1.f; 587fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell } 588fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell 589eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 590d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void requestDisallowInterceptTouchEvent(boolean allowIntercept) { 591d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We'll intercept whoever we feel like! ...as long as it isn't a challenge view. 592d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // If there are one or more pointers in the challenge view before we take over 593d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // touch events, onInterceptTouchEvent will set mBlockDrag. 594d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 595d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 596d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 597d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean onInterceptTouchEvent(MotionEvent ev) { 598d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mVelocityTracker == null) { 599d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = VelocityTracker.obtain(); 600d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 601d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.addMovement(ev); 602d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 603d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int action = ev.getActionMasked(); 604d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller switch (action) { 605022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller case MotionEvent.ACTION_DOWN: 606c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = ev.getX(); 607b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartY = ev.getY(); 608995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = false; 609022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller break; 610022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 611d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_CANCEL: 612d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_UP: 613d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 614d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 615d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 616d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_MOVE: 617d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = ev.getPointerCount(); 618d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 619d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float x = ev.getX(i); 620d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float y = ev.getY(i); 621db1c5d596e91713132131601536aaad32e693325Adam Cohen if (!mIsBouncing && mActivePointerId == INVALID_POINTER 6229c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell && (crossedDragHandle(x, y, mGestureStartY) 623c238af5112bee38b3143a65849bd41785c3744b0Adam Powell || (isInChallengeView(x, y) && 6249c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell mScrollState == SCROLL_STATE_SETTLING))) { 625d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = ev.getPointerId(i); 626c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = x; 627c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartY = y; 628b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartChallengeBottom = getChallengeBottom(); 629d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = true; 630cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); 6319c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell } else if (mChallengeShowing && isInChallengeView(x, y)) { 632d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mBlockDrag = true; 633d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 634d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 635d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 636d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 637d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 638db1c5d596e91713132131601536aaad32e693325Adam Cohen if (mBlockDrag || isChallengeInteractionBlocked()) { 639d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = INVALID_POINTER; 640d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = false; 641d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 642d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 643d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mDragging; 644d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 645d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 646db1c5d596e91713132131601536aaad32e693325Adam Cohen private boolean isChallengeInteractionBlocked() { 647db1c5d596e91713132131601536aaad32e693325Adam Cohen return !mChallengeInteractiveExternal || !mChallengeInteractiveInternal; 648db1c5d596e91713132131601536aaad32e693325Adam Cohen } 649db1c5d596e91713132131601536aaad32e693325Adam Cohen 650d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void resetTouch() { 651d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.recycle(); 652d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = null; 653d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = INVALID_POINTER; 654d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = mBlockDrag = false; 655d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 656d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 657d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 658d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean onTouchEvent(MotionEvent ev) { 659d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mVelocityTracker == null) { 660d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = VelocityTracker.obtain(); 661d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 662d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.addMovement(ev); 663d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 664d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int action = ev.getActionMasked(); 665d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller switch (action) { 666995270f01175234d0615a0e1900576f142a3b4adAdam Powell case MotionEvent.ACTION_DOWN: 667995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = false; 668c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = ev.getX(); 669995270f01175234d0615a0e1900576f142a3b4adAdam Powell mGestureStartY = ev.getY(); 670995270f01175234d0615a0e1900576f142a3b4adAdam Powell break; 671995270f01175234d0615a0e1900576f142a3b4adAdam Powell 672d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_CANCEL: 673db1c5d596e91713132131601536aaad32e693325Adam Cohen if (mDragging && !isChallengeInteractionBlocked()) { 674d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(0); 675d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 676d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 677d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 678d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 679d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_POINTER_UP: 680d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) { 681d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 682d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 683d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_UP: 684db1c5d596e91713132131601536aaad32e693325Adam Cohen if (mDragging && !isChallengeInteractionBlocked()) { 685d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); 686d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId)); 687d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 688d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 689d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 690d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 691d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_MOVE: 6926f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (!mDragging && !mBlockDrag && !mIsBouncing) { 693d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = ev.getPointerCount(); 694d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 695d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float x = ev.getX(i); 696d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float y = ev.getY(i); 697d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 698b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) || 699d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) 7001ec464679f731827f626856084f19643fff64a94John Spurlock && mActivePointerId == INVALID_POINTER 701db1c5d596e91713132131601536aaad32e693325Adam Cohen && !isChallengeInteractionBlocked()) { 702c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = x; 703b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartY = y; 704d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = ev.getPointerId(i); 705b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartChallengeBottom = getChallengeBottom(); 706d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = true; 707cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); 708d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 709d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 710d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 711d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 712d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Not an else; this can be set above. 713d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mDragging) { 714d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // No-op if already in this state, but set it here in case we arrived 715d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // at this point from either intercept or the above. 716d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_DRAGGING); 717d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 718d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int index = ev.findPointerIndex(mActivePointerId); 719d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (index < 0) { 720d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Oops, bogus state. We lost some touch events somewhere. 721d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Just drop it with no velocity and let things settle. 722d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 723d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(0); 724d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 725d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 726b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final float y = ev.getY(index); 727b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final float pos = Math.min(y - mGestureStartY, 72867625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell getLayoutBottom() - mChallengeBottomBound); 729b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 730b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler moveChallengeTo(mGestureStartChallengeBottom + (int) pos); 731d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 732d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 733d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 734d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 735d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 736d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 737b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 738cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell * The lifecycle of touch events is subtle and it's very easy to do something 739cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell * that will cause bugs that will be nasty to track when overriding this method. 740cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell * Normally one should always override onInterceptTouchEvent instead. 741cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell * 742cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell * To put it another way, don't try this at home. 743cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell */ 744cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell @Override 745cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell public boolean dispatchTouchEvent(MotionEvent ev) { 746cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell final int action = ev.getActionMasked(); 747cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell boolean handled = false; 748cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (action == MotionEvent.ACTION_DOWN) { 749cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // Defensive programming: if we didn't get the UP or CANCEL, reset anyway. 750cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mEdgeCaptured = false; 751cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 752cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) { 753cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // Normally we would need to do a lot of extra stuff here. 754cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // We can only get away with this because we haven't padded in 755cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // the widget pager or otherwise transformed it during layout. 756cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // We also don't support things like splitting MotionEvents. 757cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 758cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // We set handled to captured even if dispatch is returning false here so that 759cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // we don't send a different view a busted or incomplete event stream. 760cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev); 761cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 762cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 763cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (!handled && !mEdgeCaptured) { 764cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell handled = super.dispatchTouchEvent(ev); 765cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 766cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 767cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { 768cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mEdgeCaptured = false; 769cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 770cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 771cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell return handled; 772cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 773cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 774cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private boolean isEdgeSwipeBeginEvent(MotionEvent ev) { 775cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) { 776cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell return false; 777cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 778cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 779cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell final float x = ev.getX(); 780cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop; 781cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 782cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 783cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell /** 784b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * We only want to add additional vertical space to the drag handle when the panel is fully 785b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * closed. 786b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 787c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int getDragHandleSizeAbove() { 788c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler return isChallengeShowing() ? mDragHandleOpenAbove : mDragHandleClosedAbove; 789c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler } 790c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int getDragHandleSizeBelow() { 791c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler return isChallengeShowing() ? mDragHandleOpenBelow : mDragHandleClosedBelow; 792b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler } 793b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 794d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean isInChallengeView(float x, float y) { 79574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return isPointInView(x, y, mChallengeView); 796d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 797d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 798d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean isInDragHandle(float x, float y) { 79974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return isPointInView(x, y, mExpandChallengeView); 80074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 801d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 80274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov private boolean isPointInView(float x, float y, View view) { 80374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (view == null) { 80474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return false; 80574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 80674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return x >= view.getLeft() && y >= view.getTop() 80774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov && x < view.getRight() && y < view.getBottom(); 808d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 809d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 810b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private boolean crossedDragHandle(float x, float y, float initialY) { 8119c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell 812022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller final int challengeTop = mChallengeView.getTop(); 8139c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell final boolean horizOk = x >= 0 && x < getWidth(); 8149c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell 8159c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell final boolean vertOk; 8169c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell if (mChallengeShowing) { 8179c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell vertOk = initialY < (challengeTop - getDragHandleSizeAbove()) && 8189c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell y > challengeTop + getDragHandleSizeBelow(); 8199c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell } else { 8209c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell vertOk = initialY > challengeTop + getDragHandleSizeBelow() && 8219c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell y < challengeTop - getDragHandleSizeAbove(); 8229c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell } 8239c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell return horizOk && vertOk; 824022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller } 825022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 826d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 827d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected void onMeasure(int widthSpec, int heightSpec) { 828d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY || 829d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) { 830d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller throw new IllegalArgumentException( 831d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller "SlidingChallengeLayout must be measured with an exact size"); 832d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 833d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 834d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int width = MeasureSpec.getSize(widthSpec); 835d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int height = MeasureSpec.getSize(heightSpec); 836d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setMeasuredDimension(width, height); 837d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 838d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Find one and only one challenge view. 839d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View oldChallengeView = mChallengeView; 84074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov final View oldExpandChallengeView = mChallengeView; 841d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView = null; 84274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView = null; 843d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = getChildCount(); 8448a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen 8458a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // First iteration through the children finds special children and sets any associated 8468a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // state. 847d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 848d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View child = getChildAt(i); 849d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 850eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { 851d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != null) { 852d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller throw new IllegalStateException( 853d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller "There may only be one child with layout_isChallenge=\"true\""); 854d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 855052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren if (!(child instanceof KeyguardSecurityContainer)) { 856052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren throw new IllegalArgumentException( 857052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren "Challenge must be a KeyguardSecurityContainer"); 858052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren } 859052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren mChallengeView = (KeyguardSecurityContainer) child; 860d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != oldChallengeView) { 861d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE); 862d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 8636f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell // We're going to play silly games with the frame's background drawable later. 8646f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mFrameDrawable = mChallengeView.getBackground(); 865cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (!mHasLayout) { 866cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // Set up the margin correctly based on our content for the first run. 867cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null; 868cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell lp.leftMargin = lp.rightMargin = getChallengeMargin(true); 869cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 87074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) { 87174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mExpandChallengeView != null) { 87274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov throw new IllegalStateException( 87374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov "There may only be one child with layout_childType" 87474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov + "=\"expandChallengeHandle\""); 87574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 87674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView = child; 87774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mExpandChallengeView != oldExpandChallengeView) { 87874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView.setVisibility(mChallengeShowing ? INVISIBLE : VISIBLE); 87974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView.setOnClickListener(mExpandChallengeClickListener); 88074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 881eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) { 882eee209313d564be37b8fc068f785b3844cd6597eAdam Powell setScrimView(child); 883cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) { 884cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mWidgetsView = child; 885d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 8868a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen } 8878a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen 8885be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen // We want to measure the challenge view first, since the KeyguardWidgetPager 8895be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen // needs to do things its measure pass that are dependent on the challenge view 8905be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen // having been measured. 89174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mChallengeView != null && mChallengeView.getVisibility() != View.GONE) { 8928a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen measureChildWithMargins(mChallengeView, widthSpec, 0, heightSpec, 0); 8938a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen } 894d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 8958a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // Measure the rest of the children 8968a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen for (int i = 0; i < count; i++) { 8978a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen final View child = getChildAt(i); 89874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (child.getVisibility() == GONE) { 89974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov continue; 90074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 9018a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // Don't measure the challenge view twice! 9025da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell if (child == mChallengeView) continue; 9035da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell 9045da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell // Measure children. Widget frame measures special, so that we can ignore 9055da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell // insets for the IME. 9065da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell int parentWidthSpec = widthSpec, parentHeightSpec = heightSpec; 9075da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 9085da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) { 9095da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell final View root = getRootView(); 9105da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell if (root != null) { 9115da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell // This calculation is super dodgy and relies on several assumptions. 9125da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell // Specifically that the root of the window will be padded in for insets 9135da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell // and that the window is LAYOUT_IN_SCREEN. 9145da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell final int windowWidth = mDisplayMetrics.widthPixels; 9155da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell final int windowHeight = mDisplayMetrics.heightPixels - root.getPaddingTop(); 9165da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell parentWidthSpec = MeasureSpec.makeMeasureSpec( 9175da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell windowWidth, MeasureSpec.EXACTLY); 9185da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell parentHeightSpec = MeasureSpec.makeMeasureSpec( 9195da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell windowHeight, MeasureSpec.EXACTLY); 9205da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell } 9218a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen } 9225da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell measureChildWithMargins(child, parentWidthSpec, 0, parentHeightSpec, 0); 923d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 924d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 925d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 926d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 927d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected void onLayout(boolean changed, int l, int t, int r, int b) { 928d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingLeft = getPaddingLeft(); 929d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingTop = getPaddingTop(); 930d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingRight = getPaddingRight(); 931d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingBottom = getPaddingBottom(); 932d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int width = r - l; 933d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int height = b - t; 934d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 935d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = getChildCount(); 936d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 937d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View child = getChildAt(i); 938d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 939d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (child.getVisibility() == GONE) continue; 940d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 941d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 942d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 943eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { 944d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Challenge views pin to the bottom, offset by a portion of their height, 945d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // and center horizontally. 946d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int center = (paddingLeft + width - paddingRight) / 2; 947d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childWidth = child.getMeasuredWidth(); 948d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childHeight = child.getMeasuredHeight(); 949d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int left = center - childWidth / 2; 950d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int layoutBottom = height - paddingBottom - lp.bottomMargin; 951d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We use the top of the challenge view to position the handle, so 952d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // we never want less than the handle size showing at the bottom. 95367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound) 954d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * (1 - mChallengeOffset)); 955fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell child.setAlpha(getChallengeAlpha()); 956d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.layout(left, bottom - childHeight, left + childWidth, bottom); 95774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) { 9580f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov final int center = (paddingLeft + width - paddingRight) / 2; 9590f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov final int left = center - child.getMeasuredWidth() / 2; 9600f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov final int right = left + child.getMeasuredWidth(); 9610f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov final int bottom = height - paddingBottom - lp.bottomMargin; 9620f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov final int top = bottom - child.getMeasuredHeight(); 9630f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov child.layout(left, top, right, bottom); 964d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 965d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Non-challenge views lay out from the upper left, layered. 966d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.layout(paddingLeft + lp.leftMargin, 967d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingTop + lp.topMargin, 968d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingLeft + child.getMeasuredWidth(), 969d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingTop + child.getMeasuredHeight()); 970d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 971d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 972d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 973d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (!mHasLayout) { 97467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell if (mFrameDrawable != null) { 97567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mFrameDrawable.setAlpha(0); 97667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell } 9776f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHasLayout = true; 978d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 979d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 980d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 981d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 982d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void draw(Canvas c) { 983d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.draw(c); 9841bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 98574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov final Paint debugPaint = new Paint(); 9861bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0x40FF00CC); 9871bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // show the isInDragHandle() rect 9881bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(mDragHandleEdgeSlop, 989c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mChallengeView.getTop() - getDragHandleSizeAbove(), 9901bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler getWidth() - mDragHandleEdgeSlop, 991c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mChallengeView.getTop() + getDragHandleSizeBelow(), 9921bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint); 9931bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 99474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 9951bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 99674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov public void computeScroll() { 99774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov super.computeScroll(); 9986f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 99974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (!mScroller.isFinished()) { 100074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mChallengeView == null) { 100174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov // Can't scroll if the view is missing. 100274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov Log.e(TAG, "Challenge view missing in computeScroll"); 100374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mScroller.abortAnimation(); 100474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return; 10051bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 10061bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 100774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mScroller.computeScrollOffset(); 100874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov moveChallengeTo(mScroller.getCurrY()); 100974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov 101074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mScroller.isFinished()) { 101174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov post(mEndScrollRunnable); 10126f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1013d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1014d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1015d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 10168caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private void cancelTransitionsInProgress() { 10178caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (!mScroller.isFinished()) { 10188caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mScroller.abortAnimation(); 10198caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen completeChallengeScroll(); 10208caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10218caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (mFader != null) { 10228caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader.cancel(); 10238caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10248caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10258caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10268caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen public void fadeInChallenge() { 10278caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen fadeChallenge(true); 10288caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10298caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10308caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen public void fadeOutChallenge() { 10318caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen fadeChallenge(false); 10328caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10338caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10348caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen public void fadeChallenge(final boolean show) { 10358caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (mChallengeView != null) { 10368caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10378caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen cancelTransitionsInProgress(); 10388caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen float alpha = show ? 1f : 0f; 10398caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen int duration = show ? CHALLENGE_FADE_IN_DURATION : CHALLENGE_FADE_OUT_DURATION; 10408caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader = ObjectAnimator.ofFloat(mChallengeView, "alpha", alpha); 10418caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader.addListener(new AnimatorListenerAdapter() { 10428caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen @Override 10438caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen public void onAnimationStart(Animator animation) { 10448caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen onFadeStart(show); 10458caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10468caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen @Override 10478caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen public void onAnimationEnd(Animator animation) { 10488caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen onFadeEnd(show); 10498caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10508caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen }); 10518caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader.setDuration(duration); 10528caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader.start(); 10538caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10548caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10558caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10568caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private int getMaxChallengeBottom() { 10578caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (mChallengeView == null) return 0; 10588caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen final int layoutBottom = getLayoutBottom(); 10598caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen final int challengeHeight = mChallengeView.getMeasuredHeight(); 10608caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10618caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen return (layoutBottom + challengeHeight - mChallengeBottomBound); 10628caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10638caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10648caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private int getMinChallengeBottom() { 10658caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen return getLayoutBottom(); 10668caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10678caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10688caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10698caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private void onFadeStart(boolean show) { 10708caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mChallengeInteractiveInternal = false; 10718caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); 10728caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10738caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (show) { 10748caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen moveChallengeTo(getMinChallengeBottom()); 10758caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10768caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10778caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen setScrollState(SCROLL_STATE_FADING); 10788caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10798caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10808caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private void onFadeEnd(boolean show) { 10818caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mChallengeInteractiveInternal = true; 10828caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen setChallengeShowing(show); 10838caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10848caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (!show) { 10858caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen moveChallengeTo(getMaxChallengeBottom()); 10868caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10878caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10888caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mChallengeView.setLayerType(LAYER_TYPE_NONE, null); 10898caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader = null; 10908caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen setScrollState(SCROLL_STATE_IDLE); 10918caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10928caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 1093e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen public int getMaxChallengeTop() { 1094e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen if (mChallengeView == null) return 0; 1095e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen 1096e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen final int layoutBottom = getLayoutBottom(); 10978a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen final int challengeHeight = mChallengeView.getMeasuredHeight(); 1098e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen return layoutBottom - challengeHeight; 1099e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen } 1100e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen 1101d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 1102d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Move the bottom edge of mChallengeView to a new position and notify the listener 1103d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * if it represents a change in position. Changes made through this method will 1104d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * be stable across layout passes. If this method is called before first layout of 1105d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * this SlidingChallengeLayout it will have no effect. 1106d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 1107d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system. 1108d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @return true if the challenge view was moved 1109d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 1110d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean moveChallengeTo(int bottom) { 1111d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null || !mHasLayout) { 1112d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return false; 1113d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1114d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1115b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final int layoutBottom = getLayoutBottom(); 1116d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int challengeHeight = mChallengeView.getHeight(); 1117d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 11188caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen bottom = Math.max(getMinChallengeBottom(), 11198caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen Math.min(bottom, getMaxChallengeBottom())); 1120d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 112167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell float offset = 1.f - (float) (bottom - layoutBottom) / 112267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell (challengeHeight - mChallengeBottomBound); 1123d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeOffset = offset; 1124d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (offset > 0 && !mChallengeShowing) { 1125d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(true); 1126d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1127d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1128d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.layout(mChallengeView.getLeft(), 1129d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom); 1130d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1131fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell mChallengeView.setAlpha(getChallengeAlpha()); 11320b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 11330b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop()); 1134d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1135d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller postInvalidateOnAnimation(); 1136d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 1137d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1138d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1139b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 1140b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * The bottom edge of this SlidingChallengeLayout's coordinate system; will coincide with 1141b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * the bottom edge of mChallengeView when the challenge is fully opened. 1142b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 1143b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private int getLayoutBottom() { 1144b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final int bottomMargin = (mChallengeView == null) 1145b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler ? 0 1146b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler : ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin; 11478a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen final int layoutBottom = getMeasuredHeight() - getPaddingBottom() - bottomMargin; 1148b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler return layoutBottom; 1149b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler } 1150b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 1151b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 1152b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * The bottom edge of mChallengeView; essentially, where the sliding challenge 'is'. 1153b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 1154d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int getChallengeBottom() { 1155d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return 0; 1156d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1157d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mChallengeView.getBottom(); 1158d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1159d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1160b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 1161d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Show or hide the challenge view, animating it if necessary. 1162d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param show true to show, false to hide 1163d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 1164d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void showChallenge(boolean show) { 1165d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(show, 0); 1166995270f01175234d0615a0e1900576f142a3b4adAdam Powell if (!show) { 1167995270f01175234d0615a0e1900576f142a3b4adAdam Powell // Block any drags in progress so that callers can use this to disable dragging 1168995270f01175234d0615a0e1900576f142a3b4adAdam Powell // for other touch interactions. 1169995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = true; 1170995270f01175234d0615a0e1900576f142a3b4adAdam Powell } 1171d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1172d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1173d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void showChallenge(int velocity) { 1174d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller boolean show = false; 1175d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (Math.abs(velocity) > mMinVelocity) { 1176d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller show = velocity < 0; 1177d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 1178d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller show = mChallengeOffset >= 0.5f; 1179d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1180d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(show, velocity); 1181d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1182d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1183d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void showChallenge(boolean show, int velocity) { 1184d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 1185d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(false); 1186d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 1187d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1188d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1189d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mHasLayout) { 119067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int layoutBottom = getLayoutBottom(); 1191d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller animateChallengeTo(show ? layoutBottom : 119267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell layoutBottom + mChallengeView.getHeight() - mChallengeBottomBound, velocity); 1193d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1194d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1195d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 119619a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller @Override 1197d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 1198d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return new LayoutParams(getContext(), attrs); 1199d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1200d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1201d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 1202d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 1203d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : 1204d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) : 1205d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller new LayoutParams(p); 1206d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1207d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1208d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 1209d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 1210d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return new LayoutParams(); 1211d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1212d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1213d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 1214d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 1215d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return p instanceof LayoutParams; 1216d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1217d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1218d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static class LayoutParams extends MarginLayoutParams { 1219eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public int childType = CHILD_TYPE_NONE; 1220eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_NONE = 0; 1221eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_CHALLENGE = 2; 1222eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_SCRIM = 4; 1223cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell public static final int CHILD_TYPE_WIDGETS = 5; 122474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov public static final int CHILD_TYPE_EXPAND_CHALLENGE_HANDLE = 6; 1225d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1226d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams() { 1227d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(MATCH_PARENT, WRAP_CONTENT); 1228d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1229d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1230d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(int width, int height) { 1231d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(width, height); 1232d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1233d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1234d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(android.view.ViewGroup.LayoutParams source) { 1235d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 1236d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1237d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1238d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(MarginLayoutParams source) { 1239d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 1240d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1241d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1242d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(LayoutParams source) { 1243d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 1244d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1245eee209313d564be37b8fc068f785b3844cd6597eAdam Powell childType = source.childType; 1246d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1247d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1248d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(Context c, AttributeSet attrs) { 1249d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(c, attrs); 1250d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1251d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final TypedArray a = c.obtainStyledAttributes(attrs, 1252d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller R.styleable.SlidingChallengeLayout_Layout); 1253eee209313d564be37b8fc068f785b3844cd6597eAdam Powell childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType, 1254eee209313d564be37b8fc068f785b3844cd6597eAdam Powell CHILD_TYPE_NONE); 1255d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller a.recycle(); 1256d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1257d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1258d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller} 1259