SlidingChallengeLayout.java revision 03ad0c09502c72c02af464f1e273af3b6ff799cc
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; 29d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.util.AttributeSet; 305da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powellimport android.util.DisplayMetrics; 316f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.util.FloatProperty; 32d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.util.Log; 336f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powellimport android.util.Property; 34d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.MotionEvent; 35d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.VelocityTracker; 36d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.View; 37d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.ViewConfiguration; 38d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.ViewGroup; 3974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganovimport android.view.accessibility.AccessibilityManager; 40d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.view.animation.Interpolator; 41d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Millerimport android.widget.Scroller; 42d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 43d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller/** 44d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * This layout handles interaction with the sliding security challenge views 45d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * that overlay/resize other keyguard contents. 46d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 4719a5267003e7dc70100a4bd4f1f449523b2ff38bJim Millerpublic class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout { 48d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final String TAG = "SlidingChallengeLayout"; 491bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler private static final boolean DEBUG = false; 50d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 51c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // The drag handle is measured in dp above & below the top edge of the 52c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // challenge view; these parameters change based on whether the challenge 53c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // is open or closed. 549c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell private static final int DRAG_HANDLE_CLOSED_ABOVE = 8; // dp 55cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp 56c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp 57c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp 58c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 59c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private static final int HANDLE_ANIMATE_DURATION = 200; // ms 60c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 61d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Drawn to show the drag handle in closed state; crossfades to the challenge view 62d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // when challenge is fully visible 63cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private boolean mEdgeCaptured; 64d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 655da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell private DisplayMetrics mDisplayMetrics; 665da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell 67d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Initialized during measurement from child layoutparams 6874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov private View mExpandChallengeView; 69052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren private KeyguardSecurityContainer mChallengeView; 70eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private View mScrimView; 71cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private View mWidgetsView; 72d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 73d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Range: 0 (fully hidden) to 1 (fully visible) 74d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private float mChallengeOffset = 1.f; 75d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mChallengeShowing = true; 7603ad0c09502c72c02af464f1e273af3b6ff799ccChris Wren private boolean mWasChallengeShowing = true; 77eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private boolean mIsBouncing = false; 78d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 79d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private final Scroller mScroller; 80db1c5d596e91713132131601536aaad32e693325Adam Cohen private ObjectAnimator mFader; 81d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mScrollState; 820b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private OnChallengeScrolledListener mScrollListener; 830b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private OnBouncerStateChangedListener mBouncerListener; 84d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 85d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_IDLE = 0; 86d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_DRAGGING = 1; 87d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static final int SCROLL_STATE_SETTLING = 2; 88db1c5d596e91713132131601536aaad32e693325Adam Cohen public static final int SCROLL_STATE_FADING = 3; 89db1c5d596e91713132131601536aaad32e693325Adam Cohen 908caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private static final int CHALLENGE_FADE_OUT_DURATION = 100; 918caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private static final int CHALLENGE_FADE_IN_DURATION = 160; 92d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 93d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final int MAX_SETTLE_DURATION = 600; // ms 94d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 95d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // ID of the pointer in charge of a current drag 96d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mActivePointerId = INVALID_POINTER; 97d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final int INVALID_POINTER = -1; 98d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 99d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if the user is currently dragging the slider 100d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mDragging; 101d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if the user may not drag until a new gesture begins 102d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mBlockDrag; 103d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 104d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private VelocityTracker mVelocityTracker; 105d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mMinVelocity; 106d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int mMaxVelocity; 107c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private float mGestureStartX, mGestureStartY; // where did you first touch the screen? 108b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private int mGestureStartChallengeBottom; // where was the challenge at that time? 109c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 110c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleClosedBelow; // handle hitrect extension into the challenge view 111c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleClosedAbove; // extend the handle's hitrect this far above the line 112c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleOpenBelow; // handle hitrect extension into the challenge view 113c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mDragHandleOpenAbove; // extend the handle's hitrect this far above the line 114c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 1150b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell private int mDragHandleEdgeSlop; 11667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell private int mChallengeBottomBound; // Number of pixels from the top of the challenge view 11767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell // that should remain on-screen 118c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 119c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int mTouchSlop; 12074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov private int mTouchSlopSquare; 121c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 1226f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell float mHandleAlpha; 1236f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell float mFrameAlpha; 124cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell float mFrameAnimationTarget = Float.MIN_VALUE; 1256f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private ObjectAnimator mHandleAnimation; 1266f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell private ObjectAnimator mFrameAnimation; 1276f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 128cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private boolean mHasGlowpad; 129db1c5d596e91713132131601536aaad32e693325Adam Cohen 130db1c5d596e91713132131601536aaad32e693325Adam Cohen // We have an internal and external version, and we and them together. 131db1c5d596e91713132131601536aaad32e693325Adam Cohen private boolean mChallengeInteractiveExternal = true; 132db1c5d596e91713132131601536aaad32e693325Adam Cohen private boolean mChallengeInteractiveInternal = true; 133cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 1346f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA = 1356f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell new FloatProperty<SlidingChallengeLayout>("handleAlpha") { 1366f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1376f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public void setValue(SlidingChallengeLayout view, float value) { 1386f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.mHandleAlpha = value; 1396f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell view.invalidate(); 1406f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1416f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 1426f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell @Override 1436f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell public Float get(SlidingChallengeLayout view) { 1446f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell return view.mHandleAlpha; 1456f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 1466f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell }; 1476f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 148d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // True if at least one layout pass has happened since the view was attached. 149d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean mHasLayout; 150d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 151d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final Interpolator sMotionInterpolator = new Interpolator() { 152d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public float getInterpolation(float t) { 153d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller t -= 1.0f; 154d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return t * t * t * t * t + 1.0f; 155d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 156d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 157d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 158d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private static final Interpolator sHandleFadeInterpolator = new Interpolator() { 159d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public float getInterpolation(float t) { 160d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return t * t; 161d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 162d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 163d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 164d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private final Runnable mEndScrollRunnable = new Runnable () { 165d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void run() { 166d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller completeChallengeScroll(); 167d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 168d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller }; 169d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 170eee209313d564be37b8fc068f785b3844cd6597eAdam Powell private final OnClickListener mScrimClickListener = new OnClickListener() { 171eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 172eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void onClick(View v) { 173eee209313d564be37b8fc068f785b3844cd6597eAdam Powell hideBouncer(); 174eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 175eee209313d564be37b8fc068f785b3844cd6597eAdam Powell }; 176eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 17774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov private final OnClickListener mExpandChallengeClickListener = new OnClickListener() { 17874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov @Override 17974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov public void onClick(View v) { 18078a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock if (!isChallengeShowing()) { 18174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov showChallenge(true); 18274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 18374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 18474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov }; 18574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov 186d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 187d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Listener interface that reports changes in scroll state of the challenge area. 188d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 189d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public interface OnChallengeScrolledListener { 190d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 191d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * The scroll state itself changed. 192d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 193d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>scrollState will be one of the following:</p> 194d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 195d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <ul> 196d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li> 197d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging 198d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * the challenge area.</li> 199d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating 200d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * into place.</li> 201d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * </ul> 202d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 203d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>Do not perform expensive operations (e.g. layout) 204d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p> 205d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 206d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param scrollState The new scroll state of the challenge area. 207d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 208d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onScrollStateChanged(int scrollState); 209d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 210d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 211d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * The precise position of the challenge area has changed. 212d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 213d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * <p>NOTE: It is NOT safe to modify layout or call any View methods that may 214d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * result in a requestLayout anywhere in your view hierarchy as a result of this call. 215d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * It may be called during drawing.</p> 216d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 217d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param scrollPosition New relative position of the challenge area. 218d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 1.f = fully visible/ready to be interacted with. 219d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 0.f = fully invisible/inaccessible to the user. 220d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param challengeTop Position of the top edge of the challenge view in px in the 221d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * SlidingChallengeLayout's coordinate system. 222d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 223d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onScrollPositionChanged(float scrollPosition, int challengeTop); 224d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 225d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 226d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context) { 227d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(context, null); 228d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 229d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 230d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context, AttributeSet attrs) { 231d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(context, attrs, 0); 232d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 233d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 234d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) { 235d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(context, attrs, defStyle); 236d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 237d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller = new Scroller(context, sMotionInterpolator); 238d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 239d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final ViewConfiguration vc = ViewConfiguration.get(context); 240d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mMinVelocity = vc.getScaledMinimumFlingVelocity(); 241d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mMaxVelocity = vc.getScaledMaximumFlingVelocity(); 242d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 243fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell final Resources res = getResources(); 244fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell mDragHandleEdgeSlop = res.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size); 2450b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 246c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 24774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mTouchSlopSquare = mTouchSlop * mTouchSlop; 248c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 2495da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell mDisplayMetrics = res.getDisplayMetrics(); 2505da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell final float density = mDisplayMetrics.density; 2511bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 2521bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // top half of the lock icon, plus another 25% to be sure 253c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f); 254c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleClosedBelow = (int) (DRAG_HANDLE_CLOSED_BELOW * density + 0.5f); 255c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleOpenAbove = (int) (DRAG_HANDLE_OPEN_ABOVE * density + 0.5f); 256c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f); 257c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler 258c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler // how much space to account for in the handle when closed 259fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell mChallengeBottomBound = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding); 2601bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 261cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell setWillNotDraw(false); 262cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell } 263cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell 2646e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock public void setHandleAlpha(float alpha) { 2656e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock if (mExpandChallengeView != null) { 2666e36f1019cb6d7098b49e036e1640c8cfc6880cfJohn Spurlock mExpandChallengeView.setAlpha(alpha); 2676f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2686f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2696f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 270bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock public void setChallengeInteractive(boolean interactive) { 271db1c5d596e91713132131601536aaad32e693325Adam Cohen mChallengeInteractiveExternal = interactive; 27278a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock if (mExpandChallengeView != null) { 27378a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock mExpandChallengeView.setEnabled(interactive); 27478a8f126a9af0c4994188adeba1b955b5d4afd28John Spurlock } 275bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock } 276bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock 2776f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell void animateHandle(boolean visible) { 2786f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (mHandleAnimation != null) { 2796f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.cancel(); 28067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mHandleAnimation = null; 281d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 28267625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final float targetAlpha = visible ? 1.f : 0.f; 28367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell if (targetAlpha == mHandleAlpha) { 28467625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell return; 28567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell } 28667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, targetAlpha); 2876f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.setInterpolator(sHandleFadeInterpolator); 2886f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION); 2896f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHandleAnimation.start(); 2906f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 2916f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 292d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void sendInitialListenerUpdates() { 2930b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 294d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0; 2950b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop); 2960b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollStateChanged(mScrollState); 297d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 298d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 299d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 300d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) { 3010b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener = listener; 302d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mHasLayout) { 303d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller sendInitialListenerUpdates(); 304d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 305d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 306d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3070b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) { 3080b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener = listener; 3090b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3100b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 311d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 312d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onAttachedToWindow() { 313d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.onAttachedToWindow(); 314d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 315d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHasLayout = false; 316d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 317d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 318d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 319d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void onDetachedFromWindow() { 320d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.onDetachedFromWindow(); 321d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 322d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller removeCallbacks(mEndScrollRunnable); 323d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mHasLayout = false; 324d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 325d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3260b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell @Override 3270b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell public void requestChildFocus(View child, View focused) { 3280b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mIsBouncing && child != mChallengeView) { 3290b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell // Clear out of the bouncer if the user tries to move focus outside of 3300b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell // the security challenge view. 3310b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell hideBouncer(); 3320b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3330b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell super.requestChildFocus(child, focused); 3340b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 3350b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell 336d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We want the duration of the page snap animation to be influenced by the distance that 337d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // the screen has to travel, however, we don't want this duration to be effected in a 338d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // purely linear fashion. Instead, we use this method to moderate the effect that the distance 339d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // of travel has on the overall snap duration. 340d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller float distanceInfluenceForSnapDuration(float f) { 341d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller f -= 0.5f; // center the values about 0. 342d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller f *= 0.3f * Math.PI / 2.0f; 343d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return (float) Math.sin(f); 344d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 345d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 346d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void setScrollState(int state) { 347d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mScrollState != state) { 348d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScrollState = state; 349d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 3506f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing); 3510b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 3520b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollStateChanged(state); 353d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 354d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 355d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 356d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 357d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void completeChallengeScroll() { 358d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(mChallengeOffset != 0); 359d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_IDLE); 360db1c5d596e91713132131601536aaad32e693325Adam Cohen mChallengeInteractiveInternal = true; 361cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setLayerType(LAYER_TYPE_NONE, null); 362d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 363d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 364eee209313d564be37b8fc068f785b3844cd6597eAdam Powell void setScrimView(View scrim) { 365eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 366eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setOnClickListener(null); 367eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 368eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView = scrim; 369eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE); 370eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setFocusable(true); 371eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setOnClickListener(mScrimClickListener); 372eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 373eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 374d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 375d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Animate the bottom edge of the challenge view to the given position. 376d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 377d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param y desired final position for the bottom edge of the challenge view in px 378d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param velocity velocity in 379d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 380d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller void animateChallengeTo(int y, int velocity) { 381d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 382d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Nothing to do. 383d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 384d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 385db1c5d596e91713132131601536aaad32e693325Adam Cohen 3868caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen cancelTransitionsInProgress(); 387db1c5d596e91713132131601536aaad32e693325Adam Cohen 388db1c5d596e91713132131601536aaad32e693325Adam Cohen mChallengeInteractiveInternal = false; 389db1c5d596e91713132131601536aaad32e693325Adam Cohen mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); 39067625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int sy = mChallengeView.getBottom(); 39167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int dy = y - sy; 392d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (dy == 0) { 393d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller completeChallengeScroll(); 394d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 395d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 396d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 397d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_SETTLING); 398d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 399d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childHeight = mChallengeView.getHeight(); 400d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int halfHeight = childHeight / 2; 401d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight); 402d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float distance = halfHeight + halfHeight * 403d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller distanceInfluenceForSnapDuration(distanceRatio); 404d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 405d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller int duration = 0; 406d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller velocity = Math.abs(velocity); 407d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (velocity > 0) { 408d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); 409d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 410d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float childDelta = (float) Math.abs(dy) / childHeight; 411d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = (int) ((childDelta + 1) * 100); 412d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 413d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller duration = Math.min(duration, MAX_SETTLE_DURATION); 414d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 415d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mScroller.startScroll(0, sy, 0, dy, duration); 416d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller postInvalidateOnAnimation(); 417d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 418d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 419d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void setChallengeShowing(boolean showChallenge) { 42074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mChallengeShowing == showChallenge) { 42174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return; 42274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 42367625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell mChallengeShowing = showChallenge; 4245a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell 4255a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell if (mExpandChallengeView == null || mChallengeView == null) { 4265a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell // These might not be here yet if we haven't been through layout. 4275a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell // If we haven't, the first layout pass will set everything up correctly 4285a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell // based on mChallengeShowing as set above. 4295a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell return; 4305a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell } 4315a2c5f0efacf5f11a928c8481f6747c3d13ddcfdAdam Powell 43274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mChallengeShowing) { 43374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView.setVisibility(View.INVISIBLE); 43474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mChallengeView.setVisibility(View.VISIBLE); 43574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 43674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mChallengeView.requestAccessibilityFocus(); 43774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mChallengeView.announceForAccessibility(mContext.getString( 43874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov R.string.keyguard_accessibility_unlock_area_expanded)); 43974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 44074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } else { 44174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView.setVisibility(View.VISIBLE); 44274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mChallengeView.setVisibility(View.INVISIBLE); 44374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 44474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView.requestAccessibilityFocus(); 44574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mChallengeView.announceForAccessibility(mContext.getString( 44674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov R.string.keyguard_accessibility_unlock_area_collapsed)); 44774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 44874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 449d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 450d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 451d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 452d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @return true if the challenge is at all visible. 453d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 454d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean isChallengeShowing() { 455d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mChallengeShowing; 456d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 457d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 458d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 45919a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller public boolean isChallengeOverlapping() { 46019a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller return mChallengeShowing; 46119a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller } 46219a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller 46319a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller @Override 464eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public boolean isBouncing() { 465eee209313d564be37b8fc068f785b3844cd6597eAdam Powell return mIsBouncing; 466eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 467eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 468eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 469eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void showBouncer() { 470eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mIsBouncing) return; 47103ad0c09502c72c02af464f1e273af3b6ff799ccChris Wren mWasChallengeShowing = mChallengeShowing; 47248275d2de99ff2556031929c48f295d3f93447b6Winson Chung showChallenge(true); 47303ad0c09502c72c02af464f1e273af3b6ff799ccChris Wren mIsBouncing = true; 474eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 4756f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mScrimView.setVisibility(VISIBLE); 476eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 477052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren if (mChallengeView != null) { 478052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren mChallengeView.showBouncer(HANDLE_ANIMATE_DURATION); 479052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren } 480cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // Mess with padding/margin to inset the bouncer frame. 481cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // We have more space available to us otherwise. 482cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (mChallengeView != null) { 483cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams(); 484cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell lp.leftMargin = lp.rightMargin = getChallengeMargin(false); 485cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setLayoutParams(lp); 486cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 487cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 4880b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mBouncerListener != null) { 4890b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener.onBouncerStateChanged(true); 4900b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 491eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 492eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 493eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 494eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public void hideBouncer() { 495eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (!mIsBouncing) return; 49603ad0c09502c72c02af464f1e273af3b6ff799ccChris Wren if (!mWasChallengeShowing) showChallenge(false); 497eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mIsBouncing = false; 498eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (mScrimView != null) { 499eee209313d564be37b8fc068f785b3844cd6597eAdam Powell mScrimView.setVisibility(GONE); 500eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 501052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren if (mChallengeView != null) { 502052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren mChallengeView.hideBouncer(HANDLE_ANIMATE_DURATION); 503052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren } 5040b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mBouncerListener != null) { 5050b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mBouncerListener.onBouncerStateChanged(false); 5060b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell } 507eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } 508eee209313d564be37b8fc068f785b3844cd6597eAdam Powell 509cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private int getChallengeMargin(boolean expanded) { 510cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop; 511cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 512cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 513fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell private float getChallengeAlpha() { 514fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell float x = mChallengeOffset - 1; 515fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell return x * x * x + 1.f; 516fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell } 517fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell 518eee209313d564be37b8fc068f785b3844cd6597eAdam Powell @Override 519d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void requestDisallowInterceptTouchEvent(boolean allowIntercept) { 520d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We'll intercept whoever we feel like! ...as long as it isn't a challenge view. 521d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // If there are one or more pointers in the challenge view before we take over 522d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // touch events, onInterceptTouchEvent will set mBlockDrag. 523d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 524d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 525d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 526d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean onInterceptTouchEvent(MotionEvent ev) { 527d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mVelocityTracker == null) { 528d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = VelocityTracker.obtain(); 529d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 530d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.addMovement(ev); 531d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 532d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int action = ev.getActionMasked(); 533d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller switch (action) { 534022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller case MotionEvent.ACTION_DOWN: 535c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = ev.getX(); 536b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartY = ev.getY(); 537995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = false; 538022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller break; 539022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 540d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_CANCEL: 541d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_UP: 542d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 543d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 544d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 545d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_MOVE: 546d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = ev.getPointerCount(); 547d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 548d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float x = ev.getX(i); 549d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float y = ev.getY(i); 550db1c5d596e91713132131601536aaad32e693325Adam Cohen if (!mIsBouncing && mActivePointerId == INVALID_POINTER 5519c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell && (crossedDragHandle(x, y, mGestureStartY) 552c238af5112bee38b3143a65849bd41785c3744b0Adam Powell || (isInChallengeView(x, y) && 5539c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell mScrollState == SCROLL_STATE_SETTLING))) { 554d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = ev.getPointerId(i); 555c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = x; 556c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartY = y; 557b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartChallengeBottom = getChallengeBottom(); 558d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = true; 559cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); 5609c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell } else if (mChallengeShowing && isInChallengeView(x, y)) { 561d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mBlockDrag = true; 562d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 563d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 564d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 565d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 566d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 567db1c5d596e91713132131601536aaad32e693325Adam Cohen if (mBlockDrag || isChallengeInteractionBlocked()) { 568d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = INVALID_POINTER; 569d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = false; 570d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 571d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 572d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mDragging; 573d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 574d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 575db1c5d596e91713132131601536aaad32e693325Adam Cohen private boolean isChallengeInteractionBlocked() { 576db1c5d596e91713132131601536aaad32e693325Adam Cohen return !mChallengeInteractiveExternal || !mChallengeInteractiveInternal; 577db1c5d596e91713132131601536aaad32e693325Adam Cohen } 578db1c5d596e91713132131601536aaad32e693325Adam Cohen 579d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void resetTouch() { 580d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.recycle(); 581d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = null; 582d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = INVALID_POINTER; 583d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = mBlockDrag = false; 584d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 585d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 586d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 587d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public boolean onTouchEvent(MotionEvent ev) { 588d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mVelocityTracker == null) { 589d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker = VelocityTracker.obtain(); 590d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 591d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.addMovement(ev); 592d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 593d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int action = ev.getActionMasked(); 594d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller switch (action) { 595995270f01175234d0615a0e1900576f142a3b4adAdam Powell case MotionEvent.ACTION_DOWN: 596995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = false; 597c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = ev.getX(); 598995270f01175234d0615a0e1900576f142a3b4adAdam Powell mGestureStartY = ev.getY(); 599995270f01175234d0615a0e1900576f142a3b4adAdam Powell break; 600995270f01175234d0615a0e1900576f142a3b4adAdam Powell 601d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_CANCEL: 602db1c5d596e91713132131601536aaad32e693325Adam Cohen if (mDragging && !isChallengeInteractionBlocked()) { 603d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(0); 604d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 605d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 606d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 607d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 608d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_POINTER_UP: 609d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) { 610d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 611d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 612d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_UP: 613db1c5d596e91713132131601536aaad32e693325Adam Cohen if (mDragging && !isChallengeInteractionBlocked()) { 614d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); 615d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId)); 616d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 617d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 618d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 619d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 620d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller case MotionEvent.ACTION_MOVE: 6216f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell if (!mDragging && !mBlockDrag && !mIsBouncing) { 622d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = ev.getPointerCount(); 623d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 624d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float x = ev.getX(i); 625d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final float y = ev.getY(i); 626d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 627b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) || 628d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) 6291ec464679f731827f626856084f19643fff64a94John Spurlock && mActivePointerId == INVALID_POINTER 630db1c5d596e91713132131601536aaad32e693325Adam Cohen && !isChallengeInteractionBlocked()) { 631c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mGestureStartX = x; 632b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartY = y; 633d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mActivePointerId = ev.getPointerId(i); 634b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler mGestureStartChallengeBottom = getChallengeBottom(); 635d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mDragging = true; 636cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); 637d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 638d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 639d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 640d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 641d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Not an else; this can be set above. 642d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mDragging) { 643d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // No-op if already in this state, but set it here in case we arrived 644d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // at this point from either intercept or the above. 645d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setScrollState(SCROLL_STATE_DRAGGING); 646d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 647d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int index = ev.findPointerIndex(mActivePointerId); 648d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (index < 0) { 649d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Oops, bogus state. We lost some touch events somewhere. 650d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Just drop it with no velocity and let things settle. 651d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller resetTouch(); 652d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(0); 653d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 654d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 655b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final float y = ev.getY(index); 656b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final float pos = Math.min(y - mGestureStartY, 65767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell getLayoutBottom() - mChallengeBottomBound); 658b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 659b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler moveChallengeTo(mGestureStartChallengeBottom + (int) pos); 660d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 661d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller break; 662d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 663d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 664d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 665d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 666b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 667cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell * The lifecycle of touch events is subtle and it's very easy to do something 668cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell * that will cause bugs that will be nasty to track when overriding this method. 669cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell * Normally one should always override onInterceptTouchEvent instead. 670cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell * 671cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell * To put it another way, don't try this at home. 672cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell */ 673cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell @Override 674cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell public boolean dispatchTouchEvent(MotionEvent ev) { 675cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell final int action = ev.getActionMasked(); 676cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell boolean handled = false; 677cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (action == MotionEvent.ACTION_DOWN) { 678cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // Defensive programming: if we didn't get the UP or CANCEL, reset anyway. 679cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mEdgeCaptured = false; 680cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 681cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) { 682cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // Normally we would need to do a lot of extra stuff here. 683cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // We can only get away with this because we haven't padded in 684cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // the widget pager or otherwise transformed it during layout. 685cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // We also don't support things like splitting MotionEvents. 686cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 687cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // We set handled to captured even if dispatch is returning false here so that 688cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // we don't send a different view a busted or incomplete event stream. 689cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev); 690cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 691cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 692cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (!handled && !mEdgeCaptured) { 693cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell handled = super.dispatchTouchEvent(ev); 694cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 695cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 696cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { 697cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mEdgeCaptured = false; 698cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 699cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 700cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell return handled; 701cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 702cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 703cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell private boolean isEdgeSwipeBeginEvent(MotionEvent ev) { 704cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) { 705cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell return false; 706cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 707cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 708cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell final float x = ev.getX(); 709cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop; 710cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 711cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell 712cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell /** 713b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * We only want to add additional vertical space to the drag handle when the panel is fully 714b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * closed. 715b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 716c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int getDragHandleSizeAbove() { 717c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler return isChallengeShowing() ? mDragHandleOpenAbove : mDragHandleClosedAbove; 718c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler } 719c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler private int getDragHandleSizeBelow() { 720c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler return isChallengeShowing() ? mDragHandleOpenBelow : mDragHandleClosedBelow; 721b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler } 722b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 723d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean isInChallengeView(float x, float y) { 72474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return isPointInView(x, y, mChallengeView); 725d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 726d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 727d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean isInDragHandle(float x, float y) { 72874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return isPointInView(x, y, mExpandChallengeView); 72974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 730d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 73174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov private boolean isPointInView(float x, float y, View view) { 73274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (view == null) { 73374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return false; 73474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 73574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return x >= view.getLeft() && y >= view.getTop() 73674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov && x < view.getRight() && y < view.getBottom(); 737d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 738d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 739b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private boolean crossedDragHandle(float x, float y, float initialY) { 7409c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell 741022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller final int challengeTop = mChallengeView.getTop(); 7429c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell final boolean horizOk = x >= 0 && x < getWidth(); 7439c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell 7449c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell final boolean vertOk; 7459c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell if (mChallengeShowing) { 7469c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell vertOk = initialY < (challengeTop - getDragHandleSizeAbove()) && 7479c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell y > challengeTop + getDragHandleSizeBelow(); 7489c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell } else { 7499c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell vertOk = initialY > challengeTop + getDragHandleSizeBelow() && 7509c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell y < challengeTop - getDragHandleSizeAbove(); 7519c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell } 7529c2c77f8bd8288dcafc9f8111396d46b896d1933Adam Powell return horizOk && vertOk; 753022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller } 754022554e3da6e496524387a5d3ecc67ef9749b587Jim Miller 755d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 756d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected void onMeasure(int widthSpec, int heightSpec) { 757d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY || 758d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) { 759d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller throw new IllegalArgumentException( 760d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller "SlidingChallengeLayout must be measured with an exact size"); 761d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 762d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 763d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int width = MeasureSpec.getSize(widthSpec); 764d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int height = MeasureSpec.getSize(heightSpec); 765d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setMeasuredDimension(width, height); 766d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 767d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Find one and only one challenge view. 768d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View oldChallengeView = mChallengeView; 76974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov final View oldExpandChallengeView = mChallengeView; 770d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView = null; 77174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView = null; 772d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = getChildCount(); 7738a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen 7748a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // First iteration through the children finds special children and sets any associated 7758a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // state. 776d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 777d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View child = getChildAt(i); 778d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 779eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { 780d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != null) { 781d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller throw new IllegalStateException( 782d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller "There may only be one child with layout_isChallenge=\"true\""); 783d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 784052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren if (!(child instanceof KeyguardSecurityContainer)) { 785052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren throw new IllegalArgumentException( 786052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren "Challenge must be a KeyguardSecurityContainer"); 787052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren } 788052999f3c94df2659e6e3e7730a2810980f718f7Chris Wren mChallengeView = (KeyguardSecurityContainer) child; 789d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView != oldChallengeView) { 790d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE); 791d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 7926f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell // We're going to play silly games with the frame's background drawable later. 793cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell if (!mHasLayout) { 794cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell // Set up the margin correctly based on our content for the first run. 795cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null; 796cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell lp.leftMargin = lp.rightMargin = getChallengeMargin(true); 797cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } 79874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) { 79974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mExpandChallengeView != null) { 80074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov throw new IllegalStateException( 80174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov "There may only be one child with layout_childType" 80274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov + "=\"expandChallengeHandle\""); 80374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 80474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView = child; 80574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mExpandChallengeView != oldExpandChallengeView) { 80674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView.setVisibility(mChallengeShowing ? INVISIBLE : VISIBLE); 80774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mExpandChallengeView.setOnClickListener(mExpandChallengeClickListener); 80874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 809eee209313d564be37b8fc068f785b3844cd6597eAdam Powell } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) { 810eee209313d564be37b8fc068f785b3844cd6597eAdam Powell setScrimView(child); 811cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) { 812cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell mWidgetsView = child; 813d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 8148a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen } 8158a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen 8165be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen // We want to measure the challenge view first, since the KeyguardWidgetPager 8175be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen // needs to do things its measure pass that are dependent on the challenge view 8185be14ded6762bc51fabbbecb1b2ec01a8c758631Adam Cohen // having been measured. 81974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mChallengeView != null && mChallengeView.getVisibility() != View.GONE) { 8208a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen measureChildWithMargins(mChallengeView, widthSpec, 0, heightSpec, 0); 8218a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen } 822d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 8238a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // Measure the rest of the children 8248a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen for (int i = 0; i < count; i++) { 8258a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen final View child = getChildAt(i); 82674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (child.getVisibility() == GONE) { 82774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov continue; 82874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 8298a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen // Don't measure the challenge view twice! 8305da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell if (child == mChallengeView) continue; 8315da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell 8325da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell // Measure children. Widget frame measures special, so that we can ignore 8335da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell // insets for the IME. 8345da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell int parentWidthSpec = widthSpec, parentHeightSpec = heightSpec; 8355da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 8365da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) { 8375da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell final View root = getRootView(); 8385da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell if (root != null) { 8395da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell // This calculation is super dodgy and relies on several assumptions. 8405da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell // Specifically that the root of the window will be padded in for insets 8415da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell // and that the window is LAYOUT_IN_SCREEN. 8425da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell final int windowWidth = mDisplayMetrics.widthPixels; 8435da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell final int windowHeight = mDisplayMetrics.heightPixels - root.getPaddingTop(); 8445da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell parentWidthSpec = MeasureSpec.makeMeasureSpec( 8455da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell windowWidth, MeasureSpec.EXACTLY); 8465da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell parentHeightSpec = MeasureSpec.makeMeasureSpec( 8475da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell windowHeight, MeasureSpec.EXACTLY); 8485da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell } 8498a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen } 8505da6430fff7812e58ee7e9a05c62d72c36f366c8Adam Powell measureChildWithMargins(child, parentWidthSpec, 0, parentHeightSpec, 0); 851d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 852d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 853d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 854d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 855d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected void onLayout(boolean changed, int l, int t, int r, int b) { 856d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingLeft = getPaddingLeft(); 857d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingTop = getPaddingTop(); 858d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingRight = getPaddingRight(); 859d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int paddingBottom = getPaddingBottom(); 860d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int width = r - l; 861d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int height = b - t; 862d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 863d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int count = getChildCount(); 864d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller for (int i = 0; i < count; i++) { 865d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final View child = getChildAt(i); 866d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 867d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (child.getVisibility() == GONE) continue; 868d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 869d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 870d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 871eee209313d564be37b8fc068f785b3844cd6597eAdam Powell if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) { 872d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Challenge views pin to the bottom, offset by a portion of their height, 873d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // and center horizontally. 874d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int center = (paddingLeft + width - paddingRight) / 2; 875d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childWidth = child.getMeasuredWidth(); 876d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int childHeight = child.getMeasuredHeight(); 877d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int left = center - childWidth / 2; 878d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int layoutBottom = height - paddingBottom - lp.bottomMargin; 879d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // We use the top of the challenge view to position the handle, so 880d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // we never want less than the handle size showing at the bottom. 88167625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound) 882d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * (1 - mChallengeOffset)); 883fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell child.setAlpha(getChallengeAlpha()); 884d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.layout(left, bottom - childHeight, left + childWidth, bottom); 88574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) { 8860f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov final int center = (paddingLeft + width - paddingRight) / 2; 8870f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov final int left = center - child.getMeasuredWidth() / 2; 8880f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov final int right = left + child.getMeasuredWidth(); 8890f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov final int bottom = height - paddingBottom - lp.bottomMargin; 8900f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov final int top = bottom - child.getMeasuredHeight(); 8910f87a72d59a224c819e18cfed4374f4d484198d6Svetoslav Ganov child.layout(left, top, right, bottom); 892d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 893d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller // Non-challenge views lay out from the upper left, layered. 894d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller child.layout(paddingLeft + lp.leftMargin, 895d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingTop + lp.topMargin, 896d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingLeft + child.getMeasuredWidth(), 897d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller paddingTop + child.getMeasuredHeight()); 898d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 899d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 900d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 901d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (!mHasLayout) { 9026f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell mHasLayout = true; 903d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 904d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 905d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 906d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 907d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void draw(Canvas c) { 908d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super.draw(c); 9091bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler if (DEBUG) { 91074bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov final Paint debugPaint = new Paint(); 9111bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint.setColor(0x40FF00CC); 9121bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler // show the isInDragHandle() rect 9131bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler c.drawRect(mDragHandleEdgeSlop, 914c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mChallengeView.getTop() - getDragHandleSizeAbove(), 9151bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler getWidth() - mDragHandleEdgeSlop, 916c606bf1af953bb8a682589a29809e714c648c291Daniel Sandler mChallengeView.getTop() + getDragHandleSizeBelow(), 9171bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler debugPaint); 9181bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 91974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov } 9201bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 92174bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov public void computeScroll() { 92274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov super.computeScroll(); 9236f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell 92474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (!mScroller.isFinished()) { 92574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mChallengeView == null) { 92674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov // Can't scroll if the view is missing. 92774bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov Log.e(TAG, "Challenge view missing in computeScroll"); 92874bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mScroller.abortAnimation(); 92974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov return; 9301bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler } 9311bfcc82184824c8dc648a0948303f4b3611ac087Daniel Sandler 93274bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov mScroller.computeScrollOffset(); 93374bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov moveChallengeTo(mScroller.getCurrY()); 93474bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov 93574bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov if (mScroller.isFinished()) { 93674bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov post(mEndScrollRunnable); 9376f35209e728a7a9a56afbbdefd3d7bfa1e05ea73Adam Powell } 938d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 939d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 940d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 9418caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private void cancelTransitionsInProgress() { 9428caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (!mScroller.isFinished()) { 9438caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mScroller.abortAnimation(); 9448caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen completeChallengeScroll(); 9458caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9468caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (mFader != null) { 9478caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader.cancel(); 9488caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9498caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9508caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 9518caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen public void fadeInChallenge() { 9528caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen fadeChallenge(true); 9538caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9548caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 9558caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen public void fadeOutChallenge() { 9568caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen fadeChallenge(false); 9578caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9588caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 9598caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen public void fadeChallenge(final boolean show) { 9608caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (mChallengeView != null) { 9618caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 9628caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen cancelTransitionsInProgress(); 9638caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen float alpha = show ? 1f : 0f; 9648caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen int duration = show ? CHALLENGE_FADE_IN_DURATION : CHALLENGE_FADE_OUT_DURATION; 9658caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader = ObjectAnimator.ofFloat(mChallengeView, "alpha", alpha); 9668caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader.addListener(new AnimatorListenerAdapter() { 9678caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen @Override 9688caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen public void onAnimationStart(Animator animation) { 9698caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen onFadeStart(show); 9708caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9718caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen @Override 9728caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen public void onAnimationEnd(Animator animation) { 9738caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen onFadeEnd(show); 9748caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9758caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen }); 9768caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader.setDuration(duration); 9778caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader.start(); 9788caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9798caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9808caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 9818caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private int getMaxChallengeBottom() { 9828caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (mChallengeView == null) return 0; 9838caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen final int layoutBottom = getLayoutBottom(); 9848caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen final int challengeHeight = mChallengeView.getMeasuredHeight(); 9858caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 9868caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen return (layoutBottom + challengeHeight - mChallengeBottomBound); 9878caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9888caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 9898caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private int getMinChallengeBottom() { 9908caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen return getLayoutBottom(); 9918caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 9928caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 9938caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 9948caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private void onFadeStart(boolean show) { 9958caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mChallengeInteractiveInternal = false; 9968caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null); 9978caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 9988caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (show) { 9998caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen moveChallengeTo(getMinChallengeBottom()); 10008caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10018caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10028caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen setScrollState(SCROLL_STATE_FADING); 10038caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10048caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10058caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen private void onFadeEnd(boolean show) { 10068caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mChallengeInteractiveInternal = true; 10078caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen setChallengeShowing(show); 10088caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10098caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen if (!show) { 10108caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen moveChallengeTo(getMaxChallengeBottom()); 10118caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10128caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 10138caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mChallengeView.setLayerType(LAYER_TYPE_NONE, null); 10148caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen mFader = null; 10158caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen setScrollState(SCROLL_STATE_IDLE); 10168caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen } 10178caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen 1018e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen public int getMaxChallengeTop() { 1019e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen if (mChallengeView == null) return 0; 1020e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen 1021e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen final int layoutBottom = getLayoutBottom(); 10228a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen final int challengeHeight = mChallengeView.getMeasuredHeight(); 1023e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen return layoutBottom - challengeHeight; 1024e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen } 1025e3643138c89d49a01ba6a622ffaf71c9a95d5cdcAdam Cohen 1026d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller /** 1027d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Move the bottom edge of mChallengeView to a new position and notify the listener 1028d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * if it represents a change in position. Changes made through this method will 1029d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * be stable across layout passes. If this method is called before first layout of 1030d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * this SlidingChallengeLayout it will have no effect. 1031d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * 1032d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system. 1033d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @return true if the challenge view was moved 1034d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 1035d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private boolean moveChallengeTo(int bottom) { 1036d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null || !mHasLayout) { 1037d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return false; 1038d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1039d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1040b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final int layoutBottom = getLayoutBottom(); 1041d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final int challengeHeight = mChallengeView.getHeight(); 1042d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 10438caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen bottom = Math.max(getMinChallengeBottom(), 10448caabadd02c7bef701c44dc1718a9a493cbd1261Adam Cohen Math.min(bottom, getMaxChallengeBottom())); 1045d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 104667625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell float offset = 1.f - (float) (bottom - layoutBottom) / 104767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell (challengeHeight - mChallengeBottomBound); 1048d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeOffset = offset; 1049d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (offset > 0 && !mChallengeShowing) { 1050d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(true); 1051d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1052d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1053d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller mChallengeView.layout(mChallengeView.getLeft(), 1054d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom); 1055d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1056fa668cc930544e8b231c1fbf3ad496374b7aa21cAdam Powell mChallengeView.setAlpha(getChallengeAlpha()); 10570b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell if (mScrollListener != null) { 10580b1b552268bc6641cc5d01fb80c12258da9c6985Adam Powell mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop()); 1059d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1060d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller postInvalidateOnAnimation(); 1061d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return true; 1062d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1063d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1064b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 1065b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * The bottom edge of this SlidingChallengeLayout's coordinate system; will coincide with 1066b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * the bottom edge of mChallengeView when the challenge is fully opened. 1067b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 1068b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler private int getLayoutBottom() { 1069b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler final int bottomMargin = (mChallengeView == null) 1070b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler ? 0 1071b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler : ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin; 10728a7785c7aa2df74203276299e10b0d9056cd0560Adam Cohen final int layoutBottom = getMeasuredHeight() - getPaddingBottom() - bottomMargin; 1073b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler return layoutBottom; 1074b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler } 1075b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler 1076b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 1077b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler * The bottom edge of mChallengeView; essentially, where the sliding challenge 'is'. 1078b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler */ 1079d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private int getChallengeBottom() { 1080d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) return 0; 1081d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1082d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return mChallengeView.getBottom(); 1083d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1084d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1085b42b842ee873160acf317fc3ff6339243514b008Daniel Sandler /** 1086d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * Show or hide the challenge view, animating it if necessary. 1087d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller * @param show true to show, false to hide 1088d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller */ 1089d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public void showChallenge(boolean show) { 1090d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(show, 0); 1091995270f01175234d0615a0e1900576f142a3b4adAdam Powell if (!show) { 1092995270f01175234d0615a0e1900576f142a3b4adAdam Powell // Block any drags in progress so that callers can use this to disable dragging 1093995270f01175234d0615a0e1900576f142a3b4adAdam Powell // for other touch interactions. 1094995270f01175234d0615a0e1900576f142a3b4adAdam Powell mBlockDrag = true; 1095995270f01175234d0615a0e1900576f142a3b4adAdam Powell } 1096d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1097d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1098d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void showChallenge(int velocity) { 1099d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller boolean show = false; 1100d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (Math.abs(velocity) > mMinVelocity) { 1101d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller show = velocity < 0; 1102d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } else { 1103d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller show = mChallengeOffset >= 0.5f; 1104d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1105d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller showChallenge(show, velocity); 1106d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1107d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1108d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller private void showChallenge(boolean show, int velocity) { 1109d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mChallengeView == null) { 1110d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller setChallengeShowing(false); 1111d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return; 1112d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1113d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1114d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller if (mHasLayout) { 111567625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell final int layoutBottom = getLayoutBottom(); 1116d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller animateChallengeTo(show ? layoutBottom : 111767625e29208a97afeb8dca22a73c52ad7b4619baAdam Powell layoutBottom + mChallengeView.getHeight() - mChallengeBottomBound, velocity); 1118d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1119d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1120d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 112119a5267003e7dc70100a4bd4f1f449523b2ff38bJim Miller @Override 1122d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 1123d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return new LayoutParams(getContext(), attrs); 1124d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1125d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1126d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 1127d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 1128d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) : 1129d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) : 1130d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller new LayoutParams(p); 1131d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1132d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1133d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 1134d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 1135d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return new LayoutParams(); 1136d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1137d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1138d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller @Override 1139d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 1140d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller return p instanceof LayoutParams; 1141d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1142d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1143d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public static class LayoutParams extends MarginLayoutParams { 1144eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public int childType = CHILD_TYPE_NONE; 1145eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_NONE = 0; 1146eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_CHALLENGE = 2; 1147eee209313d564be37b8fc068f785b3844cd6597eAdam Powell public static final int CHILD_TYPE_SCRIM = 4; 1148cdf8b487456115a1bcc626f53b8da63308dc42ddAdam Powell public static final int CHILD_TYPE_WIDGETS = 5; 114974bdd21629681528dbe7f3ea363d99c8514e026bSvetoslav Ganov public static final int CHILD_TYPE_EXPAND_CHALLENGE_HANDLE = 6; 1150d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1151d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams() { 1152d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller this(MATCH_PARENT, WRAP_CONTENT); 1153d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1154d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1155d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(int width, int height) { 1156d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(width, height); 1157d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1158d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1159d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(android.view.ViewGroup.LayoutParams source) { 1160d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 1161d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1162d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1163d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(MarginLayoutParams source) { 1164d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 1165d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1166d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1167d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(LayoutParams source) { 1168d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(source); 1169d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1170eee209313d564be37b8fc068f785b3844cd6597eAdam Powell childType = source.childType; 1171d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1172d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1173d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller public LayoutParams(Context c, AttributeSet attrs) { 1174d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller super(c, attrs); 1175d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller 1176d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller final TypedArray a = c.obtainStyledAttributes(attrs, 1177d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller R.styleable.SlidingChallengeLayout_Layout); 1178eee209313d564be37b8fc068f785b3844cd6597eAdam Powell childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType, 1179eee209313d564be37b8fc068f785b3844cd6597eAdam Powell CHILD_TYPE_NONE); 1180d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller a.recycle(); 1181d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1182d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller } 1183d6523da1ad7bae805a3dbea8d7b398d86cd3c181Jim Miller} 1184