11d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell/*
21d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * Copyright (C) 2013 The Android Open Source Project
31d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell *
41d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * Licensed under the Apache License, Version 2.0 (the "License");
51d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * you may not use this file except in compliance with the License.
61d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * You may obtain a copy of the License at
71d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell *
81d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell *      http://www.apache.org/licenses/LICENSE-2.0
91d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell *
101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * Unless required by applicable law or agreed to in writing, software
111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * distributed under the License is distributed on an "AS IS" BASIS,
121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * See the License for the specific language governing permissions and
141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * limitations under the License.
151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell */
161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellpackage android.support.v4.widget;
191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.content.Context;
211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.content.res.TypedArray;
221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.graphics.Canvas;
231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.graphics.Paint;
24b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powellimport android.graphics.PixelFormat;
253cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powellimport android.graphics.Rect;
26b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powellimport android.graphics.drawable.Drawable;
2757902cff6c54c245feea589b06d12dba8f1a2a24Adam Powellimport android.os.Parcel;
2857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powellimport android.os.Parcelable;
29cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powellimport android.os.SystemClock;
307d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powellimport android.support.v4.view.AccessibilityDelegateCompat;
311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.support.v4.view.GravityCompat;
32791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powellimport android.support.v4.view.KeyEventCompat;
331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.support.v4.view.MotionEventCompat;
341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.support.v4.view.ViewCompat;
351b8262b87426b2f766b40d6ab4eaeac296d5c2feAdam Powellimport android.support.v4.view.ViewGroupCompat;
367d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powellimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.util.AttributeSet;
381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.view.Gravity;
39791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powellimport android.view.KeyEvent;
401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.view.MotionEvent;
411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.view.View;
421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.view.ViewGroup;
433cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powellimport android.view.ViewParent;
447d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powellimport android.view.accessibility.AccessibilityEvent;
451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell/**
471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * DrawerLayout acts as a top-level container for window content that allows for
481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * interactive "drawer" views to be pulled out from the edge of the window.
491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell *
501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * <p>Drawer positioning and layout is controlled using the <code>android:layout_gravity</code>
5109c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * attribute on child views corresponding to which side of the view you want the drawer
5209c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * to emerge from: left or right. (Or start/end on platform versions that support layout direction.)
5309c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * </p>
5409c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell *
5509c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * <p>To use a DrawerLayout, position your primary content view as the first child with
5609c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * a width and height of <code>match_parent</code>. Add drawers as child views after the main
5709c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * content view and set the <code>layout_gravity</code> appropriately. Drawers commonly use
5809c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * <code>match_parent</code> for height with a fixed width.</p>
5909c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell *
6009c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * <p>{@link DrawerListener} can be used to monitor the state and motion of drawer views.
6109c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * Avoid performing expensive operations such as layout during animation as it can cause
6209c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * stuttering; try to perform expensive operations during the {@link #STATE_IDLE} state.
6309c38625b5400dcda3d872dbe865c867cc02e5ebAdam Powell * {@link SimpleDrawerListener} offers default/no-op implementations of each callback method.</p>
641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell *
651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * <p>As per the Android Design guide, any drawers positioned to the left/start should
661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * always contain content for navigating around the application, whereas any drawers
671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * positioned to the right/end should always contain actions to take on the current content.
681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * This preserves the same navigation left, actions right structure present in the Action Bar
691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * and elsewhere.</p>
701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell */
711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellpublic class DrawerLayout extends ViewGroup {
721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private static final String TAG = "DrawerLayout";
731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Indicates that any drawers are in an idle, settled state. No animation is in progress.
761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;
781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Indicates that a drawer is currently being dragged by the user.
811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;
831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Indicates that a drawer is in the process of settling to a final position.
861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;
881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
890492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    /**
900492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * The drawer is unlocked.
910492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     */
920492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    public static final int LOCK_MODE_UNLOCKED = 0;
930492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell
940492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    /**
950492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * The drawer is locked closed. The user may not open it, though
960492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * the app may open it programmatically.
970492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     */
980492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    public static final int LOCK_MODE_LOCKED_CLOSED = 1;
990492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell
1000492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    /**
1010492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * The drawer is locked open. The user may not close it, though the app
1020492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * may close it programmatically.
1030492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     */
1040492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    public static final int LOCK_MODE_LOCKED_OPEN = 2;
1050492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell
1061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private static final int MIN_DRAWER_MARGIN = 64; // dp
1071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private static final int DEFAULT_SCRIM_COLOR = 0x99000000;
1091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
110ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell    /**
1111732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell     * Length of time to delay before peeking the drawer.
1121732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell     */
1131732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell    private static final int PEEK_DELAY = 160; // ms
1141732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell
1151732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell    /**
11679f95ce3e660d267831067e514ff455156c4381fAdam Powell     * Minimum velocity that will be detected as a fling
11779f95ce3e660d267831067e514ff455156c4381fAdam Powell     */
11879f95ce3e660d267831067e514ff455156c4381fAdam Powell    private static final int MIN_FLING_VELOCITY = 400; // dips per second
11979f95ce3e660d267831067e514ff455156c4381fAdam Powell
12079f95ce3e660d267831067e514ff455156c4381fAdam Powell    /**
121ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell     * Experimental feature.
122ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell     */
123ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell    private static final boolean ALLOW_EDGE_LOCK = false;
124ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell
12586559d86173efb890a8edf48d935cfebfaccf049Adam Powell    private static final boolean CHILDREN_DISALLOW_INTERCEPT = true;
12686559d86173efb890a8edf48d935cfebfaccf049Adam Powell
12786559d86173efb890a8edf48d935cfebfaccf049Adam Powell    private static final float TOUCH_SLOP_SENSITIVITY = 1.f;
12886559d86173efb890a8edf48d935cfebfaccf049Adam Powell
1291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private static final int[] LAYOUT_ATTRS = new int[] {
1301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            android.R.attr.layout_gravity
1311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    };
1321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private int mMinDrawerMargin;
1341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private int mScrimColor = DEFAULT_SCRIM_COLOR;
1361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private float mScrimOpacity;
1371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private Paint mScrimPaint = new Paint();
1381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private final ViewDragHelper mLeftDragger;
1401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private final ViewDragHelper mRightDragger;
1411732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell    private final ViewDragCallback mLeftCallback;
1421732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell    private final ViewDragCallback mRightCallback;
1431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private int mDrawerState;
144b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    private boolean mInLayout;
14557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    private boolean mFirstLayout = true;
1460492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    private int mLockModeLeft;
1470492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    private int mLockModeRight;
1481732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell    private boolean mDisallowInterceptRequested;
149cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell    private boolean mChildrenCanceledTouch;
1501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private DrawerListener mListener;
1521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private float mInitialMotionX;
1541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private float mInitialMotionY;
1551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
156b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    private Drawable mShadowLeft;
157b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    private Drawable mShadowRight;
158b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
1591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
1601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Listener for monitoring events about drawers.
1611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
1621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public interface DrawerListener {
1631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        /**
1641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * Called when a drawer's position changes.
1651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * @param drawerView The child view that was moved
1661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * @param slideOffset The new offset of this drawer within its range, from 0-1
1671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         */
1681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onDrawerSlide(View drawerView, float slideOffset);
1691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        /**
1711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * Called when a drawer has settled in a completely open state.
1721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * The drawer is interactive at this point.
1731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         *
1741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * @param drawerView Drawer view that is now open
1751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         */
1761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onDrawerOpened(View drawerView);
1771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        /**
1791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * Called when a drawer has settled in a completely closed state.
1801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         *
1811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * @param drawerView Drawer view that is now closed
1821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         */
1831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onDrawerClosed(View drawerView);
1841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        /**
1861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * Called when the drawer motion state changes. The new state will
1871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * be one of {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
1881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         *
1891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * @param newState The new drawer motion state
1901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         */
1911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onDrawerStateChanged(int newState);
1921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
1931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
194b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    /**
195b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * Stub/no-op implementations of all methods of {@link DrawerListener}.
196b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * Override this if you only care about a few of the available callback methods.
197b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     */
198b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    public static abstract class SimpleDrawerListener implements DrawerListener {
199b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        @Override
200b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        public void onDrawerSlide(View drawerView, float slideOffset) {
201b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
202b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
203b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        @Override
204b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        public void onDrawerOpened(View drawerView) {
205b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
206b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
207b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        @Override
208b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        public void onDrawerClosed(View drawerView) {
209b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
210b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
211b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        @Override
212b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        public void onDrawerStateChanged(int newState) {
213b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
214b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    }
215b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
2161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public DrawerLayout(Context context) {
2171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        this(context, null);
2181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public DrawerLayout(Context context, AttributeSet attrs) {
2211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        this(context, attrs, 0);
2221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public DrawerLayout(Context context, AttributeSet attrs, int defStyle) {
2251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        super(context, attrs, defStyle);
2261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final float density = getResources().getDisplayMetrics().density;
2281d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f);
22979f95ce3e660d267831067e514ff455156c4381fAdam Powell        final float minVel = MIN_FLING_VELOCITY * density;
2301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2311732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        mLeftCallback = new ViewDragCallback(Gravity.LEFT);
2321732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        mRightCallback = new ViewDragCallback(Gravity.RIGHT);
2331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
23486559d86173efb890a8edf48d935cfebfaccf049Adam Powell        mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback);
2351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
23679f95ce3e660d267831067e514ff455156c4381fAdam Powell        mLeftDragger.setMinVelocity(minVel);
2371732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        mLeftCallback.setDragger(mLeftDragger);
2381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
23986559d86173efb890a8edf48d935cfebfaccf049Adam Powell        mRightDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mRightCallback);
2401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
24179f95ce3e660d267831067e514ff455156c4381fAdam Powell        mRightDragger.setMinVelocity(minVel);
2421732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        mRightCallback.setDragger(mRightDragger);
243791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell
244791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        // So that we can catch the back button
245791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        setFocusableInTouchMode(true);
2467d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell
2477d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell        ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate());
2481b8262b87426b2f766b40d6ab4eaeac296d5c2feAdam Powell        ViewGroupCompat.setMotionEventSplittingEnabled(this, false);
2491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
252b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * Set a simple drawable used for the left or right shadow.
253b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * The drawable provided must have a nonzero intrinsic width.
254b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     *
255b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * @param shadowDrawable Shadow drawable to use at the edge of a drawer
256b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * @param gravity Which drawer the shadow should apply to
257b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     */
258b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    public void setDrawerShadow(Drawable shadowDrawable, int gravity) {
259b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        /*
260b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell         * TODO Someone someday might want to set more complex drawables here.
261b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell         * They're probably nuts, but we might want to consider registering callbacks,
262b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell         * setting states, etc. properly.
263b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell         */
264b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
265b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        final int absGravity = GravityCompat.getAbsoluteGravity(gravity,
266b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                ViewCompat.getLayoutDirection(this));
267b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        if ((absGravity & Gravity.LEFT) == Gravity.LEFT) {
268b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            mShadowLeft = shadowDrawable;
269b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            invalidate();
270b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
271b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        if ((absGravity & Gravity.RIGHT) == Gravity.RIGHT) {
272b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            mShadowRight = shadowDrawable;
273b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            invalidate();
274b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
275b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    }
276b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
277b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    /**
278b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * Set a simple drawable used for the left or right shadow.
279b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * The drawable provided must have a nonzero intrinsic width.
280b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     *
281b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * @param resId Resource id of a shadow drawable to use at the edge of a drawer
282b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * @param gravity Which drawer the shadow should apply to
283b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     */
284b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    public void setDrawerShadow(int resId, int gravity) {
285b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        setDrawerShadow(getResources().getDrawable(resId), gravity);
286b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    }
287b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
288b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    /**
289fe130779be95af79e875bdbeac7182a424b8b9a6Adam Powell     * Set a color to use for the scrim that obscures primary content while a drawer is open.
290fe130779be95af79e875bdbeac7182a424b8b9a6Adam Powell     *
291fe130779be95af79e875bdbeac7182a424b8b9a6Adam Powell     * @param color Color to use in 0xAARRGGBB format.
292fe130779be95af79e875bdbeac7182a424b8b9a6Adam Powell     */
293fe130779be95af79e875bdbeac7182a424b8b9a6Adam Powell    public void setScrimColor(int color) {
294fe130779be95af79e875bdbeac7182a424b8b9a6Adam Powell        mScrimColor = color;
295fe130779be95af79e875bdbeac7182a424b8b9a6Adam Powell        invalidate();
296fe130779be95af79e875bdbeac7182a424b8b9a6Adam Powell    }
297fe130779be95af79e875bdbeac7182a424b8b9a6Adam Powell
298fe130779be95af79e875bdbeac7182a424b8b9a6Adam Powell    /**
2991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Set a listener to be notified of drawer events.
3001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
3011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param listener Listener to notify when drawer events occur
3021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @see DrawerListener
3031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
3041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void setDrawerListener(DrawerListener listener) {
3051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mListener = listener;
3061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
3071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
3090492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * Enable or disable interaction with all drawers.
3100492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3110492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * <p>This allows the application to restrict the user's ability to open or close
3120492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * any drawer within this layout. DrawerLayout will still respond to calls to
3130492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * {@link #openDrawer(int)}, {@link #closeDrawer(int)} and friends if a drawer is locked.</p>
3140492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3150492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * <p>Locking drawers open or closed will implicitly open or close
3160492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * any drawers as appropriate.</p>
3170492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3180492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
3190492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *                 {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
3200492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     */
3210492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    public void setDrawerLockMode(int lockMode) {
3220492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        setDrawerLockMode(lockMode, Gravity.LEFT);
3230492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        setDrawerLockMode(lockMode, Gravity.RIGHT);
3240492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    }
3250492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell
3260492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    /**
3270492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * Enable or disable interaction with the given drawer.
3280492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3290492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * <p>This allows the application to restrict the user's ability to open or close
3300492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)},
3310492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * {@link #closeDrawer(int)} and friends if a drawer is locked.</p>
3320492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3330492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * <p>Locking a drawer open or closed will implicitly open or close
3340492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * that drawer as appropriate.</p>
3350492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3360492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
3370492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *                 {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
3380492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @param edgeGravity Gravity.LEFT, RIGHT, START or END.
3390492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *                    Expresses which drawer to change the mode for.
3400492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3410492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @see #LOCK_MODE_UNLOCKED
3420492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @see #LOCK_MODE_LOCKED_CLOSED
3430492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @see #LOCK_MODE_LOCKED_OPEN
3440492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     */
3450492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    public void setDrawerLockMode(int lockMode, int edgeGravity) {
346f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        final int absGravity = GravityCompat.getAbsoluteGravity(edgeGravity,
3470492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                ViewCompat.getLayoutDirection(this));
348f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        if (absGravity == Gravity.LEFT) {
3490492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            mLockModeLeft = lockMode;
350f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        } else if (absGravity == Gravity.RIGHT) {
3510492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            mLockModeRight = lockMode;
3520492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        }
3530492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        if (lockMode != LOCK_MODE_UNLOCKED) {
3540492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            // Cancel interaction in progress
355f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            final ViewDragHelper helper = absGravity == Gravity.LEFT ? mLeftDragger : mRightDragger;
3560492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            helper.cancel();
3570492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        }
3580492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        switch (lockMode) {
3590492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            case LOCK_MODE_LOCKED_OPEN:
360f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                final View toOpen = findDrawerWithGravity(absGravity);
3610492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                if (toOpen != null) {
3620492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                    openDrawer(toOpen);
3630492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                }
3640492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                break;
3650492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            case LOCK_MODE_LOCKED_CLOSED:
366f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                final View toClose = findDrawerWithGravity(absGravity);
3670492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                if (toClose != null) {
3680492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                    closeDrawer(toClose);
3690492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                }
3700492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                break;
3710492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            // default: do nothing
3720492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        }
3730492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    }
3740492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell
3750492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    /**
3760492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * Enable or disable interaction with the given drawer.
3770492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3780492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * <p>This allows the application to restrict the user's ability to open or close
3790492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)},
3800492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * {@link #closeDrawer(int)} and friends if a drawer is locked.</p>
3810492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3820492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * <p>Locking a drawer open or closed will implicitly open or close
3830492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * that drawer as appropriate.</p>
3840492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3850492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
3860492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *                 {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
3870492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @param drawerView The drawer view to change the lock mode for
3880492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
3890492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @see #LOCK_MODE_UNLOCKED
3900492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @see #LOCK_MODE_LOCKED_CLOSED
3910492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @see #LOCK_MODE_LOCKED_OPEN
3920492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     */
3930492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    public void setDrawerLockMode(int lockMode, View drawerView) {
3940492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        if (!isDrawerView(drawerView)) {
3950492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            throw new IllegalArgumentException("View " + drawerView + " is not a " +
3960492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                    "drawer with appropriate layout_gravity");
3970492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        }
398f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
399f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        setDrawerLockMode(lockMode, gravity);
4000492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    }
4010492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell
4020492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    /**
4030492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * Check the lock mode of the drawer with the given gravity.
4040492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
4050492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @param edgeGravity Gravity of the drawer to check
4060492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or
4070492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *         {@link #LOCK_MODE_LOCKED_OPEN}.
4080492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     */
4090492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    public int getDrawerLockMode(int edgeGravity) {
410f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        final int absGravity = GravityCompat.getAbsoluteGravity(
411f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                edgeGravity, ViewCompat.getLayoutDirection(this));
412f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        if (absGravity == Gravity.LEFT) {
4130492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            return mLockModeLeft;
414f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        } else if (absGravity == Gravity.RIGHT) {
4150492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            return mLockModeRight;
4160492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        }
4170492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        return LOCK_MODE_UNLOCKED;
4180492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    }
4190492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell
4200492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    /**
4210492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * Check the lock mode of the given drawer view.
4220492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *
4230492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @param drawerView Drawer view to check lock mode
4240492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or
4250492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     *         {@link #LOCK_MODE_LOCKED_OPEN}.
4260492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell     */
4270492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    public int getDrawerLockMode(View drawerView) {
428f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        final int absGravity = getDrawerViewAbsoluteGravity(drawerView);
429f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        if (absGravity == Gravity.LEFT) {
4300492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            return mLockModeLeft;
431f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        } else if (absGravity == Gravity.RIGHT) {
4320492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            return mLockModeRight;
4330492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        }
4340492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        return LOCK_MODE_UNLOCKED;
4350492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    }
4360492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell
4370492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    /**
4381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Resolve the shared state of all drawers from the component ViewDragHelpers.
4391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Should be called whenever a ViewDragHelper's state changes.
4401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
441b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    void updateDrawerState(int forGravity, int activeState, View activeDrawer) {
4421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int leftState = mLeftDragger.getViewDragState();
4431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int rightState = mRightDragger.getViewDragState();
4441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int state;
4461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (leftState == STATE_DRAGGING || rightState == STATE_DRAGGING) {
4471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            state = STATE_DRAGGING;
4481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        } else if (leftState == STATE_SETTLING || rightState == STATE_SETTLING) {
4491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            state = STATE_SETTLING;
4501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        } else {
4511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            state = STATE_IDLE;
4521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
4531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
454b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        if (activeDrawer != null && activeState == STATE_IDLE) {
455b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            final LayoutParams lp = (LayoutParams) activeDrawer.getLayoutParams();
456b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            if (lp.onScreen == 0) {
457b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                dispatchOnDrawerClosed(activeDrawer);
458b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            } else if (lp.onScreen == 1) {
459b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                dispatchOnDrawerOpened(activeDrawer);
460b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            }
461b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
462b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
4631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (state != mDrawerState) {
4641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mDrawerState = state;
465b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
4661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (mListener != null) {
4671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mListener.onDrawerStateChanged(state);
4681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
4691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
4701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
4711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void dispatchOnDrawerClosed(View drawerView) {
4731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
4741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (lp.knownOpen) {
4751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            lp.knownOpen = false;
4761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (mListener != null) {
4771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mListener.onDrawerClosed(drawerView);
4781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
4797d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell            sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
4801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
4811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
4821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void dispatchOnDrawerOpened(View drawerView) {
4841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
4851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (!lp.knownOpen) {
4861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            lp.knownOpen = true;
4871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (mListener != null) {
4881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mListener.onDrawerOpened(drawerView);
4891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
4907d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell            drawerView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
4911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
4921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
4931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void dispatchOnDrawerSlide(View drawerView, float slideOffset) {
4951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (mListener != null) {
4961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mListener.onDrawerSlide(drawerView, slideOffset);
4971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
4981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
4991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void setDrawerViewOffset(View drawerView, float slideOffset) {
5011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
502b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        if (slideOffset == lp.onScreen) {
5031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            return;
5041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
506b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        lp.onScreen = slideOffset;
5071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        dispatchOnDrawerSlide(drawerView, slideOffset);
5081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    float getDrawerViewOffset(View drawerView) {
511b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        return ((LayoutParams) drawerView.getLayoutParams()).onScreen;
5121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
514f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette    /**
515f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette     * @return the absolute gravity of the child drawerView, resolved according
516f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette     *         to the current layout direction
517f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette     */
518f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette    int getDrawerViewAbsoluteGravity(View drawerView) {
5191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
520f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        return GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(this));
5211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
523f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette    boolean checkDrawerViewAbsoluteGravity(View drawerView, int checkFor) {
524f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        final int absGravity = getDrawerViewAbsoluteGravity(drawerView);
525f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        return (absGravity & checkFor) == checkFor;
5261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5280492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    View findOpenDrawer() {
5290492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        final int childCount = getChildCount();
5300492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        for (int i = 0; i < childCount; i++) {
5310492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            final View child = getChildAt(i);
5320492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            if (((LayoutParams) child.getLayoutParams()).knownOpen) {
5330492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                return child;
5340492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            }
5350492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        }
5360492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        return null;
5370492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    }
5380492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell
5391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void moveDrawerToOffset(View drawerView, float slideOffset) {
5401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final float oldOffset = getDrawerViewOffset(drawerView);
5411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int width = drawerView.getWidth();
5421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int oldPos = (int) (width * oldOffset);
5431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int newPos = (int) (width * slideOffset);
5441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int dx = newPos - oldPos;
5451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
546f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        drawerView.offsetLeftAndRight(
547f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT) ? dx : -dx);
5481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        setDrawerViewOffset(drawerView, slideOffset);
5491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
551f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette    /**
552f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette     * @param gravity the gravity of the child to return. If specified as a
553f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette     *            relative value, it will be resolved according to the current
554f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette     *            layout direction.
555f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette     * @return the drawer with the specified gravity
556f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette     */
5571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    View findDrawerWithGravity(int gravity) {
558f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        final int absHorizGravity = GravityCompat.getAbsoluteGravity(
559f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                gravity, ViewCompat.getLayoutDirection(this)) & Gravity.HORIZONTAL_GRAVITY_MASK;
5601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int childCount = getChildCount();
5611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        for (int i = 0; i < childCount; i++) {
5621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View child = getChildAt(i);
563f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            final int childAbsGravity = getDrawerViewAbsoluteGravity(child);
564f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            if ((childAbsGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == absHorizGravity) {
5651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                return child;
5661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
5671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return null;
5691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
5721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Simple gravity to string - only supports LEFT and RIGHT for debugging output.
5731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
5741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param gravity Absolute gravity value
5751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @return LEFT or RIGHT as appropriate, or a hex string
5761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
5771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    static String gravityToString(int gravity) {
5781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
5791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            return "LEFT";
5801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
5821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            return "RIGHT";
5831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return Integer.toHexString(gravity);
5851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
58857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    protected void onDetachedFromWindow() {
58957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        super.onDetachedFromWindow();
59057902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        mFirstLayout = true;
59157902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    }
59257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
59357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    @Override
59457902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    protected void onAttachedToWindow() {
59557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        super.onAttachedToWindow();
59657902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        mFirstLayout = true;
59757902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    }
59857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
59957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    @Override
6001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
601c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
602c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
603c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
604c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
6051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
607c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell            if (isInEditMode()) {
608c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                // Don't crash the layout editor. Consume all of the space if specified
609c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                // or pick a magic number from thin air otherwise.
610c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                // TODO Better communication with tools of this bogus state.
611c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                // It will crash on a real device.
612c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                if (widthMode == MeasureSpec.AT_MOST) {
613c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                    widthMode = MeasureSpec.EXACTLY;
614c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                } else if (widthMode == MeasureSpec.UNSPECIFIED) {
615c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                    widthMode = MeasureSpec.EXACTLY;
616c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                    widthSize = 300;
617c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                }
618c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                if (heightMode == MeasureSpec.AT_MOST) {
619c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                    heightMode = MeasureSpec.EXACTLY;
620c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                }
621c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                else if (heightMode == MeasureSpec.UNSPECIFIED) {
622c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                    heightMode = MeasureSpec.EXACTLY;
623c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                    heightSize = 300;
624c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                }
625c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell            } else {
626c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                throw new IllegalArgumentException(
627c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell                        "DrawerLayout must be measured with MeasureSpec.EXACTLY.");
628c6f6c4511593aa49688d5425e2f6e36459076c25Adam Powell            }
6291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
6301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        setMeasuredDimension(widthSize, heightSize);
6321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        // Gravity value for each drawer we've seen. Only one of each permitted.
6341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        int foundDrawers = 0;
6351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int childCount = getChildCount();
6361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        for (int i = 0; i < childCount; i++) {
6371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View child = getChildAt(i);
6381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (child.getVisibility() == GONE) {
6401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                continue;
6411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
6421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
64300ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
64400ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell
6451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (isContentView(child)) {
6461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                // Content views get measured at exactly the layout's size.
64700ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                final int contentWidthSpec = MeasureSpec.makeMeasureSpec(
64800ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
64900ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                final int contentHeightSpec = MeasureSpec.makeMeasureSpec(
65000ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
65100ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                child.measure(contentWidthSpec, contentHeightSpec);
6521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else if (isDrawerView(child)) {
6531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int childGravity =
654f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                        getDrawerViewAbsoluteGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK;
6551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                if ((foundDrawers & childGravity) != 0) {
6561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    throw new IllegalStateException("Child drawer has absolute gravity " +
6571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                            gravityToString(childGravity) + " but this " + TAG + " already has a " +
6581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                            "drawer view along that edge");
6591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                }
66000ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,
66100ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        mMinDrawerMargin + lp.leftMargin + lp.rightMargin,
66200ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        lp.width);
66300ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec,
66400ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        lp.topMargin + lp.bottomMargin,
66500ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        lp.height);
66600ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                child.measure(drawerWidthSpec, drawerHeightSpec);
6671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
6681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                throw new IllegalStateException("Child " + child + " at index " + i +
6691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        " does not have a valid layout_gravity - must be Gravity.LEFT, " +
6701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        "Gravity.RIGHT or Gravity.NO_GRAVITY");
6711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
6721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
6731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
6741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
6761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected void onLayout(boolean changed, int l, int t, int r, int b) {
677b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        mInLayout = true;
678c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell        final int width = r - l;
6791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int childCount = getChildCount();
6801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        for (int i = 0; i < childCount; i++) {
6811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View child = getChildAt(i);
6821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (child.getVisibility() == GONE) {
6841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                continue;
6851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
6861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
68700ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
68800ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell
6891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (isContentView(child)) {
69000ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                child.layout(lp.leftMargin, lp.topMargin,
69100ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        lp.leftMargin + child.getMeasuredWidth(),
69200ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        lp.topMargin + child.getMeasuredHeight());
6931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else { // Drawer, if it wasn't onMeasure would have thrown an exception.
6941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int childWidth = child.getMeasuredWidth();
69500ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                final int childHeight = child.getMeasuredHeight();
6961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                int childLeft;
6971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
698c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                final float newOffset;
699f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
700b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                    childLeft = -childWidth + (int) (childWidth * lp.onScreen);
701c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                    newOffset = (float) (childWidth + childLeft) / childWidth;
7021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                } else { // Right; onMeasure checked for us.
703c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                    childLeft = width - (int) (childWidth * lp.onScreen);
704c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                    newOffset = (float) (width - childLeft) / childWidth;
7051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                }
7061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
707c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                final boolean changeOffset = newOffset != lp.onScreen;
708c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell
70900ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
71000ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell
71100ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                switch (vgrav) {
71200ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                    default:
71300ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                    case Gravity.TOP: {
7149b2fb1efe771e9927724b33242cbc3bc62b5b315Adam Powell                        child.layout(childLeft, lp.topMargin, childLeft + childWidth,
7159b2fb1efe771e9927724b33242cbc3bc62b5b315Adam Powell                                lp.topMargin + childHeight);
71600ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        break;
71700ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                    }
71800ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell
71900ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                    case Gravity.BOTTOM: {
72000ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        final int height = b - t;
72100ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        child.layout(childLeft,
72200ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                                height - lp.bottomMargin - child.getMeasuredHeight(),
72300ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                                childLeft + childWidth,
72400ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                                height - lp.bottomMargin);
72500ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        break;
72600ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                    }
72700ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell
72800ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                    case Gravity.CENTER_VERTICAL: {
72900ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        final int height = b - t;
73000ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        int childTop = (height - childHeight) / 2;
73100ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell
73200ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        // Offset for margins. If things don't fit right because of
73300ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        // bad measurement before, oh well.
73400ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        if (childTop < lp.topMargin) {
73500ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                            childTop = lp.topMargin;
73600ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        } else if (childTop + childHeight > height - lp.bottomMargin) {
73700ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                            childTop = height - lp.bottomMargin - childHeight;
73800ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        }
73900ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        child.layout(childLeft, childTop, childLeft + childWidth,
74000ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                                childTop + childHeight);
74100ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        break;
74200ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                    }
74300ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                }
744b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
745c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                if (changeOffset) {
746c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                    setDrawerViewOffset(child, newOffset);
747c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                }
748c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell
749c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                final int newVisibility = lp.onScreen > 0 ? VISIBLE : INVISIBLE;
750c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                if (child.getVisibility() != newVisibility) {
751c27e9ab4a09e40911d180fa0e25a0011a3adcd71Adam Powell                    child.setVisibility(newVisibility);
752b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                }
7531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
7541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
755b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        mInLayout = false;
75657902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        mFirstLayout = false;
757b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    }
758b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
759b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    @Override
760b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    public void requestLayout() {
761b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        if (!mInLayout) {
762b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            super.requestLayout();
763b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
7641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
7651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
7671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void computeScroll() {
7681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int childCount = getChildCount();
7691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        float scrimOpacity = 0;
7701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        for (int i = 0; i < childCount; i++) {
771b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            final float onscreen = ((LayoutParams) getChildAt(i).getLayoutParams()).onScreen;
7721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            scrimOpacity = Math.max(scrimOpacity, onscreen);
7731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mScrimOpacity = scrimOpacity;
7751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        // "|" used on purpose; both need to run.
7771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (mLeftDragger.continueSettling(true) | mRightDragger.continueSettling(true)) {
7781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            ViewCompat.postInvalidateOnAnimation(this);
7791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
7811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
782b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    private static boolean hasOpaqueBackground(View v) {
783b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        final Drawable bg = v.getBackground();
784b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        if (bg != null) {
785b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            return bg.getOpacity() == PixelFormat.OPAQUE;
786b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
787b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        return false;
788b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    }
789b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
7901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
7911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
79200ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell        final int height = getHeight();
793b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        final boolean drawingContent = isContentView(child);
794b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        int clipLeft = 0, clipRight = getWidth();
795b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
7961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int restoreCount = canvas.save();
797b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        if (drawingContent) {
798b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            final int childCount = getChildCount();
799b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            for (int i = 0; i < childCount; i++) {
800b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                final View v = getChildAt(i);
801b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                if (v == child || v.getVisibility() != VISIBLE ||
80200ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        !hasOpaqueBackground(v) || !isDrawerView(v) ||
80300ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                        v.getHeight() < height) {
804b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                    continue;
805b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                }
806b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
807f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                if (checkDrawerViewAbsoluteGravity(v, Gravity.LEFT)) {
808b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                    final int vright = v.getRight();
809b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                    if (vright > clipLeft) clipLeft = vright;
810b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                } else {
811b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                    final int vleft = v.getLeft();
812b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                    if (vleft < clipRight) clipRight = vleft;
813b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                }
814b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            }
815b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            canvas.clipRect(clipLeft, 0, clipRight, getHeight());
816b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
8171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final boolean result = super.drawChild(canvas, child, drawingTime);
8181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        canvas.restoreToCount(restoreCount);
819b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
820b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        if (mScrimOpacity > 0 && drawingContent) {
8211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;
8221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int imag = (int) (baseAlpha * mScrimOpacity);
8231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int color = imag << 24 | (mScrimColor & 0xffffff);
8241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mScrimPaint.setColor(color);
8251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
826b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            canvas.drawRect(clipLeft, 0, clipRight, getHeight(), mScrimPaint);
827f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        } else if (mShadowLeft != null && checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
828b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            final int shadowWidth = mShadowLeft.getIntrinsicWidth();
829b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            final int childRight = child.getRight();
830ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell            final int drawerPeekDistance = mLeftDragger.getEdgeSize();
831b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            final float alpha =
832ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell                    Math.max(0, Math.min((float) childRight / drawerPeekDistance, 1.f));
833b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            mShadowLeft.setBounds(childRight, child.getTop(),
834b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                    childRight + shadowWidth, child.getBottom());
835b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            mShadowLeft.setAlpha((int) (0xff * alpha));
836b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            mShadowLeft.draw(canvas);
837f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        } else if (mShadowRight != null && checkDrawerViewAbsoluteGravity(child, Gravity.RIGHT)) {
838b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            final int shadowWidth = mShadowRight.getIntrinsicWidth();
839b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            final int childLeft = child.getLeft();
840b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            final int showing = getWidth() - childLeft;
841ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell            final int drawerPeekDistance = mRightDragger.getEdgeSize();
842b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            final float alpha =
843ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell                    Math.max(0, Math.min((float) showing / drawerPeekDistance, 1.f));
844b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            mShadowRight.setBounds(childLeft - shadowWidth, child.getTop(),
845b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                    childLeft, child.getBottom());
846b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            mShadowRight.setAlpha((int) (0xff * alpha));
847b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            mShadowRight.draw(canvas);
8481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
8491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return result;
8501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
8511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
8521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    boolean isContentView(View child) {
8531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY;
8541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
8551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
8561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    boolean isDrawerView(View child) {
8571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int gravity = ((LayoutParams) child.getLayoutParams()).gravity;
8581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int absGravity = GravityCompat.getAbsoluteGravity(gravity,
8591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                ViewCompat.getLayoutDirection(child));
8601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return (absGravity & (Gravity.LEFT | Gravity.RIGHT)) != 0;
8611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
8621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
8631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
8641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public boolean onInterceptTouchEvent(MotionEvent ev) {
8651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int action = MotionEventCompat.getActionMasked(ev);
8661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
8671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        // "|" used deliberately here; both methods should be invoked.
8681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final boolean interceptForDrag = mLeftDragger.shouldInterceptTouchEvent(ev) |
8691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mRightDragger.shouldInterceptTouchEvent(ev);
8701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
8711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        boolean interceptForTap = false;
8721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
8731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        switch (action) {
8741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_DOWN: {
8751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float x = ev.getX();
8761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float y = ev.getY();
8771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mInitialMotionX = x;
8781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mInitialMotionY = y;
8791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                if (mScrimOpacity > 0 &&
8801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        isContentView(mLeftDragger.findTopChildUnder((int) x, (int) y))) {
8811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    interceptForTap = true;
8821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                }
8831732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                mDisallowInterceptRequested = false;
884cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell                mChildrenCanceledTouch = false;
8851732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                break;
8861732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell            }
8871732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell
8881732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell            case MotionEvent.ACTION_MOVE: {
8891732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                // If we cross the touch slop, don't perform the delayed peek for an edge touch.
8901732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                if (mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)) {
8911732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                    mLeftCallback.removeCallbacks();
8921732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                    mRightCallback.removeCallbacks();
8931732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                }
8941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                break;
8951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
8961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
8971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_CANCEL:
8981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_UP: {
8991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                closeDrawers(true);
9001732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                mDisallowInterceptRequested = false;
901cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell                mChildrenCanceledTouch = false;
9021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
9031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
9041732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell
905cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell        return interceptForDrag || interceptForTap || hasPeekingDrawer() || mChildrenCanceledTouch;
9061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
9071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
9081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
9091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public boolean onTouchEvent(MotionEvent ev) {
9101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mLeftDragger.processTouchEvent(ev);
9111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mRightDragger.processTouchEvent(ev);
9121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
9131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int action = ev.getAction();
9141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        boolean wantTouchEvents = true;
9151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
9161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        switch (action & MotionEventCompat.ACTION_MASK) {
9171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_DOWN: {
9181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float x = ev.getX();
9191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float y = ev.getY();
9201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mInitialMotionX = x;
9211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mInitialMotionY = y;
9221732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                mDisallowInterceptRequested = false;
923cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell                mChildrenCanceledTouch = false;
9241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                break;
9251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
9261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
9271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_UP: {
9281d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float x = ev.getX();
9291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float y = ev.getY();
9301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                boolean peekingOnly = true;
9318bc268e9c40e4ae375a0d65dc1293dccc541186fAdam Powell                final View touchedView = mLeftDragger.findTopChildUnder((int) x, (int) y);
9328bc268e9c40e4ae375a0d65dc1293dccc541186fAdam Powell                if (touchedView != null && isContentView(touchedView)) {
9331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    final float dx = x - mInitialMotionX;
9341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    final float dy = y - mInitialMotionY;
9351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    final int slop = mLeftDragger.getTouchSlop();
9361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    if (dx * dx + dy * dy < slop * slop) {
9370492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                        // Taps close a dimmed open drawer but only if it isn't locked open.
9380492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                        final View openDrawer = findOpenDrawer();
9390492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                        if (openDrawer != null) {
9400492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                            peekingOnly = getDrawerLockMode(openDrawer) == LOCK_MODE_LOCKED_OPEN;
9410492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                        }
9421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    }
9431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                }
9441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                closeDrawers(peekingOnly);
9451732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                mDisallowInterceptRequested = false;
9461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                break;
9471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
9481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
9491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_CANCEL: {
9501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                closeDrawers(true);
9511732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                mDisallowInterceptRequested = false;
952cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell                mChildrenCanceledTouch = false;
9531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                break;
9541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
9551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
9561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
9571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return wantTouchEvents;
9581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
9591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
960ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
96186559d86173efb890a8edf48d935cfebfaccf049Adam Powell        if (CHILDREN_DISALLOW_INTERCEPT ||
96286559d86173efb890a8edf48d935cfebfaccf049Adam Powell                (!mLeftDragger.isEdgeTouched(ViewDragHelper.EDGE_LEFT) &&
96386559d86173efb890a8edf48d935cfebfaccf049Adam Powell                !mRightDragger.isEdgeTouched(ViewDragHelper.EDGE_RIGHT))) {
9641732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell            // If we have an edge touch we want to skip this and track it for later instead.
9651732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell            super.requestDisallowInterceptTouchEvent(disallowIntercept);
9661732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        }
9671732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        mDisallowInterceptRequested = disallowIntercept;
968ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell        if (disallowIntercept) {
969ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell            closeDrawers(true);
970ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell        }
971ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell    }
972ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell
9731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
9741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Close all currently open drawer views by animating them out of view.
9751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
9761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void closeDrawers() {
9771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        closeDrawers(false);
9781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
9791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
9801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void closeDrawers(boolean peekingOnly) {
9811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        boolean needsInvalidate = false;
9821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int childCount = getChildCount();
9831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        for (int i = 0; i < childCount; i++) {
9841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View child = getChildAt(i);
9851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
9861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
9871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (!isDrawerView(child) || (peekingOnly && !lp.isPeeking)) {
9881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                continue;
9891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
9901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
9911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int childWidth = child.getWidth();
9921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
993f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
9941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                needsInvalidate |= mLeftDragger.smoothSlideViewTo(child,
9951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        -childWidth, child.getTop());
9961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
9971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                needsInvalidate |= mRightDragger.smoothSlideViewTo(child,
9981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        getWidth(), child.getTop());
9991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
10001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
10011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            lp.isPeeking = false;
10021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
10031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
10041732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        mLeftCallback.removeCallbacks();
10051732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        mRightCallback.removeCallbacks();
10061732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell
10071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (needsInvalidate) {
10081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            invalidate();
10091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
10101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
10111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
10121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
10131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Open the specified drawer view by animating it into view.
10141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
10151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param drawerView Drawer view to open
10161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
10171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void openDrawer(View drawerView) {
10181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (!isDrawerView(drawerView)) {
10191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
10201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
10211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
102257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        if (mFirstLayout) {
102357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
102457902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            lp.onScreen = 1.f;
102557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            lp.knownOpen = true;
10261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        } else {
1027f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
102857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop());
102957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            } else {
103057902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                mRightDragger.smoothSlideViewTo(drawerView, getWidth() - drawerView.getWidth(),
103157902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                        drawerView.getTop());
103257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            }
10331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
10341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        invalidate();
10351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
10361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
10371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
10381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Open the specified drawer by animating it out of view.
10391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
10401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
10411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *                GravityCompat.START or GravityCompat.END may also be used.
10421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
10431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void openDrawer(int gravity) {
1044f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        final View drawerView = findDrawerWithGravity(gravity);
10451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (drawerView == null) {
1046f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            throw new IllegalArgumentException("No drawer view found with gravity " +
1047f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                    gravityToString(gravity));
10481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
10491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        openDrawer(drawerView);
10501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
10511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
10521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
10531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Close the specified drawer view by animating it into view.
10541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
10551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param drawerView Drawer view to close
10561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
10571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void closeDrawer(View drawerView) {
10581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (!isDrawerView(drawerView)) {
10591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
10601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
10611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
106257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        if (mFirstLayout) {
106357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
106457902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            lp.onScreen = 0.f;
106557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            lp.knownOpen = false;
10661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        } else {
1067f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
106857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                mLeftDragger.smoothSlideViewTo(drawerView, -drawerView.getWidth(),
106957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                        drawerView.getTop());
107057902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            } else {
107157902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                mRightDragger.smoothSlideViewTo(drawerView, getWidth(), drawerView.getTop());
107257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            }
10731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
10741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        invalidate();
10751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
10761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
10771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
10781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Close the specified drawer by animating it out of view.
10791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
10801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
10811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *                GravityCompat.START or GravityCompat.END may also be used.
10821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
10831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void closeDrawer(int gravity) {
1084f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        final View drawerView = findDrawerWithGravity(gravity);
10851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (drawerView == null) {
1086f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            throw new IllegalArgumentException("No drawer view found with gravity " +
1087f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                    gravityToString(gravity));
10881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
10891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        closeDrawer(drawerView);
10901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
10911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1092b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    /**
1093b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * Check if the given drawer view is currently in an open state.
1094b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * To be considered "open" the drawer must have settled into its fully
1095b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * visible state. To check for partial visibility use
1096b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * {@link #isDrawerVisible(android.view.View)}.
1097b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     *
1098b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * @param drawer Drawer view to check
1099b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * @return true if the given drawer view is in an open state
1100b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * @see #isDrawerVisible(android.view.View)
1101b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     */
1102b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    public boolean isDrawerOpen(View drawer) {
1103b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        if (!isDrawerView(drawer)) {
1104b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            throw new IllegalArgumentException("View " + drawer + " is not a drawer");
1105b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
1106b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        return ((LayoutParams) drawer.getLayoutParams()).knownOpen;
1107b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    }
1108b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
1109b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    /**
111079f95ce3e660d267831067e514ff455156c4381fAdam Powell     * Check if the given drawer view is currently in an open state.
111179f95ce3e660d267831067e514ff455156c4381fAdam Powell     * To be considered "open" the drawer must have settled into its fully
111279f95ce3e660d267831067e514ff455156c4381fAdam Powell     * visible state. If there is no drawer with the given gravity this method
111379f95ce3e660d267831067e514ff455156c4381fAdam Powell     * will return false.
111479f95ce3e660d267831067e514ff455156c4381fAdam Powell     *
111579f95ce3e660d267831067e514ff455156c4381fAdam Powell     * @param drawerGravity Gravity of the drawer to check
111679f95ce3e660d267831067e514ff455156c4381fAdam Powell     * @return true if the given drawer view is in an open state
111779f95ce3e660d267831067e514ff455156c4381fAdam Powell     */
111879f95ce3e660d267831067e514ff455156c4381fAdam Powell    public boolean isDrawerOpen(int drawerGravity) {
111979f95ce3e660d267831067e514ff455156c4381fAdam Powell        final View drawerView = findDrawerWithGravity(drawerGravity);
112079f95ce3e660d267831067e514ff455156c4381fAdam Powell        if (drawerView != null) {
112179f95ce3e660d267831067e514ff455156c4381fAdam Powell            return isDrawerOpen(drawerView);
112279f95ce3e660d267831067e514ff455156c4381fAdam Powell        }
112379f95ce3e660d267831067e514ff455156c4381fAdam Powell        return false;
112479f95ce3e660d267831067e514ff455156c4381fAdam Powell    }
112579f95ce3e660d267831067e514ff455156c4381fAdam Powell
112679f95ce3e660d267831067e514ff455156c4381fAdam Powell    /**
1127b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * Check if a given drawer view is currently visible on-screen. The drawer
1128b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * may be only peeking onto the screen, fully extended, or anywhere inbetween.
1129b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     *
1130b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * @param drawer Drawer view to check
1131b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * @return true if the given drawer is visible on-screen
1132b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     * @see #isDrawerOpen(android.view.View)
1133b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell     */
1134b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    public boolean isDrawerVisible(View drawer) {
1135b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        if (!isDrawerView(drawer)) {
1136b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            throw new IllegalArgumentException("View " + drawer + " is not a drawer");
1137b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        }
1138b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        return ((LayoutParams) drawer.getLayoutParams()).onScreen > 0;
1139b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell    }
1140b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell
114179f95ce3e660d267831067e514ff455156c4381fAdam Powell    /**
114279f95ce3e660d267831067e514ff455156c4381fAdam Powell     * Check if a given drawer view is currently visible on-screen. The drawer
114379f95ce3e660d267831067e514ff455156c4381fAdam Powell     * may be only peeking onto the screen, fully extended, or anywhere inbetween.
114479f95ce3e660d267831067e514ff455156c4381fAdam Powell     * If there is no drawer with the given gravity this method will return false.
114579f95ce3e660d267831067e514ff455156c4381fAdam Powell     *
114679f95ce3e660d267831067e514ff455156c4381fAdam Powell     * @param drawerGravity Gravity of the drawer to check
114779f95ce3e660d267831067e514ff455156c4381fAdam Powell     * @return true if the given drawer is visible on-screen
114879f95ce3e660d267831067e514ff455156c4381fAdam Powell     */
114979f95ce3e660d267831067e514ff455156c4381fAdam Powell    public boolean isDrawerVisible(int drawerGravity) {
115079f95ce3e660d267831067e514ff455156c4381fAdam Powell        final View drawerView = findDrawerWithGravity(drawerGravity);
115179f95ce3e660d267831067e514ff455156c4381fAdam Powell        if (drawerView != null) {
115279f95ce3e660d267831067e514ff455156c4381fAdam Powell            return isDrawerVisible(drawerView);
115379f95ce3e660d267831067e514ff455156c4381fAdam Powell        }
115479f95ce3e660d267831067e514ff455156c4381fAdam Powell        return false;
115579f95ce3e660d267831067e514ff455156c4381fAdam Powell    }
115679f95ce3e660d267831067e514ff455156c4381fAdam Powell
1157ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell    private boolean hasPeekingDrawer() {
1158ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell        final int childCount = getChildCount();
1159ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell        for (int i = 0; i < childCount; i++) {
1160ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell            final LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
1161ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell            if (lp.isPeeking) {
1162ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell                return true;
1163ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell            }
1164ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell        }
1165ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell        return false;
1166ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell    }
1167ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell
11681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
11691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
11701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
11711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
11721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
11731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
11741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
11751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return p instanceof LayoutParams
11761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                ? new LayoutParams((LayoutParams) p)
117700ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                : p instanceof ViewGroup.MarginLayoutParams
117800ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell                ? new LayoutParams((MarginLayoutParams) p)
11791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                : new LayoutParams(p);
11801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
11811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
11821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
11831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
11841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return p instanceof LayoutParams && super.checkLayoutParams(p);
11851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
11861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
11871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
11881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
11891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return new LayoutParams(getContext(), attrs);
11901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
11911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1192791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    private boolean hasVisibleDrawer() {
11930492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        return findVisibleDrawer() != null;
11940492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    }
11950492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell
11960492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell    private View findVisibleDrawer() {
1197791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        final int childCount = getChildCount();
1198791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        for (int i = 0; i < childCount; i++) {
1199791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell            final View child = getChildAt(i);
1200791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell            if (isDrawerView(child) && isDrawerVisible(child)) {
12010492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                return child;
1202791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell            }
1203791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        }
12040492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        return null;
1205791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    }
1206791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell
1207cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell    void cancelChildViewTouch() {
1208cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell        // Cancel child touches
1209cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell        if (!mChildrenCanceledTouch) {
1210cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell            final long now = SystemClock.uptimeMillis();
1211cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell            final MotionEvent cancelEvent = MotionEvent.obtain(now, now,
1212cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
1213cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell            final int childCount = getChildCount();
1214cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell            for (int i = 0; i < childCount; i++) {
1215cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell                getChildAt(i).dispatchTouchEvent(cancelEvent);
1216cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell            }
1217cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell            cancelEvent.recycle();
1218cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell            mChildrenCanceledTouch = true;
1219cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell        }
1220cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell    }
1221cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell
1222791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    @Override
1223791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    public boolean onKeyDown(int keyCode, KeyEvent event) {
1224791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        if (keyCode == KeyEvent.KEYCODE_BACK && hasVisibleDrawer()) {
1225791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell            KeyEventCompat.startTracking(event);
1226791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell            return true;
1227791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        }
1228791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        return super.onKeyDown(keyCode, event);
1229791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    }
1230791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell
1231791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    @Override
1232791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    public boolean onKeyUp(int keyCode, KeyEvent event) {
12330492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell        if (keyCode == KeyEvent.KEYCODE_BACK) {
12340492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            final View visibleDrawer = findVisibleDrawer();
12350492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            if (visibleDrawer != null && getDrawerLockMode(visibleDrawer) == LOCK_MODE_UNLOCKED) {
12360492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                closeDrawers();
12370492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            }
12380492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            return visibleDrawer != null;
1239791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        }
1240791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell        return super.onKeyUp(keyCode, event);
1241791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell    }
1242791f31bbba40b8b51694a1b2cdc804f360786ed1Adam Powell
124357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    @Override
124457902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    protected void onRestoreInstanceState(Parcelable state) {
124557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        final SavedState ss = (SavedState) state;
124657902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        super.onRestoreInstanceState(ss.getSuperState());
124757902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
124857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        if (ss.openDrawerGravity != Gravity.NO_GRAVITY) {
124957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            final View toOpen = findDrawerWithGravity(ss.openDrawerGravity);
125057902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            if (toOpen != null) {
125157902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                openDrawer(toOpen);
125257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            }
125357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        }
12548e01d24e718d603974182cd48f648369c07edec1Adam Powell
12558e01d24e718d603974182cd48f648369c07edec1Adam Powell        setDrawerLockMode(ss.lockModeLeft, Gravity.LEFT);
12568e01d24e718d603974182cd48f648369c07edec1Adam Powell        setDrawerLockMode(ss.lockModeRight, Gravity.RIGHT);
125757902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    }
125857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
125957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    @Override
126057902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    protected Parcelable onSaveInstanceState() {
126157902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        final Parcelable superState = super.onSaveInstanceState();
126257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
126357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        final SavedState ss = new SavedState(superState);
126457902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
126557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        final int childCount = getChildCount();
126657902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        for (int i = 0; i < childCount; i++) {
126757902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            final View child = getChildAt(i);
126857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            if (!isDrawerView(child)) {
126957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                continue;
127057902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            }
127157902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
127257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
127357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            if (lp.knownOpen) {
127457902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                ss.openDrawerGravity = lp.gravity;
127557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                // Only one drawer can be open at a time.
127657902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                break;
127757902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            }
127857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        }
127957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
12808e01d24e718d603974182cd48f648369c07edec1Adam Powell        ss.lockModeLeft = mLockModeLeft;
12818e01d24e718d603974182cd48f648369c07edec1Adam Powell        ss.lockModeRight = mLockModeRight;
12828e01d24e718d603974182cd48f648369c07edec1Adam Powell
128357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        return ss;
128457902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    }
128557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
128657902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    /**
128757902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell     * State persisted across instances
128857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell     */
128957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    protected static class SavedState extends BaseSavedState {
129057902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        int openDrawerGravity = Gravity.NO_GRAVITY;
12918e01d24e718d603974182cd48f648369c07edec1Adam Powell        int lockModeLeft = LOCK_MODE_UNLOCKED;
12928e01d24e718d603974182cd48f648369c07edec1Adam Powell        int lockModeRight = LOCK_MODE_UNLOCKED;
129357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
129457902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        public SavedState(Parcel in) {
129557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            super(in);
129657902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            openDrawerGravity = in.readInt();
129757902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        }
129857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
129957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        public SavedState(Parcelable superState) {
130057902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            super(superState);
130157902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        }
130257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
130357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        @Override
130457902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        public void writeToParcel(Parcel dest, int flags) {
130557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            super.writeToParcel(dest, flags);
130657902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            dest.writeInt(openDrawerGravity);
130757902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        }
130857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
130957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        public static final Parcelable.Creator<SavedState> CREATOR =
131057902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                new Parcelable.Creator<SavedState>() {
131157902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            @Override
131257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            public SavedState createFromParcel(Parcel source) {
131357902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                return new SavedState(source);
131457902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            }
131557902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
131657902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            @Override
131757902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            public SavedState[] newArray(int size) {
131857902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell                return new SavedState[size];
131957902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell            }
132057902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell        };
132157902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell    }
132257902cff6c54c245feea589b06d12dba8f1a2a24Adam Powell
13231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private class ViewDragCallback extends ViewDragHelper.Callback {
1324f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette        private final int mAbsGravity;
13251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        private ViewDragHelper mDragger;
13261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13271732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        private final Runnable mPeekRunnable = new Runnable() {
13281732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell            @Override public void run() {
13291732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell                peekDrawer();
13301732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell            }
13311732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        };
13321732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell
13331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public ViewDragCallback(int gravity) {
1334f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            mAbsGravity = gravity;
13351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
13361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void setDragger(ViewDragHelper dragger) {
13381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mDragger = dragger;
13391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
13401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13411732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        public void removeCallbacks() {
13421732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell            DrawerLayout.this.removeCallbacks(mPeekRunnable);
13431732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        }
13441732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell
13451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
13461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public boolean tryCaptureView(View child, int pointerId) {
13471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            // Only capture views where the gravity matches what we're looking for.
13481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            // This lets us use two ViewDragHelpers, one for each side drawer.
1349f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            return isDrawerView(child) && checkDrawerViewAbsoluteGravity(child, mAbsGravity)
1350f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                    && getDrawerLockMode(child) == LOCK_MODE_UNLOCKED;
13511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
13521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
13541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onViewDragStateChanged(int state) {
1355f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            updateDrawerState(mAbsGravity, state, mDragger.getCapturedView());
13561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
13571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
13591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
13601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            float offset;
13611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int childWidth = changedView.getWidth();
13621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            // This reverses the positioning shown in onLayout.
1364f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            if (checkDrawerViewAbsoluteGravity(changedView, Gravity.LEFT)) {
13651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                offset = (float) (childWidth + left) / childWidth;
13661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
13671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int width = getWidth();
13681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                offset = (float) (width - left) / childWidth;
13691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
13701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            setDrawerViewOffset(changedView, offset);
1371b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            changedView.setVisibility(offset == 0 ? INVISIBLE : VISIBLE);
13721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            invalidate();
13731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
13741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
13761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onViewCaptured(View capturedChild, int activePointerId) {
13771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final LayoutParams lp = (LayoutParams) capturedChild.getLayoutParams();
13781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            lp.isPeeking = false;
13791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            closeOtherDrawer();
13811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
13821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        private void closeOtherDrawer() {
1384f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            final int otherGrav = mAbsGravity == Gravity.LEFT ? Gravity.RIGHT : Gravity.LEFT;
13851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View toClose = findDrawerWithGravity(otherGrav);
13861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (toClose != null) {
13871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                closeDrawer(toClose);
13881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
13891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
13901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
13921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onViewReleased(View releasedChild, float xvel, float yvel) {
13931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            // Offset is how open the drawer is, therefore left/right values
13941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            // are reversed from one another.
13951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final float offset = getDrawerViewOffset(releasedChild);
13961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int childWidth = releasedChild.getWidth();
13971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
13981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            int left;
1399f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            if (checkDrawerViewAbsoluteGravity(releasedChild, Gravity.LEFT)) {
14001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                left = xvel > 0 || xvel == 0 && offset > 0.5f ? 0 : -childWidth;
14011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
14021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int width = getWidth();
14037d690eb050d901c7a7b4ebc3896471124ef98f7cAdam Powell                left = xvel < 0 || xvel == 0 && offset > 0.5f ? width - childWidth : width;
14041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
14051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
14061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mDragger.settleCapturedViewAt(left, releasedChild.getTop());
14071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            invalidate();
14081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
14091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
14101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
14111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onEdgeTouched(int edgeFlags, int pointerId) {
14121732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell            postDelayed(mPeekRunnable, PEEK_DELAY);
14131732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        }
14141732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell
14151732720ad57fe6d01392cd06551f1a25cff0333cAdam Powell        private void peekDrawer() {
14161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View toCapture;
14171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int childLeft;
1418ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell            final int peekDistance = mDragger.getEdgeSize();
1419f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            final boolean leftEdge = mAbsGravity == Gravity.LEFT;
1420b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            if (leftEdge) {
14211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                toCapture = findDrawerWithGravity(Gravity.LEFT);
1422ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell                childLeft = (toCapture != null ? -toCapture.getWidth() : 0) + peekDistance;
14231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
14241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                toCapture = findDrawerWithGravity(Gravity.RIGHT);
1425ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell                childLeft = getWidth() - peekDistance;
14261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
14270492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            // Only peek if it would mean making the drawer more visible and the drawer isn't locked
1428b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell            if (toCapture != null && ((leftEdge && toCapture.getLeft() < childLeft) ||
14290492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                    (!leftEdge && toCapture.getLeft() > childLeft)) &&
14300492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell                    getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) {
1431b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                final LayoutParams lp = (LayoutParams) toCapture.getLayoutParams();
14321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mDragger.smoothSlideViewTo(toCapture, childLeft, toCapture.getTop());
1433b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell                lp.isPeeking = true;
14341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                invalidate();
14351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
14361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                closeOtherDrawer();
1437cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell
1438cde2707260e8241ffb816a03cbf5d52c28004b8aAdam Powell                cancelChildViewTouch();
14391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
14401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
14411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
14421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
1443ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell        public boolean onEdgeLock(int edgeFlags) {
1444ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell            if (ALLOW_EDGE_LOCK) {
1445f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette                final View drawer = findDrawerWithGravity(mAbsGravity);
1446ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell                if (drawer != null && !isDrawerOpen(drawer)) {
1447ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell                    closeDrawer(drawer);
1448ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell                }
1449ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell                return true;
1450acc82321ad119706485db342eaa12b225fa9b667Adam Powell            }
1451ea7b10f4d5531713506e98c8093e7aab811f21f3Adam Powell            return false;
1452acc82321ad119706485db342eaa12b225fa9b667Adam Powell        }
1453acc82321ad119706485db342eaa12b225fa9b667Adam Powell
1454acc82321ad119706485db342eaa12b225fa9b667Adam Powell        @Override
14551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
14561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View toCapture;
14571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if ((edgeFlags & ViewDragHelper.EDGE_LEFT) == ViewDragHelper.EDGE_LEFT) {
14581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                toCapture = findDrawerWithGravity(Gravity.LEFT);
14591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
14601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                toCapture = findDrawerWithGravity(Gravity.RIGHT);
14611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
14621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
14630492ea23e32dbf509a7613d29e5791fdd44b2135Adam Powell            if (toCapture != null && getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) {
14641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mDragger.captureChildView(toCapture, pointerId);
14651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
14661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
14671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
14681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
14691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public int getViewHorizontalDragRange(View child) {
14701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            return child.getWidth();
14711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
14721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
14731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
14741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public int clampViewPositionHorizontal(View child, int left, int dx) {
1475f55dfacb0db5da12ad3b9e5615c3feaea372f37dAlan Viverette            if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
14761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                return Math.max(-child.getWidth(), Math.min(left, 0));
14771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
14781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int width = getWidth();
14791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                return Math.max(width - child.getWidth(), Math.min(left, width));
14801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
14811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
148200ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell
148300ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell        @Override
148400ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell        public int clampViewPositionVertical(View child, int top, int dy) {
148500ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell            return child.getTop();
148600ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell        }
14871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
14881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
148900ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
14901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
14911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public int gravity = Gravity.NO_GRAVITY;
1492b562d856f6ff58b7fc421a3b0cd1e0e089b994abAdam Powell        float onScreen;
14931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        boolean isPeeking;
14941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        boolean knownOpen;
14951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
14961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public LayoutParams(Context c, AttributeSet attrs) {
14971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            super(c, attrs);
14981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
14991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
15001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            this.gravity = a.getInt(0, Gravity.NO_GRAVITY);
15011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            a.recycle();
15021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
15031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
15041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public LayoutParams(int width, int height) {
15051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            super(width, height);
15061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
15071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
15081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public LayoutParams(int width, int height, int gravity) {
15091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            this(width, height);
15101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            this.gravity = gravity;
15111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
15121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
15131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public LayoutParams(LayoutParams source) {
15141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            super(source);
15151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            this.gravity = source.gravity;
15161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
15171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
15181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public LayoutParams(ViewGroup.LayoutParams source) {
15191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            super(source);
15201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
152100ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell
152200ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell        public LayoutParams(ViewGroup.MarginLayoutParams source) {
152300ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell            super(source);
152400ca2532981fbd705f947a637ffd967a8d6f733bAdam Powell        }
15251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
15267d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell
15277d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell    class AccessibilityDelegate extends AccessibilityDelegateCompat {
15283cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell        private final Rect mTmpRect = new Rect();
15293cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell
15307d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell        @Override
15317d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
15323cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            final AccessibilityNodeInfoCompat superNode = AccessibilityNodeInfoCompat.obtain(info);
15333cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            super.onInitializeAccessibilityNodeInfo(host, superNode);
15343cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell
15353cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            info.setSource(host);
15363cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            final ViewParent parent = ViewCompat.getParentForAccessibility(host);
15373cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            if (parent instanceof View) {
15383cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell                info.setParent((View) parent);
15393cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            }
15403cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            copyNodeInfoNoChildren(info, superNode);
15413cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell
15423cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            superNode.recycle();
15433cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell
1544d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette            addChildrenForAccessibility(info, (ViewGroup) host);
1545d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette        }
1546d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette
1547d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette        private void addChildrenForAccessibility(AccessibilityNodeInfoCompat info, ViewGroup v) {
1548d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette            final int childCount = v.getChildCount();
15497d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell            for (int i = 0; i < childCount; i++) {
1550d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                final View child = v.getChildAt(i);
1551d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                if (filter(child)) {
1552d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                    continue;
1553d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                }
1554d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette
1555d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                // Adding children that are marked as not important for
1556d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                // accessibility will break the hierarchy, so we need to check
1557d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                // that value and re-parent views if necessary.
1558d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                final int importance = ViewCompat.getImportantForAccessibility(child);
1559d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                switch (importance) {
1560d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                    case ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS:
1561d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                        // Always skip NO_HIDE views and their descendants.
1562d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                        break;
1563d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                    case ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO:
1564d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                        // Re-parent children of NO view groups, skip NO views.
1565d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                        if (child instanceof ViewGroup) {
1566d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                            addChildrenForAccessibility(info, (ViewGroup) child);
1567d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                        }
1568d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                        break;
1569d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                    case ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO:
1570d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                        // Force AUTO views to YES and add them.
1571d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                        ViewCompat.setImportantForAccessibility(
1572d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                                child, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
1573d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                    case ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES:
1574d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                        info.addChild(child);
1575d6edbe712f21ea4924ab9fb49ebd8c94d1e03884Alan Viverette                        break;
15767d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell                }
15777d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell            }
15787d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell        }
15797d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell
15807d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell        @Override
15817d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
15827d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell                AccessibilityEvent event) {
15837d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell            if (!filter(child)) {
15847d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell                return super.onRequestSendAccessibilityEvent(host, child, event);
15857d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell            }
15867d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell            return false;
15877d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell        }
15887d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell
15897d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell        public boolean filter(View child) {
15907d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell            final View openDrawer = findOpenDrawer();
15917d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell            return openDrawer != null && openDrawer != child;
15927d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell        }
15933cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell
15943cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell        /**
15953cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell         * This should really be in AccessibilityNodeInfoCompat, but there unfortunately
15963cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell         * seem to be a few elements that are not easily cloneable using the underlying API.
15973cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell         * Leave it private here as it's not general-purpose useful.
15983cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell         */
15993cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell        private void copyNodeInfoNoChildren(AccessibilityNodeInfoCompat dest,
16003cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell                AccessibilityNodeInfoCompat src) {
16013cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            final Rect rect = mTmpRect;
16023cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell
16033cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            src.getBoundsInParent(rect);
16043cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setBoundsInParent(rect);
16053cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell
16063cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            src.getBoundsInScreen(rect);
16073cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setBoundsInScreen(rect);
16083cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell
16093cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setVisibleToUser(src.isVisibleToUser());
16103cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setPackageName(src.getPackageName());
16113cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setClassName(src.getClassName());
16123cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setContentDescription(src.getContentDescription());
16133cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell
16143cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setEnabled(src.isEnabled());
16153cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setClickable(src.isClickable());
16163cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setFocusable(src.isFocusable());
16173cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setFocused(src.isFocused());
16183cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setAccessibilityFocused(src.isAccessibilityFocused());
16193cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setSelected(src.isSelected());
16203cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.setLongClickable(src.isLongClickable());
16213cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell
16223cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell            dest.addAction(src.getActions());
16233cf6141d516a0a6170823b1bda5c0b6d7500e76cAdam Powell        }
16247d0061d5605a1ac298837bee21c0d4eb4a34bd4eAdam Powell    }
16251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell}
1626