first implementation of sliding panel
diff --git a/res/drawable/bg_108.png b/res/drawable/bg_108.png
new file mode 100644
index 0000000..ef5b1b4
--- /dev/null
+++ b/res/drawable/bg_108.png
Binary files differ
diff --git a/res/drawable/bg_144.png b/res/drawable/bg_144.png
new file mode 100644
index 0000000..f6db8e2
--- /dev/null
+++ b/res/drawable/bg_144.png
Binary files differ
diff --git a/res/drawable/bg_216.png b/res/drawable/bg_216.png
new file mode 100644
index 0000000..b7270e9
--- /dev/null
+++ b/res/drawable/bg_216.png
Binary files differ
diff --git a/res/layout/activity_sflphone_home.xml b/res/layout/activity_sflphone_home.xml
index 946c05b..f13a251 100644
--- a/res/layout/activity_sflphone_home.xml
+++ b/res/layout/activity_sflphone_home.xml
@@ -36,52 +36,55 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent" >
 
-    <RelativeLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res/org.sflphone"
+    <org.sflphone.views.SlidingUpPanelLayout
+        android:id="@+id/contact_panel"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical" >
+        android:layout_height="match_parent" >
 
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="?android:attr/actionBarSize"
-            android:layout_alignParentTop="true"
-            android:background="@color/sfl_dark_blue" />
-
-        <org.sflphone.views.PagerSlidingTabStrip
-            android:id="@+id/pts_main"
-            android:layout_width="match_parent"
-            android:layout_height="?android:attr/actionBarSize"
-            android:layout_alignParentTop="true"
-            android:layout_marginTop="?android:attr/actionBarSize"
-            android:background="@color/sfl_blue_0"
-            app:indicatorColor="@color/sfl_light_blue"
-            app:underlineColor="@color/sfl_light_blue" />
-
-        <android.support.v4.view.ViewPager
-            android:id="@+id/pager"
+        <RelativeLayout
+            xmlns:app="http://schemas.android.com/apk/res/org.sflphone"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:layout_below="@+id/pts_main"
-            android:paddingBottom="@dimen/contact_drawer_handle_height" />
+            android:orientation="vertical" >
 
-        <ImageView
-            android:id="@+id/overall_shadow"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:alpha="0"
-            android:background="@color/black"
-            android:clickable="false"
-            android:focusable="false" />
+            <ImageView
+                android:layout_width="match_parent"
+                android:layout_height="?android:attr/actionBarSize"
+                android:layout_alignParentTop="true"
+                android:background="@color/sfl_dark_blue" />
 
-        <include
-            android:id="@+id/custom_sliding_drawer"
+            <org.sflphone.views.PagerSlidingTabStrip
+                android:id="@+id/pts_main"
+                android:layout_width="match_parent"
+                android:layout_height="?android:attr/actionBarSize"
+                android:layout_alignParentTop="true"
+                android:layout_marginTop="?android:attr/actionBarSize"
+                android:background="@color/sfl_blue_0"
+                app:indicatorColor="@color/sfl_light_blue"
+                app:underlineColor="@color/sfl_light_blue" />
+
+            <android.support.v4.view.ViewPager
+                android:id="@+id/pager"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_below="@+id/pts_main"
+                android:paddingBottom="@dimen/contact_drawer_handle_height" />
+
+            <ImageView
+                android:id="@+id/overall_shadow"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:alpha="0"
+                android:background="@color/black"
+                android:clickable="false"
+                android:focusable="false" />
+        </RelativeLayout>
+
+        <FrameLayout
+            android:id="@+id/contacts_frame"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentBottom="true"
-            layout="@layout/contact_drawer" />
-    </RelativeLayout>
+            android:layout_height="match_parent" />
+    </org.sflphone.views.SlidingUpPanelLayout>
 
     <FrameLayout
         android:id="@+id/left_drawer"
diff --git a/res/layout/contact_drawer.xml b/res/layout/contact_drawer.xml
index d435548..f2dc4e2 100644
--- a/res/layout/contact_drawer.xml
+++ b/res/layout/contact_drawer.xml
@@ -44,24 +44,6 @@
         android:layout_width="match_parent"
         android:layout_height="72dp" >
 
-<!--         <ImageView -->
-<!--             android:id="@+id/menu_top_shadow_left" -->
-<!--             android:layout_width="0dp" -->
-<!--             android:layout_height="4dp" -->
-<!--             android:layout_above="@+id/coucou" -->
-<!--             android:layout_alignParentLeft="true" -->
-<!--             android:layout_toLeftOf="@+id/hello" -->
-<!--             android:src="@drawable/defaultshadowtop" /> -->
-
-<!--         <ImageView -->
-<!--             android:id="@+id/menu_top_shadow_right" -->
-<!--             android:layout_width="0dp" -->
-<!--             android:layout_height="4dp" -->
-<!--             android:layout_above="@+id/coucou" -->
-<!--             android:layout_alignParentRight="true" -->
-<!--             android:layout_toRightOf="@+id/hello" -->
-<!--             android:src="@drawable/defaultshadowtop" /> -->
-
         <RelativeLayout
             android:id="@+id/coucou"
             android:layout_width="match_parent"
diff --git a/res/layout/frag_contact_list.xml b/res/layout/frag_contact_list.xml
index ecbdd41..a668315 100644
--- a/res/layout/frag_contact_list.xml
+++ b/res/layout/frag_contact_list.xml
@@ -36,6 +36,52 @@
     android:layout_height="match_parent"
     android:orientation="vertical" >
 
