DrawerLayout.java revision 1d26501f0c8e9f3577f651938a03f6b3a1a672c7
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;
241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.support.v4.view.GravityCompat;
251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.support.v4.view.MotionEventCompat;
261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.support.v4.view.ViewCompat;
271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.util.AttributeSet;
281d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.util.Log;
291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.view.Gravity;
301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.view.MotionEvent;
311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.view.View;
321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellimport android.view.ViewGroup;
331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell/**
351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * DrawerLayout acts as a top-level container for window content that allows for
361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * interactive "drawer" views to be pulled out from the edge of the window.
371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell *
381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * <p>Drawer positioning and layout is controlled using the <code>android:layout_gravity</code>
391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * attribute on child views corresponding to </p>
401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell *
411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * <p>As per the Android Design guide, any drawers positioned to the left/start should
421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * always contain content for navigating around the application, whereas any drawers
431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * positioned to the right/end should always contain actions to take on the current content.
441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * This preserves the same navigation left, actions right structure present in the Action Bar
451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell * and elsewhere.</p>
461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell */
471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powellpublic class DrawerLayout extends ViewGroup {
481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private static final String TAG = "DrawerLayout";
491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private static final int INVALID_POINTER = -1;
511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Indicates that any drawers are in an idle, settled state. No animation is in progress.
541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;
561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Indicates that a drawer is currently being dragged by the user.
591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;
611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Indicates that a drawer is in the process of settling to a final position.
641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;
661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private static final int MIN_DRAWER_MARGIN = 64; // dp
681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private static final int DRAWER_PEEK_DISTANCE = 16; // dp
701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private static final int DEFAULT_SCRIM_COLOR = 0x99000000;
721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private static final int[] LAYOUT_ATTRS = new int[] {
741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            android.R.attr.layout_gravity
751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    };
761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private int mMinDrawerMargin;
781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private int mDrawerPeekDistance;
791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private int mScrimColor = DEFAULT_SCRIM_COLOR;
811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private float mScrimOpacity;
821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private Paint mScrimPaint = new Paint();
831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private final ViewDragHelper mLeftDragger;
851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private final ViewDragHelper mRightDragger;
861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private int mDrawerState;
871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private DrawerListener mListener;
891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private float mInitialMotionX;
911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private float mInitialMotionY;
921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Listener for monitoring events about drawers.
951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public interface DrawerListener {
971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        /**
981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * Called when a drawer's position changes.
991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * @param drawerView The child view that was moved
1001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * @param slideOffset The new offset of this drawer within its range, from 0-1
1011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         */
1021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onDrawerSlide(View drawerView, float slideOffset);
1031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        /**
1051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * Called when a drawer has settled in a completely open state.
1061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * The drawer is interactive at this point.
1071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         *
1081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * @param drawerView Drawer view that is now open
1091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         */
1101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onDrawerOpened(View drawerView);
1111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        /**
1131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * Called when a drawer has settled in a completely closed state.
1141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         *
1151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * @param drawerView Drawer view that is now closed
1161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         */
1171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onDrawerClosed(View drawerView);
1181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        /**
1201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * Called when the drawer motion state changes. The new state will
1211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * be one of {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
1221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         *
1231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         * @param newState The new drawer motion state
1241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell         */
1251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onDrawerStateChanged(int newState);
1261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
1271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1281d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public DrawerLayout(Context context) {
1291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        this(context, null);
1301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
1311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public DrawerLayout(Context context, AttributeSet attrs) {
1331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        this(context, attrs, 0);
1341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
1351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public DrawerLayout(Context context, AttributeSet attrs, int defStyle) {
1371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        super(context, attrs, defStyle);
1381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final float density = getResources().getDisplayMetrics().density;
1401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f);
1411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mDrawerPeekDistance = (int) (DRAWER_PEEK_DISTANCE * density + 0.5f);
1421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final ViewDragCallback leftCallback = new ViewDragCallback(Gravity.LEFT);
1441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final ViewDragCallback rightCallback = new ViewDragCallback(Gravity.RIGHT);
1451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mLeftDragger = ViewDragHelper.create(this, 0.5f, leftCallback);
1471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
1481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        leftCallback.setDragger(mLeftDragger);
1491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mRightDragger = ViewDragHelper.create(this, 0.5f, rightCallback);
1511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
1521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        rightCallback.setDragger(mRightDragger);
1531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
1541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
1561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Set a listener to be notified of drawer events.
1571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
1581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param listener Listener to notify when drawer events occur
1591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @see DrawerListener
1601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
1611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void setDrawerListener(DrawerListener listener) {
1621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mListener = listener;
1631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
1641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
1661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Resolve the shared state of all drawers from the component ViewDragHelpers.
1671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Should be called whenever a ViewDragHelper's state changes.
1681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
1691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void updateDrawerState(int forGravity) {
1701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int leftState = mLeftDragger.getViewDragState();
1711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int rightState = mRightDragger.getViewDragState();
1721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int state;
1741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (leftState == STATE_DRAGGING || rightState == STATE_DRAGGING) {
1751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            state = STATE_DRAGGING;
1761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        } else if (leftState == STATE_SETTLING || rightState == STATE_SETTLING) {
1771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            state = STATE_SETTLING;
1781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        } else {
1791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            state = STATE_IDLE;
1801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
1811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (state != mDrawerState) {
1831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mDrawerState = state;
1841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View activeDrawer = findDrawerWithGravity(forGravity);
1851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (state == STATE_IDLE && activeDrawer != null) {
1861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final LayoutParams lp = (LayoutParams) activeDrawer.getLayoutParams();
1871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                if (lp.onscreen == 0) {
1881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    dispatchOnDrawerClosed(activeDrawer);
1891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                } else if (lp.onscreen == 1) {
1901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    dispatchOnDrawerOpened(activeDrawer);
1911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                }
1921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
1931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (mListener != null) {
1941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mListener.onDrawerStateChanged(state);
1951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
1961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
1971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
1981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
1991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void dispatchOnDrawerClosed(View drawerView) {
2001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
2011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (lp.knownOpen) {
2021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            lp.knownOpen = false;
2031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (mListener != null) {
2041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mListener.onDrawerClosed(drawerView);
2051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
2061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
2071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void dispatchOnDrawerOpened(View drawerView) {
2101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
2111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (!lp.knownOpen) {
2121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            lp.knownOpen = true;
2131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (mListener != null) {
2141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mListener.onDrawerOpened(drawerView);
2151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
2161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
2171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void dispatchOnDrawerSlide(View drawerView, float slideOffset) {
2201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (mListener != null) {
2211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mListener.onDrawerSlide(drawerView, slideOffset);
2221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
2231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void setDrawerViewOffset(View drawerView, float slideOffset) {
2261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
2271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (slideOffset == lp.onscreen) {
2281d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            return;
2291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
2301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        lp.onscreen = slideOffset;
2321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        dispatchOnDrawerSlide(drawerView, slideOffset);
2331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    float getDrawerViewOffset(View drawerView) {
2361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return ((LayoutParams) drawerView.getLayoutParams()).onscreen;
2371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    int getDrawerViewGravity(View drawerView) {
2401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
2411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(drawerView));
2421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    boolean checkDrawerViewGravity(View drawerView, int checkFor) {
2451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int absGrav = getDrawerViewGravity(drawerView);
2461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return (absGrav & checkFor) == checkFor;
2471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void moveDrawerToOffset(View drawerView, float slideOffset) {
2501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final float oldOffset = getDrawerViewOffset(drawerView);
2511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int width = drawerView.getWidth();
2521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int oldPos = (int) (width * oldOffset);
2531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int newPos = (int) (width * slideOffset);
2541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int dx = newPos - oldPos;
2551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        drawerView.offsetLeftAndRight(checkDrawerViewGravity(drawerView, Gravity.LEFT) ? dx : -dx);
2571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        setDrawerViewOffset(drawerView, slideOffset);
2581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    View findDrawerWithGravity(int gravity) {
2611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int childCount = getChildCount();
2621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        for (int i = 0; i < childCount; i++) {
2631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View child = getChildAt(i);
2641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int childGravity = getDrawerViewGravity(child);
2651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if ((childGravity & Gravity.HORIZONTAL_GRAVITY_MASK) ==
2661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    (gravity & Gravity.HORIZONTAL_GRAVITY_MASK)) {
2671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                return child;
2681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
2691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
2701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return null;
2711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
2741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Simple gravity to string - only supports LEFT and RIGHT for debugging output.
2751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
2761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param gravity Absolute gravity value
2771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @return LEFT or RIGHT as appropriate, or a hex string
2781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
2791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    static String gravityToString(int gravity) {
2801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
2811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            return "LEFT";
2821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
2831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
2841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            return "RIGHT";
2851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
2861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return Integer.toHexString(gravity);
2871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
2881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
2901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
2911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
2921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
2931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
2941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
2951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
2961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
2971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            throw new IllegalArgumentException(
2981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    "DrawerLayout must be measured with MeasureSpec.EXACTLY.");
2991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
3001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        setMeasuredDimension(widthSize, heightSize);
3021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        // Gravity value for each drawer we've seen. Only one of each permitted.
3041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        int foundDrawers = 0;
3051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int childCount = getChildCount();
3061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        for (int i = 0; i < childCount; i++) {
3071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View child = getChildAt(i);
3081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (child.getVisibility() == GONE) {
3101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                continue;
3111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
3121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (isContentView(child)) {
3141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                // Content views get measured at exactly the layout's size.
3151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                child.measure(widthMeasureSpec, heightMeasureSpec);
3161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else if (isDrawerView(child)) {
3171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int childGravity =
3181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        getDrawerViewGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK;
3191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                if ((foundDrawers & childGravity) != 0) {
3201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    throw new IllegalStateException("Child drawer has absolute gravity " +
3211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                            gravityToString(childGravity) + " but this " + TAG + " already has a " +
3221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                            "drawer view along that edge");
3231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                }
3241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec, mMinDrawerMargin,
3251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        child.getLayoutParams().width);
3261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                child.measure(drawerWidthSpec, heightMeasureSpec);
3271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
3281d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                throw new IllegalStateException("Child " + child + " at index " + i +
3291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        " does not have a valid layout_gravity - must be Gravity.LEFT, " +
3301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        "Gravity.RIGHT or Gravity.NO_GRAVITY");
3311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
3321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
3331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
3341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
3361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected void onLayout(boolean changed, int l, int t, int r, int b) {
3371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int childCount = getChildCount();
3381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        for (int i = 0; i < childCount; i++) {
3391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View child = getChildAt(i);
3401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (child.getVisibility() == GONE) {
3421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                continue;
3431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
3441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (isContentView(child)) {
3461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
3471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else { // Drawer, if it wasn't onMeasure would have thrown an exception.
3481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
3491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int childWidth = child.getMeasuredWidth();
3511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                int childLeft;
3521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                if (checkDrawerViewGravity(child, Gravity.LEFT)) {
3541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    childLeft = -childWidth + (int) (childWidth * lp.onscreen);
3551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                } else { // Right; onMeasure checked for us.
3561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    childLeft = r - l - (int) (childWidth * lp.onscreen);
3571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                }
3581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
3601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
3611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
3621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
3631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
3651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void computeScroll() {
3661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int childCount = getChildCount();
3671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        float scrimOpacity = 0;
3681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        for (int i = 0; i < childCount; i++) {
3691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final float onscreen = ((LayoutParams) getChildAt(i).getLayoutParams()).onscreen;
3701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            scrimOpacity = Math.max(scrimOpacity, onscreen);
3711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
3721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mScrimOpacity = scrimOpacity;
3731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        // "|" used on purpose; both need to run.
3751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (mLeftDragger.continueSettling(true) | mRightDragger.continueSettling(true)) {
3761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            ViewCompat.postInvalidateOnAnimation(this);
3771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
3781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
3791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
3811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
3821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int restoreCount = canvas.save();
3831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final boolean result = super.drawChild(canvas, child, drawingTime);
3841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        canvas.restoreToCount(restoreCount);
3851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (mScrimOpacity > 0 && isContentView(child)) {
3861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;
3871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int imag = (int) (baseAlpha * mScrimOpacity);
3881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int color = imag << 24 | (mScrimColor & 0xffffff);
3891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mScrimPaint.setColor(color);
3901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            canvas.drawRect(0, 0, getWidth(), getHeight(), mScrimPaint);
3921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
3931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return result;
3941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
3951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
3961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    boolean isContentView(View child) {
3971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY;
3981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
3991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    boolean isDrawerView(View child) {
4011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int gravity = ((LayoutParams) child.getLayoutParams()).gravity;
4021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int absGravity = GravityCompat.getAbsoluteGravity(gravity,
4031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                ViewCompat.getLayoutDirection(child));
4041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return (absGravity & (Gravity.LEFT | Gravity.RIGHT)) != 0;
4051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
4061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
4081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public boolean onInterceptTouchEvent(MotionEvent ev) {
4091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int action = MotionEventCompat.getActionMasked(ev);
4101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        // "|" used deliberately here; both methods should be invoked.
4121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final boolean interceptForDrag = mLeftDragger.shouldInterceptTouchEvent(ev) |
4131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mRightDragger.shouldInterceptTouchEvent(ev);
4141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        boolean interceptForTap = false;
4161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        switch (action) {
4181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_DOWN: {
4191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float x = ev.getX();
4201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float y = ev.getY();
4211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mInitialMotionX = x;
4221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mInitialMotionY = y;
4231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                if (mScrimOpacity > 0 &&
4241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        isContentView(mLeftDragger.findTopChildUnder((int) x, (int) y))) {
4251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    interceptForTap = true;
4261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                }
4271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                break;
4281d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
4291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_CANCEL:
4311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_UP: {
4321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                closeDrawers(true);
4331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
4341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
4351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return interceptForDrag || interceptForTap;
4361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
4371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
4391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
4401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        super.requestDisallowInterceptTouchEvent(disallowIntercept);
4411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (disallowIntercept) {
4421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            closeDrawers(true);
4431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
4441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
4451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
4471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public boolean onTouchEvent(MotionEvent ev) {
4481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mLeftDragger.processTouchEvent(ev);
4491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        mRightDragger.processTouchEvent(ev);
4501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int action = ev.getAction();
4521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        boolean wantTouchEvents = true;
4531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        switch (action & MotionEventCompat.ACTION_MASK) {
4551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_DOWN: {
4561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float x = ev.getX();
4571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float y = ev.getY();
4581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mInitialMotionX = x;
4591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mInitialMotionY = y;
4601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                break;
4611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
4621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_UP: {
4641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float x = ev.getX();
4651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final float y = ev.getY();
4661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                boolean peekingOnly = true;
4671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                if (isContentView(mLeftDragger.findTopChildUnder((int) x, (int) y))) {
4681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    final float dx = x - mInitialMotionX;
4691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    final float dy = y - mInitialMotionY;
4701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    final int slop = mLeftDragger.getTouchSlop();
4711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    if (dx * dx + dy * dy < slop * slop) {
4721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        // Taps close a dimmed open pane.
4731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        peekingOnly = false;
4741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    }
4751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                }
4761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                closeDrawers(peekingOnly);
4771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                break;
4781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
4791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            case MotionEvent.ACTION_CANCEL: {
4811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                closeDrawers(true);
4821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                break;
4831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
4841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
4851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return wantTouchEvents;
4871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
4881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
4901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Close all currently open drawer views by animating them out of view.
4911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
4921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void closeDrawers() {
4931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        closeDrawers(false);
4941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
4951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
4961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    void closeDrawers(boolean peekingOnly) {
4971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        boolean needsInvalidate = false;
4981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int childCount = getChildCount();
4991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        for (int i = 0; i < childCount; i++) {
5001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View child = getChildAt(i);
5011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
5021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (!isDrawerView(child) || (peekingOnly && !lp.isPeeking)) {
5041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                continue;
5051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
5061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int childWidth = child.getWidth();
5081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (checkDrawerViewGravity(child, Gravity.LEFT)) {
5101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                needsInvalidate |= mLeftDragger.smoothSlideViewTo(child,
5111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        -childWidth, child.getTop());
5121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
5131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                needsInvalidate |= mRightDragger.smoothSlideViewTo(child,
5141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                        getWidth(), child.getTop());
5151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
5161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            lp.isPeeking = false;
5181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (needsInvalidate) {
5211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            invalidate();
5221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
5261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Open the specified drawer view by animating it into view.
5271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
5281d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param drawerView Drawer view to open
5291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
5301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void openDrawer(View drawerView) {
5311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (!isDrawerView(drawerView)) {
5321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
5331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (checkDrawerViewGravity(drawerView, Gravity.LEFT)) {
5361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop());
5371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        } else {
5381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mRightDragger.smoothSlideViewTo(drawerView, getWidth() - drawerView.getWidth(),
5391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    drawerView.getTop());
5401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        invalidate();
5421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
5451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Open the specified drawer by animating it out of view.
5461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
5471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
5481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *                GravityCompat.START or GravityCompat.END may also be used.
5491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
5501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void openDrawer(int gravity) {
5511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int absGravity = GravityCompat.getAbsoluteGravity(gravity,
5521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                ViewCompat.getLayoutDirection(this));
5531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final View drawerView = findDrawerWithGravity(absGravity);
5541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (drawerView == null) {
5561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            throw new IllegalArgumentException("No drawer view found with absolute gravity " +
5571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    gravityToString(absGravity));
5581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        openDrawer(drawerView);
5601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
5631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Close the specified drawer view by animating it into view.
5641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
5651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param drawerView Drawer view to close
5661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
5671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void closeDrawer(View drawerView) {
5681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (!isDrawerView(drawerView)) {
5691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
5701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (checkDrawerViewGravity(drawerView, Gravity.LEFT)) {
5731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mLeftDragger.smoothSlideViewTo(drawerView, -drawerView.getWidth(), drawerView.getTop());
5741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        } else {
5751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mRightDragger.smoothSlideViewTo(drawerView, getWidth(), drawerView.getTop());
5761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        invalidate();
5781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    /**
5811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * Close the specified drawer by animating it out of view.
5821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *
5831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
5841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     *                GravityCompat.START or GravityCompat.END may also be used.
5851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell     */
5861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public void closeDrawer(int gravity) {
5871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final int absGravity = GravityCompat.getAbsoluteGravity(gravity,
5881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                ViewCompat.getLayoutDirection(this));
5891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        final View drawerView = findDrawerWithGravity(absGravity);
5901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        if (drawerView == null) {
5921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            throw new IllegalArgumentException("No drawer view found with absolute gravity " +
5931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                    gravityToString(absGravity));
5941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
5951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        closeDrawer(drawerView);
5961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
5971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
5981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
5991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
6001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
6011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
6021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
6041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
6051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return p instanceof LayoutParams
6061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                ? new LayoutParams((LayoutParams) p)
6071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                : new LayoutParams(p);
6081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
6091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
6111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
6121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return p instanceof LayoutParams && super.checkLayoutParams(p);
6131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
6141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    @Override
6161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
6171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        return new LayoutParams(getContext(), attrs);
6181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
6191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    private class ViewDragCallback extends ViewDragHelper.Callback {
6211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        private final int mGravity;
6231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        private ViewDragHelper mDragger;
6241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public ViewDragCallback(int gravity) {
6261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mGravity = gravity;
6271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
6281d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void setDragger(ViewDragHelper dragger) {
6301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mDragger = dragger;
6311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
6321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
6341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public boolean tryCaptureView(View child, int pointerId) {
6351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            // Only capture views where the gravity matches what we're looking for.
6361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            // This lets us use two ViewDragHelpers, one for each side drawer.
6371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            return isDrawerView(child) && checkDrawerViewGravity(child, mGravity);
6381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
6391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
6411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onViewDragStateChanged(int state) {
6421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            updateDrawerState(mGravity);
6431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
6441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
6461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
6471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            float offset;
6481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int childWidth = changedView.getWidth();
6491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            // This reverses the positioning shown in onLayout.
6511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (checkDrawerViewGravity(changedView, Gravity.LEFT)) {
6521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                offset = (float) (childWidth + left) / childWidth;
6531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
6541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int width = getWidth();
6551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                offset = (float) (width - left) / childWidth;
6561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
6571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            setDrawerViewOffset(changedView, offset);
6581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            invalidate();
6591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
6601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
6621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onViewCaptured(View capturedChild, int activePointerId) {
6631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final LayoutParams lp = (LayoutParams) capturedChild.getLayoutParams();
6641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            lp.isPeeking = false;
6651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            closeOtherDrawer();
6671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
6681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        private void closeOtherDrawer() {
6701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int otherGrav = mGravity == Gravity.LEFT ? Gravity.RIGHT : Gravity.LEFT;
6711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View toClose = findDrawerWithGravity(otherGrav);
6721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (toClose != null) {
6731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                closeDrawer(toClose);
6741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
6751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
6761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
6781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onViewReleased(View releasedChild, float xvel, float yvel) {
6791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            // Offset is how open the drawer is, therefore left/right values
6801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            // are reversed from one another.
6811d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final float offset = getDrawerViewOffset(releasedChild);
6821d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int childWidth = releasedChild.getWidth();
6831d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6841d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            int left;
6851d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (checkDrawerViewGravity(releasedChild, Gravity.LEFT)) {
6861d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                left = xvel > 0 || xvel == 0 && offset > 0.5f ? 0 : -childWidth;
6871d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
6881d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int width = getWidth();
6891d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                left = xvel < 0 || xvel == 0 && offset < 0.5f ? width - childWidth : width;
6901d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
6911d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6921d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            mDragger.settleCapturedViewAt(left, releasedChild.getTop());
6931d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            invalidate();
6941d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
6951d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
6961d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
6971d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onEdgeTouched(int edgeFlags, int pointerId) {
6981d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View toCapture;
6991d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final int childLeft;
7001d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if ((edgeFlags & ViewDragHelper.EDGE_LEFT) == ViewDragHelper.EDGE_LEFT) {
7011d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                toCapture = findDrawerWithGravity(Gravity.LEFT);
7021d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                childLeft = -toCapture.getWidth() + mDrawerPeekDistance;
7031d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
7041d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                toCapture = findDrawerWithGravity(Gravity.RIGHT);
7051d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                childLeft = getWidth() - mDrawerPeekDistance;
7061d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
7071d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7081d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (toCapture != null) {
7091d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mDragger.smoothSlideViewTo(toCapture, childLeft, toCapture.getTop());
7101d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                ((LayoutParams) toCapture.getLayoutParams()).isPeeking = true;
7111d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                invalidate();
7121d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7131d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                closeOtherDrawer();
7141d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
7151d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7161d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7171d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
7181d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
7191d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final View toCapture;
7201d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if ((edgeFlags & ViewDragHelper.EDGE_LEFT) == ViewDragHelper.EDGE_LEFT) {
7211d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                toCapture = findDrawerWithGravity(Gravity.LEFT);
7221d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
7231d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                toCapture = findDrawerWithGravity(Gravity.RIGHT);
7241d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
7251d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7261d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (toCapture != null) {
7271d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                mDragger.captureChildView(toCapture, pointerId);
7281d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
7291d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7301d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7311d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
7321d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public int getViewHorizontalDragRange(View child) {
7331d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            return child.getWidth();
7341d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7351d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7361d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        @Override
7371d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public int clampViewPositionHorizontal(View child, int left, int dx) {
7381d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            if (checkDrawerViewGravity(child, Gravity.LEFT)) {
7391d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                return Math.max(-child.getWidth(), Math.min(left, 0));
7401d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            } else {
7411d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                final int width = getWidth();
7421d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell                return Math.max(width - child.getWidth(), Math.min(left, width));
7431d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            }
7441d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7451d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
7461d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7471d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    public static class LayoutParams extends ViewGroup.LayoutParams {
7481d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7491d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public int gravity = Gravity.NO_GRAVITY;
7501d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        float onscreen;
7511d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        boolean isPeeking;
7521d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        boolean knownOpen;
7531d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7541d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public LayoutParams(Context c, AttributeSet attrs) {
7551d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            super(c, attrs);
7561d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7571d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            final TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
7581d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            this.gravity = a.getInt(0, Gravity.NO_GRAVITY);
7591d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            a.recycle();
7601d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7611d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7621d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public LayoutParams(int width, int height) {
7631d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            super(width, height);
7641d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7651d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7661d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public LayoutParams(int width, int height, int gravity) {
7671d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            this(width, height);
7681d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            this.gravity = gravity;
7691d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7701d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7711d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public LayoutParams(LayoutParams source) {
7721d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            super(source);
7731d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            this.gravity = source.gravity;
7741d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7751d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell
7761d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        public LayoutParams(ViewGroup.LayoutParams source) {
7771d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell            super(source);
7781d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell        }
7791d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell    }
7801d26501f0c8e9f3577f651938a03f6b3a1a672c7Adam Powell}
781