19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1975986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.R;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
2275986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.graphics.Bitmap;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
2775986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.os.SystemClock;
2875986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.util.AttributeSet;
2975986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.view.MotionEvent;
3075986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.view.SoundEffectConstants;
3175986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.view.VelocityTracker;
3275986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.view.View;
3375986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.view.ViewGroup;
3475986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganovimport android.view.accessibility.AccessibilityEvent;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SlidingDrawer hides content out of the screen and allows the user to drag a handle
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to bring the content on screen. SlidingDrawer can be used vertically or horizontally.
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A special widget composed of two children views: the handle, that the users drags,
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and the content, attached to the handle and dragged with it.
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * SlidingDrawer should be used as an overlay inside layouts. This means SlidingDrawer
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * should only be used inside of a FrameLayout or a RelativeLayout for instance. The
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * size of the SlidingDrawer defines how much space the content will occupy once slid
46980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy * out so SlidingDrawer should usually use match_parent for both its dimensions.
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Inside an XML layout, SlidingDrawer must define the id of the handle and of the
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * content:
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre class="prettyprint">
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * &lt;SlidingDrawer
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     android:id="@+id/drawer"
54980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy *     android:layout_width="match_parent"
55980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy *     android:layout_height="match_parent"
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     android:handle="@+id/handle"
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     android:content="@+id/content"&gt;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     &lt;ImageView
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *         android:id="@id/handle"
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *         android:layout_width="88dip"
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *         android:layout_height="44dip" /&gt;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *     &lt;GridView
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *         android:id="@id/content"
67980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy *         android:layout_width="match_parent"
68980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy *         android:layout_height="match_parent" /&gt;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * &lt;/SlidingDrawer&gt;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </pre>
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#SlidingDrawer_content
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#SlidingDrawer_handle
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#SlidingDrawer_topOffset
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#SlidingDrawer_bottomOffset
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#SlidingDrawer_orientation
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#SlidingDrawer_allowSingleTap
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#SlidingDrawer_animateOnClick
8086ca5d35139db0eccc2babcca5bf835f8c2b019fRomain Guy *
8186ca5d35139db0eccc2babcca5bf835f8c2b019fRomain Guy * @deprecated This class is not supported anymore. It is recommended you
8286ca5d35139db0eccc2babcca5bf835f8c2b019fRomain Guy * base your own implementation on the source code for the Android Open
8386ca5d35139db0eccc2babcca5bf835f8c2b019fRomain Guy * Source Project if you must use it in your application.
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
8586ca5d35139db0eccc2babcca5bf835f8c2b019fRomain Guy@Deprecated
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class SlidingDrawer extends ViewGroup {
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int ORIENTATION_HORIZONTAL = 0;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int ORIENTATION_VERTICAL = 1;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TAP_THRESHOLD = 6;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final float MAXIMUM_TAP_VELOCITY = 100.0f;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final float MAXIMUM_MINOR_VELOCITY = 150.0f;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final float MAXIMUM_MAJOR_VELOCITY = 200.0f;
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final float MAXIMUM_ACCELERATION = 2000.0f;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int VELOCITY_UNITS = 1000;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int ANIMATION_FRAME_DURATION = 1000 / 60;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int EXPANDED_FULL_OPEN = -10001;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int COLLAPSED_FULL_CLOSED = -10002;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mHandleId;
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mContentId;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View mHandle;
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private View mContent;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Rect mFrame = new Rect();
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Rect mInvalidate = new Rect();
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mTracking;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mLocked;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VelocityTracker mVelocityTracker;
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mVertical;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mExpanded;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mBottomOffset;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mTopOffset;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mHandleHeight;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mHandleWidth;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private OnDrawerOpenListener mOnDrawerOpenListener;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private OnDrawerCloseListener mOnDrawerCloseListener;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private OnDrawerScrollListener mOnDrawerScrollListener;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float mAnimatedAcceleration;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float mAnimatedVelocity;
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private float mAnimationPosition;
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mAnimationLastTime;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mCurrentAnimationTime;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mTouchDelta;
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mAnimating;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mAllowSingleTap;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mAnimateOnClick;
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mTapThreshold;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mMaximumTapVelocity;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mMaximumMinorVelocity;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mMaximumMajorVelocity;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mMaximumAcceleration;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mVelocityUnits;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Callback invoked when the drawer is opened.
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static interface OnDrawerOpenListener {
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Invoked when the drawer becomes fully open.
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onDrawerOpened();
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Callback invoked when the drawer is closed.
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static interface OnDrawerCloseListener {
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Invoked when the drawer becomes fully closed.
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onDrawerClosed();
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Callback invoked when the drawer is scrolled.
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static interface OnDrawerScrollListener {
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Invoked when the user starts dragging/flinging the drawer's handle.
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onScrollStarted();
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Invoked when the user stops dragging/flinging the drawer's handle.
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onScrollEnded();
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a new SlidingDrawer from a specified set of attributes defined in XML.
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context The application's environment.
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param attrs The attributes defined in XML.
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SlidingDrawer(Context context, AttributeSet attrs) {
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, attrs, 0);
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a new SlidingDrawer from a specified set of attributes defined in XML.
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context The application's environment.
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param attrs The attributes defined in XML.
192617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
193617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
194617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
196617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public SlidingDrawer(Context context, AttributeSet attrs, int defStyleAttr) {
197617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
198617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
199617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
200617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    /**
201617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * Creates a new SlidingDrawer from a specified set of attributes defined in XML.
202617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *
203617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param context The application's environment.
204617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param attrs The attributes defined in XML.
205617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
206617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
207617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
208617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleRes A resource identifier of a style resource that
209617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        supplies default values for the view, used only if
210617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        defStyleAttr is 0 or can not be found in the theme. Can be 0
211617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        to not look for defaults.
212617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     */
213617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public SlidingDrawer(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
214617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
215617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
216617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(
217617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                attrs, R.styleable.SlidingDrawer, defStyleAttr, defStyleRes);
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int orientation = a.getInt(R.styleable.SlidingDrawer_orientation, ORIENTATION_VERTICAL);
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVertical = orientation == ORIENTATION_VERTICAL;
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBottomOffset = (int) a.getDimension(R.styleable.SlidingDrawer_bottomOffset, 0.0f);
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTopOffset = (int) a.getDimension(R.styleable.SlidingDrawer_topOffset, 0.0f);
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAllowSingleTap = a.getBoolean(R.styleable.SlidingDrawer_allowSingleTap, true);
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimateOnClick = a.getBoolean(R.styleable.SlidingDrawer_animateOnClick, true);
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int handleId = a.getResourceId(R.styleable.SlidingDrawer_handle, 0);
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (handleId == 0) {
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("The handle attribute is required and must refer "
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + "to a valid child.");
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int contentId = a.getResourceId(R.styleable.SlidingDrawer_content, 0);
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (contentId == 0) {
2348a342a3cc07162cdb5458692f04fbc677802919eRomain Guy            throw new IllegalArgumentException("The content attribute is required and must refer "
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + "to a valid child.");
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2388a342a3cc07162cdb5458692f04fbc677802919eRomain Guy        if (handleId == contentId) {
2398a342a3cc07162cdb5458692f04fbc677802919eRomain Guy            throw new IllegalArgumentException("The content and handle attributes must refer "
2408a342a3cc07162cdb5458692f04fbc677802919eRomain Guy                    + "to different children.");
2418a342a3cc07162cdb5458692f04fbc677802919eRomain Guy        }
2428a342a3cc07162cdb5458692f04fbc677802919eRomain Guy
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandleId = handleId;
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContentId = contentId;
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final float density = getResources().getDisplayMetrics().density;
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTapThreshold = (int) (TAP_THRESHOLD * density + 0.5f);
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMaximumTapVelocity = (int) (MAXIMUM_TAP_VELOCITY * density + 0.5f);
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMaximumMinorVelocity = (int) (MAXIMUM_MINOR_VELOCITY * density + 0.5f);
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMaximumMajorVelocity = (int) (MAXIMUM_MAJOR_VELOCITY * density + 0.5f);
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMaximumAcceleration = (int) (MAXIMUM_ACCELERATION * density + 0.5f);
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVelocityUnits = (int) (VELOCITY_UNITS * density + 0.5f);
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setAlwaysDrawnWithCacheEnabled(false);
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onFinishInflate() {
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandle = findViewById(mHandleId);
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mHandle == null) {
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("The handle attribute is must refer to an"
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " existing child.");
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandle.setOnClickListener(new DrawerToggler());
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContent = findViewById(mContentId);
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContent == null) {
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("The content attribute is must refer to an"
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " existing child.");
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContent.setVisibility(View.GONE);
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int widthSpecSize =  MeasureSpec.getSize(widthMeasureSpec);
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException("SlidingDrawer cannot have UNSPECIFIED dimensions");
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View handle = mHandle;
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        measureChild(handle, widthMeasureSpec, heightMeasureSpec);
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mVertical) {
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int height = heightSpecSize - handle.getMeasuredHeight() - mTopOffset;
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContent.measure(MeasureSpec.makeMeasureSpec(widthSpecSize, MeasureSpec.EXACTLY),
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int width = widthSpecSize - handle.getMeasuredWidth() - mTopOffset;
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContent.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MeasureSpec.makeMeasureSpec(heightSpecSize, MeasureSpec.EXACTLY));
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setMeasuredDimension(widthSpecSize, heightSpecSize);
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dispatchDraw(Canvas canvas) {
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long drawingTime = getDrawingTime();
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View handle = mHandle;
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean isVertical = mVertical;
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        drawChild(canvas, handle, drawingTime);
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTracking || mAnimating) {
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Bitmap cache = mContent.getDrawingCache();
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cache != null) {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isVertical) {
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    canvas.drawBitmap(cache, 0, handle.getBottom(), null);
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    canvas.drawBitmap(cache, handle.getRight(), 0, null);
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                canvas.save();
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                canvas.translate(isVertical ? 0 : handle.getLeft() - mTopOffset,
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        isVertical ? handle.getTop() - mTopOffset : 0);
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                drawChild(canvas, mContent, drawingTime);
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                canvas.restore();
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (mExpanded) {
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            drawChild(canvas, mContent, drawingTime);
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onLayout(boolean changed, int l, int t, int r, int b) {
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTracking) {
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int width = r - l;
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int height = b - t;
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View handle = mHandle;
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childWidth = handle.getMeasuredWidth();
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childHeight = handle.getMeasuredHeight();
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childLeft;
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int childTop;
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View content = mContent;
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mVertical) {
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childLeft = (width - childWidth) / 2;
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childTop = mExpanded ? mTopOffset : height - childHeight + mBottomOffset;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            content.layout(0, mTopOffset + childHeight, content.getMeasuredWidth(),
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mTopOffset + childHeight + content.getMeasuredHeight());
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childLeft = mExpanded ? mTopOffset : width - childWidth + mBottomOffset;
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childTop = (height - childHeight) / 2;
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            content.layout(mTopOffset + childWidth, 0,
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mTopOffset + childWidth + content.getMeasuredWidth(),
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    content.getMeasuredHeight());
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        handle.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandleHeight = handle.getHeight();
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandleWidth = handle.getWidth();
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onInterceptTouchEvent(MotionEvent event) {
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mLocked) {
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int action = event.getAction();
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float x = event.getX();
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float y = event.getY();
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Rect frame = mFrame;
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View handle = mHandle;
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        handle.getHitRect(frame);
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mTracking && !frame.contains((int) x, (int) y)) {
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (action == MotionEvent.ACTION_DOWN) {
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTracking = true;
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handle.setPressed(true);
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Must be called before prepareTracking()
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            prepareContent();
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
397c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            // Must be called after prepareContent()
398c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            if (mOnDrawerScrollListener != null) {
399c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                mOnDrawerScrollListener.onScrollStarted();
400c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project            }
401c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mVertical) {
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int top = mHandle.getTop();
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTouchDelta = (int) y - top;
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                prepareTracking(top);
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int left = mHandle.getLeft();
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTouchDelta = (int) x - left;
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                prepareTracking(left);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mVelocityTracker.addMovement(event);
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onTouchEvent(MotionEvent event) {
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mLocked) {
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTracking) {
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mVelocityTracker.addMovement(event);
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int action = event.getAction();
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (action) {
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MotionEvent.ACTION_MOVE:
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    moveHandle((int) (mVertical ? event.getY() : event.getX()) - mTouchDelta);
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MotionEvent.ACTION_UP:
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MotionEvent.ACTION_CANCEL: {
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final VelocityTracker velocityTracker = mVelocityTracker;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    velocityTracker.computeCurrentVelocity(mVelocityUnits);
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    float yVelocity = velocityTracker.getYVelocity();
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    float xVelocity = velocityTracker.getXVelocity();
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    boolean negative;
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final boolean vertical = mVertical;
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (vertical) {
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        negative = yVelocity < 0;
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (xVelocity < 0) {
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            xVelocity = -xVelocity;
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (xVelocity > mMaximumMinorVelocity) {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            xVelocity = mMaximumMinorVelocity;
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        negative = xVelocity < 0;
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (yVelocity < 0) {
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            yVelocity = -yVelocity;
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (yVelocity > mMaximumMinorVelocity) {
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            yVelocity = mMaximumMinorVelocity;
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    float velocity = (float) Math.hypot(xVelocity, yVelocity);
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (negative) {
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        velocity = -velocity;
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final int top = mHandle.getTop();
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final int left = mHandle.getLeft();
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (Math.abs(velocity) < mMaximumTapVelocity) {
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (vertical ? (mExpanded && top < mTapThreshold + mTopOffset) ||
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                (!mExpanded && top > mBottomOffset + mBottom - mTop -
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        mHandleHeight - mTapThreshold) :
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                (mExpanded && left < mTapThreshold + mTopOffset) ||
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                (!mExpanded && left > mBottomOffset + mRight - mLeft -
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        mHandleWidth - mTapThreshold)) {
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (mAllowSingleTap) {
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                playSoundEffect(SoundEffectConstants.CLICK);
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (mExpanded) {
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    animateClose(vertical ? top : left);
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                } else {
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    animateOpen(vertical ? top : left);
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
482c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                            } else {
483c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project                                performFling(vertical ? top : left, velocity, false);
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            performFling(vertical ? top : left, velocity, false);
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        performFling(vertical ? top : left, velocity, false);
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mTracking || mAnimating || super.onTouchEvent(event);
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void animateClose(int position) {
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        prepareTracking(position);
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        performFling(position, mMaximumAcceleration, true);
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void animateOpen(int position) {
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        prepareTracking(position);
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        performFling(position, -mMaximumAcceleration, true);
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void performFling(int position, float velocity, boolean always) {
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimationPosition = position;
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimatedVelocity = velocity;
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mExpanded) {
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (always || (velocity > mMaximumMajorVelocity ||
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (position > mTopOffset + (mVertical ? mHandleHeight : mHandleWidth) &&
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            velocity > -mMaximumMajorVelocity))) {
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We are expanded, but they didn't move sufficiently to cause
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // us to retract.  Animate back to the expanded position.
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAnimatedAcceleration = mMaximumAcceleration;
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (velocity < 0) {
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mAnimatedVelocity = 0;
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We are expanded and are now going to animate away.
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAnimatedAcceleration = -mMaximumAcceleration;
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (velocity > 0) {
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mAnimatedVelocity = 0;
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!always && (velocity > mMaximumMajorVelocity ||
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (position > (mVertical ? getHeight() : getWidth()) / 2 &&
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            velocity > -mMaximumMajorVelocity))) {
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We are collapsed, and they moved enough to allow us to expand.
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAnimatedAcceleration = mMaximumAcceleration;
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (velocity < 0) {
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mAnimatedVelocity = 0;
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We are collapsed, but they didn't move sufficiently to cause
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // us to retract.  Animate back to the collapsed position.
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAnimatedAcceleration = -mMaximumAcceleration;
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (velocity > 0) {
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mAnimatedVelocity = 0;
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long now = SystemClock.uptimeMillis();
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimationLastTime = now;
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimating = true;
554d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck        removeCallbacks(mSlidingRunnable);
555d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck        postDelayed(mSlidingRunnable, ANIMATION_FRAME_DURATION);
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        stopTracking();
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void prepareTracking(int position) {
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTracking = true;
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVelocityTracker = VelocityTracker.obtain();
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean opening = !mExpanded;
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (opening) {
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAnimatedAcceleration = mMaximumAcceleration;
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAnimatedVelocity = mMaximumMajorVelocity;
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAnimationPosition = mBottomOffset +
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (mVertical ? getHeight() - mHandleHeight : getWidth() - mHandleWidth);
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            moveHandle((int) mAnimationPosition);
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAnimating = true;
570d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            removeCallbacks(mSlidingRunnable);
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long now = SystemClock.uptimeMillis();
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAnimationLastTime = now;
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAnimating = true;
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mAnimating) {
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAnimating = false;
578d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck                removeCallbacks(mSlidingRunnable);
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            moveHandle(position);
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void moveHandle(int position) {
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View handle = mHandle;
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mVertical) {
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (position == EXPANDED_FULL_OPEN) {
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handle.offsetTopAndBottom(mTopOffset - handle.getTop());
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invalidate();
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (position == COLLAPSED_FULL_CLOSED) {
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handle.offsetTopAndBottom(mBottomOffset + mBottom - mTop -
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mHandleHeight - handle.getTop());
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invalidate();
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int top = handle.getTop();
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int deltaY = position - top;
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (position < mTopOffset) {
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    deltaY = mTopOffset - top;
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (deltaY > mBottomOffset + mBottom - mTop - mHandleHeight - top) {
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    deltaY = mBottomOffset + mBottom - mTop - mHandleHeight - top;
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handle.offsetTopAndBottom(deltaY);
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Rect frame = mFrame;
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Rect region = mInvalidate;
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handle.getHitRect(frame);
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                region.set(frame);
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                region.union(frame.left, frame.top - deltaY, frame.right, frame.bottom - deltaY);
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                region.union(0, frame.bottom - deltaY, getWidth(),
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        frame.bottom - deltaY + mContent.getHeight());
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invalidate(region);
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (position == EXPANDED_FULL_OPEN) {
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handle.offsetLeftAndRight(mTopOffset - handle.getLeft());
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invalidate();
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (position == COLLAPSED_FULL_CLOSED) {
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handle.offsetLeftAndRight(mBottomOffset + mRight - mLeft -
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mHandleWidth - handle.getLeft());
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invalidate();
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int left = handle.getLeft();
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int deltaX = position - left;
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (position < mTopOffset) {
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    deltaX = mTopOffset - left;
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (deltaX > mBottomOffset + mRight - mLeft - mHandleWidth - left) {
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    deltaX = mBottomOffset + mRight - mLeft - mHandleWidth - left;
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handle.offsetLeftAndRight(deltaX);
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Rect frame = mFrame;
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final Rect region = mInvalidate;
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handle.getHitRect(frame);
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                region.set(frame);
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                region.union(frame.left - deltaX, frame.top, frame.right - deltaX, frame.bottom);
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                region.union(frame.right - deltaX, 0,
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        frame.right - deltaX + mContent.getWidth(), getHeight());
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                invalidate(region);
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void prepareContent() {
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAnimating) {
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Something changed in the content, we need to honor the layout request
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // before creating the cached bitmap
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final View content = mContent;
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (content.isLayoutRequested()) {
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mVertical) {
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int childHeight = mHandleHeight;
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int height = mBottom - mTop - childHeight - mTopOffset;
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                content.measure(MeasureSpec.makeMeasureSpec(mRight - mLeft, MeasureSpec.EXACTLY),
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                content.layout(0, mTopOffset + childHeight, content.getMeasuredWidth(),
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mTopOffset + childHeight + content.getMeasuredHeight());
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int childWidth = mHandle.getWidth();
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int width = mRight - mLeft - childWidth - mTopOffset;
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                content.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        MeasureSpec.makeMeasureSpec(mBottom - mTop, MeasureSpec.EXACTLY));
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                content.layout(childWidth + mTopOffset, 0,
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mTopOffset + childWidth + content.getMeasuredWidth(),
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        content.getMeasuredHeight());
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Try only once... we should really loop but it's not a big deal
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // if the draw was cancelled, it will only be temporary anyway
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        content.getViewTreeObserver().dispatchOnPreDraw();
6790d9275e565551eed57297627188aa39f3897a50bRomain Guy        if (!content.isHardwareAccelerated()) content.buildDrawingCache();
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        content.setVisibility(View.GONE);
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void stopTracking() {
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandle.setPressed(false);
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTracking = false;
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mOnDrawerScrollListener != null) {
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mOnDrawerScrollListener.onScrollEnded();
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mVelocityTracker != null) {
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mVelocityTracker.recycle();
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mVelocityTracker = null;
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void doAnimation() {
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAnimating) {
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            incrementAnimation();
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mAnimationPosition >= mBottomOffset + (mVertical ? getHeight() : getWidth()) - 1) {
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAnimating = false;
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                closeDrawer();
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (mAnimationPosition < mTopOffset) {
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAnimating = false;
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                openDrawer();
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                moveHandle((int) mAnimationPosition);
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mCurrentAnimationTime += ANIMATION_FRAME_DURATION;
710d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck                postDelayed(mSlidingRunnable, ANIMATION_FRAME_DURATION);
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void incrementAnimation() {
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long now = SystemClock.uptimeMillis();
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float t = (now - mAnimationLastTime) / 1000.0f;                   // ms -> s
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final float position = mAnimationPosition;
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final float v = mAnimatedVelocity;                                // px/s
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final float a = mAnimatedAcceleration;                            // px/s/s
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimationPosition = position + (v * t) + (0.5f * a * t * t);     // px
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimatedVelocity = v + (a * t);                                  // px/s
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimationLastTime = now;                                         // ms
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Toggles the drawer open and close. Takes effect immediately.
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #open()
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #close()
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateClose()
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateOpen()
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateToggle()
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void toggle() {
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mExpanded) {
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            openDrawer();
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            closeDrawer();
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        invalidate();
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        requestLayout();
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Toggles the drawer open and close with an animation.
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #open()
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #close()
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateClose()
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateOpen()
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #toggle()
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void animateToggle() {
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mExpanded) {
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            animateOpen();
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            animateClose();
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Opens the drawer immediately.
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #toggle()
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #close()
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateOpen()
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void open() {
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        openDrawer();
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        invalidate();
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        requestLayout();
77375986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov
77475986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Closes the drawer immediately.
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #toggle()
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #open()
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateClose()
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void close() {
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        closeDrawer();
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        invalidate();
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        requestLayout();
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Closes the drawer with an animation.
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #close()
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #open()
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateOpen()
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateToggle()
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #toggle()
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void animateClose() {
800c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        prepareContent();
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (scrollListener != null) {
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollListener.onScrollStarted();
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        animateClose(mVertical ? mHandle.getTop() : mHandle.getLeft());
80675986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (scrollListener != null) {
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollListener.onScrollEnded();
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Opens the drawer with an animation.
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #close()
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #open()
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateClose()
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #animateToggle()
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #toggle()
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void animateOpen() {
822c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project        prepareContent();
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (scrollListener != null) {
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollListener.onScrollStarted();
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        animateOpen(mVertical ? mHandle.getTop() : mHandle.getLeft());
82875986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov
82975986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
83075986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (scrollListener != null) {
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            scrollListener.onScrollEnded();
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8368a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
837a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn    public CharSequence getAccessibilityClassName() {
838a7bb6fbeab933326d58aa806d8194b7b13239d34Dianne Hackborn        return SlidingDrawer.class.getName();
8398a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
8408a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void closeDrawer() {
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        moveHandle(COLLAPSED_FULL_CLOSED);
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContent.setVisibility(View.GONE);
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContent.destroyDrawingCache();
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mExpanded) {
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mExpanded = false;
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mOnDrawerCloseListener != null) {
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mOnDrawerCloseListener.onDrawerClosed();
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void openDrawer() {
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        moveHandle(EXPANDED_FULL_OPEN);
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContent.setVisibility(View.VISIBLE);
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mExpanded) {
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mExpanded = true;
86575986cf9bc57ef11ad70f36fb77fbbf5d63af6ecsvetoslavganov
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mOnDrawerOpenListener != null) {
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mOnDrawerOpenListener.onDrawerOpened();
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the listener that receives a notification when the drawer becomes open.
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param onDrawerOpenListener The listener to be notified when the drawer is opened.
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setOnDrawerOpenListener(OnDrawerOpenListener onDrawerOpenListener) {
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOnDrawerOpenListener = onDrawerOpenListener;
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the listener that receives a notification when the drawer becomes close.
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param onDrawerCloseListener The listener to be notified when the drawer is closed.
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setOnDrawerCloseListener(OnDrawerCloseListener onDrawerCloseListener) {
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOnDrawerCloseListener = onDrawerCloseListener;
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the listener that receives a notification when the drawer starts or ends
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a scroll. A fling is considered as a scroll. A fling will also trigger a
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * drawer opened or drawer closed event.
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param onDrawerScrollListener The listener to be notified when scrolling
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        starts or stops.
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setOnDrawerScrollListener(OnDrawerScrollListener onDrawerScrollListener) {
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOnDrawerScrollListener = onDrawerScrollListener;
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the handle of the drawer.
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The View reprenseting the handle of the drawer, identified by
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         the "handle" id in XML.
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public View getHandle() {
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mHandle;
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the content of the drawer.
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The View reprenseting the content of the drawer, identified by
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         the "content" id in XML.
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public View getContent() {
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mContent;
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Unlocks the SlidingDrawer so that touch events are processed.
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #lock()
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unlock() {
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLocked = false;
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Locks the SlidingDrawer so that touch events are ignores.
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #unlock()
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void lock() {
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLocked = true;
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Indicates whether the drawer is currently fully opened.
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return True if the drawer is opened, false otherwise.
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isOpened() {
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mExpanded;
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Indicates whether the drawer is scrolling or flinging.
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return True if the drawer is scroller or flinging, false otherwise.
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isMoving() {
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mTracking || mAnimating;
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class DrawerToggler implements OnClickListener {
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onClick(View v) {
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mLocked) {
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // mAllowSingleTap isn't relevant here; you're *always*
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // allowed to open/close the drawer by clicking with the
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // trackball.
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mAnimateOnClick) {
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                animateToggle();
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                toggle();
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
974d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck    private final Runnable mSlidingRunnable = new Runnable() {
975d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck        @Override
976d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck        public void run() {
977d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            doAnimation();
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
979d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck    };
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
981