+    <RelativeLayout
+        android:id="@+id/slider_button"
+        android:layout_width="match_parent"
+        android:layout_height="68dp" >
+
+        <RelativeLayout
+            android:id="@+id/coucou"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/contact_drawer_handle_height"
+            android:layout_alignParentBottom="true"
+            android:background="@color/sfl_dark_blue" >
+
+            <TextView
+                android:id="@+id/handle_title"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_alignParentBottom="true"
+                android:layout_centerInParent="true"
+                android:gravity="center"
+                android:text="Contacts"
+                android:textColor="@color/white"
+                android:textStyle="bold" />
+
+            <ImageButton
+                android:id="@+id/contact_search_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentBottom="true"
+                android:layout_alignParentRight="true"
+                android:background="@color/sfl_dark_blue"
+                android:gravity="center"
+                android:src="@drawable/ic_btn_search" >
+            </ImageButton>
+        </RelativeLayout>
+
+        <!-- Declared after for implicit z order -->
+
+        <org.sflphone.views.HalfCircleImageView
+            android:id="@+id/hello"
+            android:layout_width="112dp"
+            android:layout_height="68dp"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:src="@drawable/ic_action_group" />
+    </RelativeLayout>
+
     <org.sflphone.views.stickylistheaders.StickyListHeadersListView
         android:id="@+id/contacts_list"
         android:layout_width="match_parent"
diff --git a/src/org/sflphone/client/HomeActivity.java b/src/org/sflphone/client/HomeActivity.java
index 8e9833b..854420f 100644
--- a/src/org/sflphone/client/HomeActivity.java
+++ b/src/org/sflphone/client/HomeActivity.java
@@ -43,7 +43,6 @@
 import org.sflphone.fragments.HomeFragment;
 import org.sflphone.fragments.MenuFragment;
 import org.sflphone.interfaces.CallInterface;
-import org.sflphone.loaders.LoaderConstants;
 import org.sflphone.model.CallContact;
 import org.sflphone.model.Conference;
 import org.sflphone.model.SipCall;
@@ -51,9 +50,9 @@
 import org.sflphone.service.CallManagerCallBack;
 import org.sflphone.service.ISipService;
 import org.sflphone.service.SipService;
-import org.sflphone.views.CustomSlidingDrawer;
-import org.sflphone.views.CustomSlidingDrawer.OnDrawerScrollListener;
 import org.sflphone.views.PagerSlidingTabStrip;
+import org.sflphone.views.SlidingUpPanelLayout;
+import org.sflphone.views.SlidingUpPanelLayout.PanelSlideListener;
 
 import android.app.Activity;
 import android.app.AlertDialog;
@@ -65,6 +64,7 @@
 import android.content.ServiceConnection;
 import android.content.res.Configuration;
 import android.database.Cursor;
+import android.graphics.Color;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -103,7 +103,7 @@
     private static final int REQUEST_CODE_CALL = 2;
 
     RelativeLayout mSliderButton;
-    CustomSlidingDrawer mContactDrawer;
+    SlidingUpPanelLayout mContactDrawer;
     private DrawerLayout mNavigationDrawer;
     private ActionBarDrawerToggle mDrawerToggle;
     ImageView mShadow;
@@ -116,10 +116,6 @@
     private boolean isClosing = false;
     private Timer t = new Timer();
 
-    // private TabHost mTabHost;
-
-    // public SFLPhoneHome extends Activity implements ActionBar.TabListener, OnClickListener
-
     /* called before activity is killed, e.g. rotation */
     @Override
     protected void onSaveInstanceState(Bundle bundle) {
@@ -152,37 +148,46 @@
             getFragmentManager().beginTransaction().replace(R.id.contacts_frame, mContactsFragment).commit();
         }
 
-        mContactDrawer = (CustomSlidingDrawer) findViewById(R.id.custom_sliding_drawer);
-
-        mContactDrawer.setOnDrawerScrollListener(new OnDrawerScrollListener() {
+        mContactDrawer = (SlidingUpPanelLayout) findViewById(R.id.contact_panel);
+        // mContactDrawer.setShadowDrawable(getResources().getDrawable(R.drawable.above_shadow));
+        mContactDrawer.setAnchorPoint(0.3f);
+        mContactDrawer.setDragView(findViewById(R.id.contacts_frame));
+        mContactDrawer.setEnableDragViewTouchEvents(true);
+//        mContactDrawer.setCoveredFadeColor(0xff000000);
+        mContactDrawer.setPanelSlideListener(new PanelSlideListener() {
 
             @Override
-            public void onScrollStarted() {
-                // getActionBar().hide();
-
-            }
-
-            @Override
-            public void onScrollEnded() {
-
-            }
-
-            @Override
-            public void onScroll(int offset) {
-
-                if (offset < 400) {
-                    getActionBar().hide();
-                    // mNavigationDrawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
-                } else if (offset > 450) {
-                    getActionBar().show();
-                    // mNavigationDrawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
+            public void onPanelSlide(View panel, float slideOffset) {
+                if (slideOffset < 0.2) {
+                    if (getActionBar().isShowing()) {
+                        getActionBar().hide();
+                    }
+                } else {
+                    if (!getActionBar().isShowing()) {
+                        getActionBar().show();
+                    }
                 }
             }
+
+            @Override
+            public void onPanelExpanded(View panel) {
+
+            }
+
+            @Override
+            public void onPanelCollapsed(View panel) {
+
+            }
+
+            @Override
+            public void onPanelAnchored(View panel) {
+
+            }
         });
 
-        mContactsFragment.setHandleView((RelativeLayout) findViewById(R.id.slider_button));
+        // TODO
+        // mContactsFragment.setHandleView((RelativeLayout) findViewById(R.id.slider_button));
         mShadow = (ImageView) findViewById(R.id.overall_shadow);
-        mContactDrawer.setmTrackHandle(findViewById(R.id.slider_button));
 
         // Set up the ViewPager with the sections adapter.
         mViewPager = (ViewPager) findViewById(R.id.pager);
@@ -226,7 +231,7 @@
         super.onPostCreate(savedInstanceState);
         // Sync the toggle state after onRestoreInstanceState has occurred.
         mDrawerToggle.syncState();
-        if (mContactDrawer.isOpened()) {
+        if (mContactDrawer.isExpanded()) {
             getActionBar().hide();
         }
     }
@@ -269,16 +274,9 @@
             mNavigationDrawer.closeDrawer(Gravity.LEFT);
             return;
         }
-        if (getActionBar().getCustomView() != null) {
-            getActionBar().setDisplayShowCustomEnabled(false);
-            getActionBar().setCustomView(null);
-            // Display all the contacts again
-            getLoaderManager().restartLoader(LoaderConstants.CONTACT_LOADER, null, mContactsFragment);
-            return;
-        }
 
-        if (mContactDrawer.isOpened()) {
-            mContactDrawer.animateClose();
+        if (mContactDrawer.isExpanded() || mContactDrawer.isAnchored()) {
+            mContactDrawer.collapsePane();
             return;
         }
 
@@ -501,7 +499,7 @@
             }
         });
         launcher.start();
-        mContactDrawer.animateClose();
+        mContactDrawer.collapsePane();
 
     }
 
@@ -574,12 +572,12 @@
 
     @Override
     public void onContactDragged() {
-        mContactDrawer.animateClose();
+        mContactDrawer.collapsePane();
     }
 
     @Override
     public void openDrawer() {
-        mContactDrawer.animateOpen();
+        mContactDrawer.expandPane();
     }
 
     @Override
diff --git a/src/org/sflphone/fragments/ContactListFragment.java b/src/org/sflphone/fragments/ContactListFragment.java
index 07da1c9..28c0407 100644
--- a/src/org/sflphone/fragments/ContactListFragment.java
+++ b/src/org/sflphone/fragments/ContactListFragment.java
@@ -168,8 +168,20 @@
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         View inflatedView = inflater.inflate(R.layout.frag_contact_list, container, false);
         mHeader = (LinearLayout) inflater.inflate(R.layout.frag_contact_list_header, null);
-        // mPlaceHolder = mHeader.findViewById(R.id.placeholder);
         mContactList = (StickyListHeadersListView) inflatedView.findViewById(R.id.contacts_list);
+        
+        ((ImageButton) inflatedView.findViewById(R.id.contact_search_button)).setOnClickListener(new OnClickListener() {
+
+            @Override
+            public void onClick(View v) {
+                mContactList.smoothScrollToPosition(0);
+                mQuickReturnSearchView.setOnQueryTextListener(ContactListFragment.this);
+                mQuickReturnSearchView.setIconified(false);
+                mQuickReturnSearchView.setFocusable(true);
+                mCallbacks.openDrawer();
+            }
+        });
+        
         mQuickReturnSearchView = (SearchView) mHeader.findViewById(R.id.contact_search);
         mStarredGrid = (GridView) mHeader.findViewById(R.id.favorites_grid);
         llMain = (LinearLayout) mHeader.findViewById(R.id.llMain);
@@ -196,15 +208,6 @@
             }
         });
 
-        // mQuickReturnSearchView.setOnClickListener(new OnClickListener() {
-        //
-        // @Override
-        // public void onClick(View v) {
-        // // TODO Stub de la méthode généré automatiquement
-        //
-        // }
-        // });
-
         getLoaderManager().initLoader(LoaderConstants.CONTACT_LOADER, null, this);
 
     }
@@ -214,9 +217,7 @@
         public boolean onItemLongClick(AdapterView<?> av, View view, int pos, long id) {
             DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view.findViewById(R.id.photo));
             view.startDrag(null, shadowBuilder, view, 0);
-            // view.setVisibility(View.INVISIBLE);
             mCallbacks.onContactDragged();
-            // ((SearchView) mHandle.findViewById(R.id.contact_search_text)).setIconified(true);
             return true;
         }
 
diff --git a/src/org/sflphone/views/SlidingUpPanelLayout.java b/src/org/sflphone/views/SlidingUpPanelLayout.java
new file mode 100644
index 0000000..e53ab79
--- /dev/null
+++ b/src/org/sflphone/views/SlidingUpPanelLayout.java
@@ -0,0 +1,1084 @@
+package org.sflphone.views;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.ViewDragHelper;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.SoundEffectConstants;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+
+public class SlidingUpPanelLayout extends ViewGroup {
+
+    private static final String TAG = SlidingUpPanelLayout.class.getSimpleName();
+
+    /**
+     * Default peeking out panel height
+     */
+    private static final int DEFAULT_PANEL_HEIGHT = 68; // dp;
+
+    /**
+     * Default height of the shadow above the peeking out panel
+     */
+    private static final int DEFAULT_SHADOW_HEIGHT = 4; // dp;
+
+    /**
+     * If no fade color is given by default it will fade to 80% gray.
+     */
+    private static final int DEFAULT_FADE_COLOR = 0x99000000;
+
+    /**
+     * Minimum velocity that will be detected as a fling
+     */
+    private static final int MIN_FLING_VELOCITY = 400; // dips per second
+
+    /**
+     * The fade color used for the panel covered by the slider. 0 = no fading.
+     */
+    private int mCoveredFadeColor = DEFAULT_FADE_COLOR;
+
+    /**
+     * The paint used to dim the main layout when sliding
+     */
+    private final Paint mCoveredFadePaint = new Paint();
+
+    /**
+     * Drawable used to draw the shadow between panes.
+     */
+    private Drawable mShadowDrawable;
+
+    /**
+     * The size of the overhang in pixels.
+     */
+    private int mPanelHeight;
+
+    /**
+     * The size of the shadow in pixels.
+     */
+    private final int mShadowHeight;
+
+    /**
+     * True if a panel can slide with the current measurements
+     */
+    private boolean mCanSlide;
+
+    /**
+     * If provided, the panel can be dragged by only this view. Otherwise, the entire panel can be used for dragging.
+     */
+    private View mDragView;
+
+    /**
+     * The child view that can slide, if any.
+     */
+    private View mSlideableView;
+
+    /**
+     * How far the panel is offset from its expanded position. range [0, 1] where 0 = expanded, 1 = collapsed.
+     */
+    private float mSlideOffset;
+
+    /**
+     * How far in pixels the slideable panel may move.
+     */
+    private int mSlideRange;
+
+    /**
+     * A panel view is locked into internal scrolling or another condition that is preventing a drag.
+     */
+    private boolean mIsUnableToDrag;
+
+    /**
+     * Flag indicating that sliding feature is enabled\disabled
+     */
+    private boolean mIsSlidingEnabled;
+
+    /**
+     * Flag indicating if a drag view can have its own touch events. If set to true, a drag view can scroll horizontally and have its own click
+     * listener.
+     * 
+     * Default is set to false.
+     */
+    private boolean mIsUsingDragViewTouchEvents;
+
+    /**
+     * Threshold to tell if there was a scroll touch event.
+     */
+    private int mScrollTouchSlop;
+
+    private float mInitialMotionX;
+    private float mInitialMotionY;
+    private boolean mDragViewHit;
+    private float mAnchorPoint = 0.f;
+
+    private PanelSlideListener mPanelSlideListener;
+
+    private final ViewDragHelper mDragHelper;
+
+    /**
+     * Stores whether or not the pane was expanded the last time it was slideable. If expand/collapse operations are invoked this state is modified.
+     * Used by instance state save/restore.
+     */
+    private boolean mPreservedExpandedState;
+    private boolean mFirstLayout = true;
+
+    private final Rect mTmpRect = new Rect();
+
+    /**
+     * Listener for monitoring events about sliding panes.
+     */
+    public interface PanelSlideListener {
+        /**
+         * Called when a sliding pane's position changes.
+         * 
+         * @param panel
+         *            The child view that was moved
+         * @param slideOffset
+         *            The new offset of this sliding pane within its range, from 0-1
+         */
+        public void onPanelSlide(View panel, float slideOffset);
+
+        /**
+         * Called when a sliding pane becomes slid completely collapsed. The pane may or may not be interactive at this point depending on if it's
+         * shown or hidden
+         * 
+         * @param panel
+         *            The child view that was slid to an collapsed position, revealing other panes
+         */
+        public void onPanelCollapsed(View panel);
+
+        /**
+         * Called when a sliding pane becomes slid completely expanded. The pane is now guaranteed to be interactive. It may now obscure other views
+         * in the layout.
+         * 
+         * @param panel
+         *            The child view that was slid to a expanded position
+         */
+        public void onPanelExpanded(View panel);
+
+        public void onPanelAnchored(View panel);
+    }
+
+    /**
+     * No-op stubs for {@link PanelSlideListener}. If you only want to implement a subset of the listener methods you can extend this instead of
+     * implement the full interface.
+     */
+    public static class SimplePanelSlideListener implements PanelSlideListener {
+        @Override
+        public void onPanelSlide(View panel, float slideOffset) {
+        }
+
+        @Override
+        public void onPanelCollapsed(View panel) {
+        }
+
+        @Override
+        public void onPanelExpanded(View panel) {
+        }
+
+        @Override
+        public void onPanelAnchored(View panel) {
+        }
+    }
+
+    public SlidingUpPanelLayout(Context context) {
+        this(context, null);
+    }
+
+    public SlidingUpPanelLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SlidingUpPanelLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        final float density = context.getResources().getDisplayMetrics().density;
+        mPanelHeight = (int) (DEFAULT_PANEL_HEIGHT * density + 0.5f);
+        mShadowHeight = (int) (DEFAULT_SHADOW_HEIGHT * density + 0.5f);
+
+        setWillNotDraw(false);
+
+        mDragHelper = ViewDragHelper.create(this, 0.5f, new DragHelperCallback());
+        mDragHelper.setMinVelocity(MIN_FLING_VELOCITY * density);
+
+        mCanSlide = true;
+        mIsSlidingEnabled = true;
+
+        setCoveredFadeColor(DEFAULT_FADE_COLOR);
+
+        ViewConfiguration vc = ViewConfiguration.get(context);
+        mScrollTouchSlop = vc.getScaledTouchSlop();
+    }
+
+    /**
+     * Set the color used to fade the pane covered by the sliding pane out when the pane will become fully covered in the expanded state.
+     * 
+     * @param color
+     *            An ARGB-packed color value
+     */
+    public void setCoveredFadeColor(int color) {
+        mCoveredFadeColor = color;
+        invalidate();
+    }
+
+    /**
+     * @return The ARGB-packed color value used to fade the fixed pane
+     */
+    public int getCoveredFadeColor() {
+        return mCoveredFadeColor;
+    }
+
+    /**
+     * Set the collapsed panel height in pixels
+     * 
+     * @param val
+     *            A height in pixels
+     */
+    public void setPanelHeight(int val) {
+        mPanelHeight = val;
+        requestLayout();
+    }
+
+    /**
+     * @return The current collapsed panel height
+     */
+    public int getPanelHeight() {
+        return mPanelHeight;
+    }
+
+    public void setPanelSlideListener(PanelSlideListener listener) {
+        mPanelSlideListener = listener;
+    }
+
+    /**
+     * Set the draggable view portion. Use to null, to allow the whole panel to be draggable
+     * 
+     * @param dragView
+     *            A view that will be used to drag the panel.
+     */
+    public void setDragView(View dragView) {
+        mDragView = dragView;
+    }
+
+    /**
+     * Set an anchor point where the panel can stop during sliding
+     * 
+     * @param anchorPoint
+     *            A value between 0 and 1, determining the position of the anchor point starting from the top of the layout.
+     */
+    public void setAnchorPoint(float anchorPoint) {
+        if (anchorPoint > 0 && anchorPoint < 1)
+            mAnchorPoint = anchorPoint;
+    }
+
+    /**
+     * Set the shadow for the sliding panel
+     * 
+     */
+    public void setShadowDrawable(Drawable drawable) {
+        mShadowDrawable = drawable;
+    }
+
+    void dispatchOnPanelSlide(View panel) {
+        if (mPanelSlideListener != null) {
+            mPanelSlideListener.onPanelSlide(panel, mSlideOffset);
+        }
+    }
+
+    void dispatchOnPanelExpanded(View panel) {
+        if (mPanelSlideListener != null) {
+            mPanelSlideListener.onPanelExpanded(panel);
+        }
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+    }
+
+    void dispatchOnPanelCollapsed(View panel) {
+        if (mPanelSlideListener != null) {
+            mPanelSlideListener.onPanelCollapsed(panel);
+        }
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+    }
+
+    void dispatchOnPanelAnchored(View panel) {
+        if (mPanelSlideListener != null) {
+            mPanelSlideListener.onPanelAnchored(panel);
+        }
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+    }
+
+    void updateObscuredViewVisibility() {
+        if (getChildCount() == 0) {
+            return;
+        }
+        final int leftBound = getPaddingLeft();
+        final int rightBound = getWidth() - getPaddingRight();
+        final int topBound = getPaddingTop();
+        final int bottomBound = getHeight() - getPaddingBottom();
+        final int left;
+        final int right;
+        final int top;
+        final int bottom;
+        if (mSlideableView != null && hasOpaqueBackground(mSlideableView)) {
+            left = mSlideableView.getLeft();
+            right = mSlideableView.getRight();
+            top = mSlideableView.getTop();
+            bottom = mSlideableView.getBottom();
+        } else {
+            left = right = top = bottom = 0;
+        }
+        View child = getChildAt(0);
+        final int clampedChildLeft = Math.max(leftBound, child.getLeft());
+        final int clampedChildTop = Math.max(topBound, child.getTop());
+        final int clampedChildRight = Math.min(rightBound, child.getRight());
+        final int clampedChildBottom = Math.min(bottomBound, child.getBottom());
+        final int vis;
+        if (clampedChildLeft >= left && clampedChildTop >= top && clampedChildRight <= right && clampedChildBottom <= bottom) {
+            vis = INVISIBLE;
+        } else {
+            vis = VISIBLE;
+        }
+        child.setVisibility(vis);
+    }
+
+    void setAllChildrenVisible() {
+        for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == INVISIBLE) {
+                child.setVisibility(VISIBLE);
+            }
+        }
+    }
+
+    private static boolean hasOpaqueBackground(View v) {
+        final Drawable bg = v.getBackground();
+        if (bg != null) {
+            return bg.getOpacity() == PixelFormat.OPAQUE;
+        }
+        return false;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mFirstLayout = true;
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mFirstLayout = true;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+        if (widthMode != MeasureSpec.EXACTLY) {
+            throw new IllegalStateException("Width must have an exact value or MATCH_PARENT");
+        } else if (heightMode != MeasureSpec.EXACTLY) {
+            throw new IllegalStateException("Height must have an exact value or MATCH_PARENT");
+        }
+
+        int layoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
+        int panelHeight = mPanelHeight;
+
+        final int childCount = getChildCount();
+
+        if (childCount > 2) {
+            Log.e(TAG, "onMeasure: More than two child views are not supported.");
+        } else if (getChildAt(1).getVisibility() == GONE) {
+            panelHeight = 0;
+        }
+
+        // We'll find the current one below.
+        mSlideableView = null;
+        mCanSlide = false;
+
+        // First pass. Measure based on child LayoutParams width/height.
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            int height = layoutHeight;
+            if (child.getVisibility() == GONE) {
+                lp.dimWhenOffset = false;
+                continue;
+            }
+
+            if (i == 1) {
+                lp.slideable = true;
+                lp.dimWhenOffset = true;
+                mSlideableView = child;
+                mCanSlide = true;
+            } else {
+                height -= panelHeight;
+            }
+
+            int childWidthSpec;
+            if (lp.width == LayoutParams.WRAP_CONTENT) {
+                childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
+            } else if (lp.width == LayoutParams.MATCH_PARENT) {
+                childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
+            } else {
+                childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
+            }
+
+            int childHeightSpec;
+            if (lp.height == LayoutParams.WRAP_CONTENT) {
+                childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+            } else if (lp.height == LayoutParams.MATCH_PARENT) {
+                childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+            } else {
+                childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
+            }
+
+            child.measure(childWidthSpec, childHeightSpec);
+        }
+
+        setMeasuredDimension(widthSize, heightSize);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int paddingLeft = getPaddingLeft();
+        final int paddingTop = getPaddingTop();
+
+        final int childCount = getChildCount();
+        int yStart = paddingTop;
+        int nextYStart = yStart;
+
+        if (mFirstLayout) {
+            mSlideOffset = mCanSlide && mPreservedExpandedState ? 0.f : 1.f;
+        }
+
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            int childHeight = child.getMeasuredHeight();
+
+            if (lp.slideable) {
+                mSlideRange = childHeight - mPanelHeight;
+                yStart += (int) (mSlideRange * mSlideOffset);
+            } else {
+                yStart = nextYStart;
+            }
+
+            final int childTop = yStart;
+            final int childBottom = childTop + childHeight;
+            final int childLeft = paddingLeft;
+            final int childRight = childLeft + child.getMeasuredWidth();
+            child.layout(childLeft, childTop, childRight, childBottom);
+
+            nextYStart += child.getHeight();
+        }
+
+        if (mFirstLayout) {
+            updateObscuredViewVisibility();
+        }
+
+        mFirstLayout = false;
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        // Recalculate sliding panes and their details
+        if (h != oldh) {
+            mFirstLayout = true;
+        }
+    }
+
+    /**
+     * Set sliding enabled flag
+     * 
+     * @param enabled
+     *            flag value
+     */
+    public void setSlidingEnabled(boolean enabled) {
+        mIsSlidingEnabled = enabled;
+    }
+
+    /**
+     * Set if the drag view can have its own touch events. If set to true, a drag view can scroll horizontally and have its own click listener.
+     * 
+     * Default is set to false.
+     */
+    public void setEnableDragViewTouchEvents(boolean enabled) {
+        mIsUsingDragViewTouchEvents = enabled;
+    }
+
+    private boolean isDragViewHit(int x, int y) {
+        View v = mDragView != null ? mDragView : mSlideableView;
+        if (v == null)
+            return false;
+        int[] viewLocation = new int[2];
+        v.getLocationOnScreen(viewLocation);
+        int[] parentLocation = new int[2];
+        this.getLocationOnScreen(parentLocation);
+        int screenX = parentLocation[0] + x;
+        int screenY = parentLocation[1] + y;
+        return screenX >= viewLocation[0] && screenX < viewLocation[0] + v.getWidth() && screenY >= viewLocation[1]
+                && screenY < viewLocation[1] + v.getHeight();
+    }
+
+    @Override
+    public void requestChildFocus(View child, View focused) {
+        super.requestChildFocus(child, focused);
+        if (!isInTouchMode() && !mCanSlide) {
+            mPreservedExpandedState = child == mSlideableView;
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        final int action = MotionEventCompat.getActionMasked(ev);
+
+        if (!mCanSlide || !mIsSlidingEnabled || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) {
+            mDragHelper.cancel();
+            return super.onInterceptTouchEvent(ev);
+        }
+
+        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+            mDragHelper.cancel();
+            return false;
+        }
+
+        final float x = ev.getX();
+        final float y = ev.getY();
+        boolean interceptTap = false;
+
+        switch (action) {
+        case MotionEvent.ACTION_DOWN: {
+            mIsUnableToDrag = false;
+            mInitialMotionX = x;
+            mInitialMotionY = y;
+            mDragViewHit = isDragViewHit((int) x, (int) y);
+
+            if (mDragViewHit && !mIsUsingDragViewTouchEvents) {
+                interceptTap = true;
+            }
+            break;
+        }
+
+        case MotionEvent.ACTION_MOVE: {
+            final float adx = Math.abs(x - mInitialMotionX);
+            final float ady = Math.abs(y - mInitialMotionY);
+            final int dragSlop = mDragHelper.getTouchSlop();
+
+            // Handle any horizontal scrolling on the drag view.
+            if (mIsUsingDragViewTouchEvents) {
+                if (adx > mScrollTouchSlop && ady < mScrollTouchSlop) {
+                    return super.onInterceptTouchEvent(ev);
+                }
+                // Intercept the touch if the drag view has any vertical scroll.
+                // onTouchEvent will determine if the view should drag vertically.
+                else if (ady > mScrollTouchSlop) {
+                    interceptTap = mDragViewHit;
+                }
+            }
+
+            if (ady > dragSlop && adx > ady) {
+                mDragHelper.cancel();
+                mIsUnableToDrag = true;
+                return false;
+            }
+            break;
+        }
+        }
+
+        final boolean interceptForDrag = mDragViewHit && mDragHelper.shouldInterceptTouchEvent(ev);
+
+        return interceptForDrag || interceptTap;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (!mCanSlide || !mIsSlidingEnabled) {
+            return super.onTouchEvent(ev);
+        }
+
+        mDragHelper.processTouchEvent(ev);
+
+        final int action = ev.getAction();
+        boolean wantTouchEvents = true;
+
+        switch (action & MotionEventCompat.ACTION_MASK) {
+        case MotionEvent.ACTION_DOWN: {
+            final float x = ev.getX();
+            final float y = ev.getY();
+            mInitialMotionX = x;
+            mInitialMotionY = y;
+            break;
+        }
+
+        case MotionEvent.ACTION_UP: {
+            final float x = ev.getX();
+            final float y = ev.getY();
+            final float dx = x - mInitialMotionX;
+            final float dy = y - mInitialMotionY;
+            final int slop = mDragHelper.getTouchSlop();
+            if (dx * dx + dy * dy < slop * slop && isDragViewHit((int) x, (int) y)) {
+                View v = mDragView != null ? mDragView : mSlideableView;
+                v.playSoundEffect(SoundEffectConstants.CLICK);
+                if (!isExpanded() && !isAnchored()) {
+                    expandPane(mSlideableView, 0, mAnchorPoint);
+                } else {
+                    collapsePane();
+                }
+                break;
+            }
+            break;
+        }
+        }
+
+        return wantTouchEvents;
+    }
+
+    private boolean expandPane(View pane, int initialVelocity, float mSlideOffset) {
+        if (mFirstLayout || smoothSlideTo(mSlideOffset, initialVelocity)) {
+            mPreservedExpandedState = true;
+            return true;
+        }
+        return false;
+    }
+
+    private boolean collapsePane(View pane, int initialVelocity) {
+        if (mFirstLayout || smoothSlideTo(1.f, initialVelocity)) {
+            mPreservedExpandedState = false;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Collapse the sliding pane if it is currently slideable. If first layout has already completed this will animate.
+     * 
+     * @return true if the pane was slideable and is now collapsed/in the process of collapsing
+     */
+    public boolean collapsePane() {
+        return collapsePane(mSlideableView, 0);
+    }
+
+    /**
+     * Expand the sliding pane if it is currently slideable. If first layout has already completed this will animate.
+     * 
+     * @return true if the pane was slideable and is now expanded/in the process of expading
+     */
+    public boolean expandPane() {
+        return expandPane(0);
+    }
+
+    /**
+     * Partially expand the sliding pane up to a specific offset
+     * 
+     * @param mSlideOffset
+     *            Value between 0 and 1, where 0 is completely expanded.
+     * @return true if the pane was slideable and is now expanded/in the process of expading
+     */
+    public boolean expandPane(float mSlideOffset) {
+        if (!isPaneVisible()) {
+            showPane();
+        }
+        return expandPane(mSlideableView, 0, mSlideOffset);
+    }
+
+    /**
+     * Check if the layout is completely expanded.
+     * 
+     * @return true if sliding panels are completely expanded
+     */
+    public boolean isExpanded() {
+        return mFirstLayout && mPreservedExpandedState || !mFirstLayout && mCanSlide && mSlideOffset == 0;
+    }
+
+    /**
+     * Check if the layout is anchored in an intermediate point.
+     * 
+     * @return true if sliding panels are anchored
+     */
+    public boolean isAnchored() {
+        int anchoredTop = (int) (mAnchorPoint * mSlideRange);
+        return !mFirstLayout && mCanSlide && mSlideOffset == (float) anchoredTop / (float) mSlideRange;
+    }
+
+    /**
+     * Check if the content in this layout cannot fully fit side by side and therefore the content pane can be slid back and forth.
+     * 
+     * @return true if content in this layout can be expanded
+     */
+    public boolean isSlideable() {
+        return mCanSlide;
+    }
+
+    public boolean isPaneVisible() {
+        if (getChildCount() < 2) {
+            return false;
+        }
+        View slidingPane = getChildAt(1);
+        return slidingPane.getVisibility() == View.VISIBLE;
+    }
+
+    public void showPane() {
+        if (getChildCount() < 2) {
+            return;
+        }
+        View slidingPane = getChildAt(1);
+        slidingPane.setVisibility(View.VISIBLE);
+        requestLayout();
+    }
+
+    public void hidePane() {
+        if (mSlideableView == null) {
+            return;
+        }
+        mSlideableView.setVisibility(View.GONE);
+        requestLayout();
+    }
+
+    private void onPanelDragged(int newTop) {
+        final int topBound = getPaddingTop();
+        mSlideOffset = (float) (newTop - topBound) / mSlideRange;
+        dispatchOnPanelSlide(mSlideableView);
+    }
+
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        boolean result;
+        final int save = canvas.save(Canvas.CLIP_SAVE_FLAG);
+
+        boolean drawScrim = false;
+
+        if (mCanSlide && !lp.slideable && mSlideableView != null) {
+            // Clip against the slider; no sense drawing what will immediately be covered.
+            canvas.getClipBounds(mTmpRect);
+            mTmpRect.bottom = (int) Math.min(mTmpRect.bottom, mSlideableView.getTop() + getResources().getDisplayMetrics().density * 68); // + 60 cause of the rounded shape handle
+            canvas.clipRect(mTmpRect);
+            if (mSlideOffset < 1) {
+                drawScrim = true;
+            }
+        }
+
+        result = super.drawChild(canvas, child, drawingTime);
+        canvas.restoreToCount(save);
+
+        if (drawScrim) {
+            final int baseAlpha = (mCoveredFadeColor & 0xff000000) >>> 24;
+            final int imag = (int) (baseAlpha * (1 - mSlideOffset));
+            final int color = imag << 24 | (mCoveredFadeColor & 0xffffff);
+            mCoveredFadePaint.setColor(color);
+            canvas.drawRect(mTmpRect, mCoveredFadePaint);
+        }
+
+        return result;
+    }
+
+    /**
+     * Smoothly animate mDraggingPane to the target X position within its range.
+     * 
+     * @param slideOffset
+     *            position to animate to
+     * @param velocity
+     *            initial velocity in case of fling, or 0.
+     */
+    boolean smoothSlideTo(float slideOffset, int velocity) {
+        if (!mCanSlide) {
+            // Nothing to do.
+            return false;
+        }
+
+        final int topBound = getPaddingTop();
+        int y = (int) (topBound + slideOffset * mSlideRange);
+
+        if (mDragHelper.smoothSlideViewTo(mSlideableView, mSlideableView.getLeft(), y)) {
+            setAllChildrenVisible();
+            ViewCompat.postInvalidateOnAnimation(this);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void computeScroll() {
+        if (mDragHelper.continueSettling(true)) {
+            if (!mCanSlide) {
+                mDragHelper.abort();
+                return;
+            }
+
+            ViewCompat.postInvalidateOnAnimation(this);
+        }
+    }
+
+    @Override
+    public void draw(Canvas c) {
+        super.draw(c);
+
+        if (mSlideableView == null) {
+            // No need to draw a shadow if we don't have one.
+            return;
+        }
+
+        final int right = mSlideableView.getRight();
+        final int top = mSlideableView.getTop() - mShadowHeight;
+        final int bottom = mSlideableView.getTop();
+        final int left = mSlideableView.getLeft();
+
+        if (mShadowDrawable != null) {
+            mShadowDrawable.setBounds(left, top, right, bottom);
+            mShadowDrawable.draw(c);
+        }
+    }
+
+    /**
+     * Tests scrollability within child views of v given a delta of dx.
+     * 
+     * @param v
+     *            View to test for horizontal scrollability
+     * @param checkV
+     *            Whether the view v passed should itself be checked for scrollability (true), or just its children (false).
+     * @param dx
+     *            Delta scrolled in pixels
+     * @param x
+     *            X coordinate of the active touch point
+     * @param y
+     *            Y coordinate of the active touch point
+     * @return true if child views of v can be scrolled by delta of dx.
+     */
+    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
+        if (v instanceof ViewGroup) {
+            final ViewGroup group = (ViewGroup) v;
+            final int scrollX = v.getScrollX();
+            final int scrollY = v.getScrollY();
+            final int count = group.getChildCount();
+            // Count backwards - let topmost views consume scroll distance first.
+            for (int i = count - 1; i >= 0; i--) {
+                final View child = group.getChildAt(i);
+                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && y + scrollY >= child.getTop()
+                        && y + scrollY < child.getBottom() && canScroll(child, true, dx, x + scrollX - child.getLeft(), y + scrollY - child.getTop())) {
+                    return true;
+                }
+            }
+        }
+        return checkV && ViewCompat.canScrollHorizontally(v, -dx);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams();
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) : new LayoutParams(p);
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams && super.checkLayoutParams(p);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+
+        SavedState ss = new SavedState(superState);
+        ss.isExpanded = isSlideable() ? isExpanded() : mPreservedExpandedState;
+
+        return ss;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+
+        if (ss.isExpanded) {
+            expandPane();
+        } else {
+            collapsePane();
+        }
+        mPreservedExpandedState = ss.isExpanded;
+    }
+
+    private class DragHelperCallback extends ViewDragHelper.Callback {
+
+        @Override
+        public boolean tryCaptureView(View child, int pointerId) {
+            if (mIsUnableToDrag) {
+                return false;
+            }
+
+            return ((LayoutParams) child.getLayoutParams()).slideable;
+        }
+
+        @Override
+        public void onViewDragStateChanged(int state) {
+            if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) {
+                if (mSlideOffset == 0) {
+                    updateObscuredViewVisibility();
+                    dispatchOnPanelExpanded(mSlideableView);
+                    mPreservedExpandedState = true;
+                } else if (isAnchored()) {
+                    updateObscuredViewVisibility();
+                    dispatchOnPanelAnchored(mSlideableView);
+                    mPreservedExpandedState = true;
+                } else {
+                    dispatchOnPanelCollapsed(mSlideableView);
+                    mPreservedExpandedState = false;
+                }
+            }
+        }
+
+        @Override
+        public void onViewCaptured(View capturedChild, int activePointerId) {
+            // Make all child views visible in preparation for sliding things around
+            setAllChildrenVisible();
+        }
+
+        @Override
+        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
+            onPanelDragged(top);
+            invalidate();
+        }
+
+        @Override
+        public void onViewReleased(View releasedChild, float xvel, float yvel) {
+            int top = getPaddingTop();
+
+            if (mAnchorPoint != 0) {
+                int anchoredTop = (int) (mAnchorPoint * mSlideRange);
+                float anchorOffset = (float) anchoredTop / (float) mSlideRange;
+
+                if (yvel > 0 || (yvel == 0 && mSlideOffset >= (1f + anchorOffset) / 2)) {
+                    top += mSlideRange;
+                } else if (yvel == 0 && mSlideOffset < (1f + anchorOffset) / 2 && mSlideOffset >= anchorOffset / 2) {
+                    top += mSlideRange * mAnchorPoint;
+                }
+
+            } else if (yvel > 0 || (yvel == 0 && mSlideOffset > 0.5f)) {
+                top += mSlideRange;
+            }
+
+            mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top);
+            invalidate();
+        }
+
+        @Override
+        public int getViewVerticalDragRange(View child) {
+            return mSlideRange;
+        }
+
+        @Override
+        public int clampViewPositionVertical(View child, int top, int dy) {
+            final int topBound = getPaddingTop();
+            final int bottomBound = topBound + mSlideRange;
+
+            final int newLeft = Math.min(Math.max(top, topBound), bottomBound);
+
+            return newLeft;
+        }
+
+    }
+
+    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
+        private static final int[] ATTRS = new int[] { android.R.attr.layout_weight };
+
+        /**
+         * True if this pane is the slideable pane in the layout.
+         */
+        boolean slideable;
+
+        /**
+         * True if this view should be drawn dimmed when it's been offset from its default position.
+         */
+        boolean dimWhenOffset;
+
+        Paint dimPaint;
+
+        public LayoutParams() {
+            super(MATCH_PARENT, MATCH_PARENT);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+
+            final TypedArray a = c.obtainStyledAttributes(attrs, ATTRS);
+            a.recycle();
+        }
+
+    }
+
+    static class SavedState extends BaseSavedState {
+        boolean isExpanded;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        private SavedState(Parcel in) {
+            super(in);
+            isExpanded = in.readInt() != 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(isExpanded ? 1 : 0);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+}