ItemTouchHelper demo activities

NOTICE: TBR

Change-Id: I8d4c0bd2662fc0deb6465de753c1107938fbe6ee
diff --git a/samples/Support7Demos/Android.mk b/samples/Support7Demos/Android.mk
index 9e7164d..371c737 100644
--- a/samples/Support7Demos/Android.mk
+++ b/samples/Support7Demos/Android.mk
@@ -35,13 +35,16 @@
         frameworks/support/v7/appcompat/res \
         frameworks/support/v7/gridlayout/res \
         frameworks/support/v7/mediarouter/res \
-        frameworks/support/v7/recyclerview/res \
-        frameworks/support/v7/cardview/res
+        frameworks/support/v7/cardview/res \
+        frameworks/support/design/res \
+        frameworks/support/v7/recyclerview/res
+
 LOCAL_AAPT_FLAGS := \
         --auto-add-overlay \
         --extra-packages android.support.v7.appcompat \
         --extra-packages android.support.v7.cardview \
         --extra-packages android.support.v7.gridlayout \
-        --extra-packages android.support.v7.recyclerview \
-        --extra-packages android.support.v7.mediarouter
+        --extra-packages android.support.v7.mediarouter \
+        --extra-packages android.support.design \
+        --extra-packages android.support.v7.recyclerview
 include $(BUILD_PACKAGE)
diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml
index 7860462..3f3ec1e 100644
--- a/samples/Support7Demos/AndroidManifest.xml
+++ b/samples/Support7Demos/AndroidManifest.xml
@@ -406,5 +406,22 @@
                   android:label="@string/palette"
                   android:theme="@style/Theme.AppCompat" />
 
+        <!-- item touch helper demo activities-->
+        <activity android:name=".widget.touch.SwipeToDismissActivity"
+                  android:label="@string/swipe_to_dismiss_activity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+            </intent-filter>
+        </activity>
+        <activity android:name=".widget.touch.DragAndDropActivity"
+                  android:label="@string/drag_and_drop_activity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+            </intent-filter>
+        </activity>
     </application>
+
+
 </manifest>
diff --git a/samples/Support7Demos/res/layout/activity_item_touch.xml b/samples/Support7Demos/res/layout/activity_item_touch.xml
new file mode 100644
index 0000000..d809b0e
--- /dev/null
+++ b/samples/Support7Demos/res/layout/activity_item_touch.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <android.support.v7.widget.RecyclerView
+            android:layout_width="fill_parent"
+            android:layout_height="60dp"
+            android:scrollbars="horizontal"
+            android:id="@+id/config_recycler_view"/>
+    <android.support.v7.widget.RecyclerView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:id="@+id/recycler_view"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/layout/config_view_toggle.xml b/samples/Support7Demos/res/layout/config_view_toggle.xml
new file mode 100644
index 0000000..ac187ff
--- /dev/null
+++ b/samples/Support7Demos/res/layout/config_view_toggle.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="wrap_content"
+              android:layout_height="match_parent">
+
+</CheckBox>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/layout/touch_item.xml b/samples/Support7Demos/res/layout/touch_item.xml
new file mode 100644
index 0000000..7ff9547
--- /dev/null
+++ b/samples/Support7Demos/res/layout/touch_item.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+                                    xmlns:card="http://schemas.android.com/apk/res-auto"
+                                    android:layout_width="match_parent"
+                                    card:cardUseCompatPadding="true"
+                                    android:background="@color/card_classic"
+                                    android:layout_height="wrap_content">
+    <TextView android:layout_width="wrap_content"
+              android:textColor="@android:color/black"
+              android:layout_height="@dimen/touch_item_min_height"
+              android:id="@+id/text_view"/>
+    <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:layout_gravity="end|center_vertical"
+            android:id="@+id/action_button" android:visibility="gone"/>
+    <FrameLayout
+            android:id="@+id/overlay"
+            android:visibility="gone"
+            android:background="@color/card_tropical"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/touch_item_min_height">
+        <TextView android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="center"
+                  android:text="@string/swiping"/>
+    </FrameLayout>
+</android.support.v7.widget.CardView>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/values/dimens.xml b/samples/Support7Demos/res/values/dimens.xml
index f952d18..f2520b9 100644
--- a/samples/Support7Demos/res/values/dimens.xml
+++ b/samples/Support7Demos/res/values/dimens.xml
@@ -17,5 +17,6 @@
 <resources>
 
     <dimen name="color_palette_size">60dp</dimen>
+    <dimen name="touch_item_min_height">60dp</dimen>
 
 </resources>
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index b1f6ffa..2353c18 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -186,4 +186,16 @@
     <string name="tint_overflow_clear">Clear overflow button tint</string>
     <string name="dummy">Dummy item</string>
 
+    <string name="swipe_to_dismiss_activity">RecyclerView/ItemTouchHelper/Swipe To Dismiss</string>
+    <string name="drag_and_drop_activity">RecyclerView/ItemTouchHelper/Drag and Drop Activity</string>
+    <string name="swipe_start">start</string>
+    <string name="swipe_end">end</string>
+    <string name="pointer_swipe_enabled">pointer swipe</string>
+    <string name="custom_swipe_enabled">custom swipe</string>
+    <string name="drag_up">up</string>
+    <string name="drag_down">down</string>
+    <string name="long_press_drag">long press drag</string>
+    <string name="drag">drag me</string>
+    <string name="swipe">swipe me</string>
+    <string name="swiping">swiping</string>
 </resources>
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
index 4bb64f4..782da52 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
@@ -19,12 +19,15 @@
 import com.example.android.supportv7.Cheeses;
 import com.example.android.supportv7.R;
 import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+import com.example.android.supportv7.widget.util.ConfigViewHolder;
 
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
@@ -167,56 +170,11 @@
 
     abstract ConfigToggle[] createConfigToggles();
 
-    private class ConfigViewHolder extends RecyclerView.ViewHolder
-            implements CompoundButton.OnCheckedChangeListener {
-
-        private CheckBox mCheckBox;
-
-        private ConfigToggle mConfigToggle;
-
-        public ConfigViewHolder(View itemView) {
-            super(itemView);
-            mCheckBox = (CheckBox) itemView;
-            mCheckBox.setOnCheckedChangeListener(this);
-        }
-
-        public void bind(ConfigToggle toggle) {
-            mConfigToggle = toggle;
-            mCheckBox.setText(toggle.getText());
-            mCheckBox.setChecked(toggle.isChecked());
-        }
-
-        @Override
-        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-            if (mConfigToggle != null) {
-                mConfigToggle.onChange(isChecked);
-            }
-        }
-    }
-
-
-    public abstract static class ConfigToggle {
-
-        private String mLabel;
-
-        protected ConfigToggle(Context context, int labelId) {
-            mLabel = context.getResources().getString(labelId);
-        }
-
-        public String getText() {
-            return mLabel;
-        }
-
-        abstract public boolean isChecked();
-
-        abstract public void onChange(boolean newValue);
-    }
-
-
     private RecyclerView.Adapter mConfigAdapter = new RecyclerView.Adapter<ConfigViewHolder>() {
         @Override
         public ConfigViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return new ConfigViewHolder(new CheckBox(parent.getContext()));
+            return new ConfigViewHolder(LayoutInflater.from(parent.getContext())
+                    .inflate(R.layout.config_view_toggle, parent, false));
         }
 
         @Override
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
index ef25c0b..3ce5c60 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
@@ -18,6 +18,7 @@
 import com.example.android.supportv7.Cheeses;
 import com.example.android.supportv7.R;
 import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
+import com.example.android.supportv7.widget.util.ConfigToggle;
 
 import android.support.v4.view.ViewCompat;
 import android.support.v7.widget.GridLayoutManager;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java
index 9aaa558..7482e3e 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/LinearLayoutManagerActivity.java
@@ -22,6 +22,7 @@
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.util.ConfigToggle;
 
 /**
  * A sample activity that uses {@link LinearLayoutManager}.
@@ -41,7 +42,7 @@
     }
 
     @Override
-    BaseLayoutManagerActivity.ConfigToggle[] createConfigToggles() {
+    ConfigToggle[] createConfigToggles() {
         return new ConfigToggle[]{
                 new ConfigToggle(this, R.string.checkbox_orientation) {
                     @Override
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/DragAndDropActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/DragAndDropActivity.java
new file mode 100644
index 0000000..7f9f7e5
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/DragAndDropActivity.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv7.widget.touch;
+
+import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class DragAndDropActivity extends ItemTouchHelperActivity {
+
+    boolean mDragUpEnabled = true;
+    boolean mDragDownEnabled = true;
+    boolean mLongPressDragEnabled = true;
+
+    @Override
+    ConfigToggle[] createConfigToggles() {
+        return new ConfigToggle[]{
+                new ConfigToggle(this, R.string.drag_up) {
+                    @Override
+                    public boolean isChecked() {
+                        return mDragUpEnabled;
+                    }
+
+                    @Override
+                    public void onChange(boolean newValue) {
+                        mDragUpEnabled = newValue;
+                    }
+                },
+                new ConfigToggle(this, R.string.drag_down) {
+                    @Override
+                    public boolean isChecked() {
+                        return mDragDownEnabled;
+                    }
+
+                    @Override
+                    public void onChange(boolean newValue) {
+                        mDragDownEnabled = newValue;
+                    }
+                },
+                new ConfigToggle(this, R.string.long_press_drag) {
+                    @Override
+                    public boolean isChecked() {
+                        return mLongPressDragEnabled;
+                    }
+
+                    @Override
+                    public void onChange(boolean newValue) {
+                        mLongPressDragEnabled = newValue;
+                        mAdapter.notifyDataSetChanged();
+                    }
+                }
+        };
+    }
+
+    @Override
+    public boolean isLongPressDragEnabled() {
+        return mLongPressDragEnabled;
+    }
+
+    @Override
+    public void onBind(ItemTouchViewHolder viewHolder) {
+        super.onBind(viewHolder);
+        viewHolder.actionButton.setVisibility(mLongPressDragEnabled ? View.GONE : View.VISIBLE);
+    }
+
+    @Override
+    public void clearView(RecyclerView.ViewHolder viewHolder) {
+        super.clearView(viewHolder);
+        ItemTouchViewHolder touchVH = (ItemTouchViewHolder) viewHolder;
+        touchVH.cardView.setCardBackgroundColor(getResources().getColor(android.R.color.white));
+        touchVH.overlay.setVisibility(View.GONE);
+    }
+
+    @Override
+    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+        ItemTouchViewHolder touchVH = (ItemTouchViewHolder) viewHolder;
+        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
+            touchVH.cardView.setCardBackgroundColor(getResources().getColor(R.color.card_aquatic));
+        }
+        super.onSelectedChanged(viewHolder, actionState);
+    }
+
+    @Override
+    public ItemTouchViewHolder onCreateViewHolder(ViewGroup parent) {
+        final ItemTouchViewHolder vh = super.onCreateViewHolder(parent);
+        vh.actionButton.setText(R.string.drag);
+        vh.actionButton.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+                    mItemTouchHelper.startDrag(vh);
+                }
+                return false;
+            }
+        });
+        return vh;
+    }
+
+    @Override
+    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+        return mCallback.makeMovementFlags(
+                (mDragUpEnabled ? ItemTouchHelper.UP : 0) |
+                        (mDragDownEnabled ? ItemTouchHelper.DOWN : 0), 0);
+    }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/ItemTouchHelperActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/ItemTouchHelperActivity.java
new file mode 100644
index 0000000..54a0bb3
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/ItemTouchHelperActivity.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv7.widget.touch;
+
+import com.example.android.supportv7.Cheeses;
+import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+import com.example.android.supportv7.widget.util.ConfigViewHolder;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.os.Bundle;
+import android.support.v7.widget.CardView;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Sample activity from which ItemTouchHelper demo activities inherit.
+ */
+abstract public class ItemTouchHelperActivity extends Activity {
+
+    public RecyclerView mRecyclerView;
+
+    public ItemTouchAdapter mAdapter;
+
+    public ItemTouchHelper mItemTouchHelper;
+
+    public ItemTouchHelper.Callback mCallback;
+
+    private ConfigToggle[] mConfigToggles;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_item_touch);
+        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
+        mRecyclerView.setHasFixedSize(true);
+        mAdapter = createAdapter();
+        mRecyclerView.setAdapter(mAdapter);
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
+        mItemTouchHelper = createItemTouchHelper();
+        mItemTouchHelper.attachToRecyclerView(mRecyclerView);
+        initToggles();
+    }
+
+    private void initToggles() {
+        mConfigToggles = createConfigToggles();
+        RecyclerView configView = (RecyclerView) findViewById(R.id.config_recycler_view);
+        configView.setAdapter(new RecyclerView.Adapter<ConfigViewHolder>() {
+            @Override
+            public ConfigViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+                return new ConfigViewHolder(LayoutInflater.from(parent.getContext())
+                        .inflate(R.layout.config_view_toggle, parent, false));
+            }
+
+            @Override
+            public void onBindViewHolder(ConfigViewHolder holder, int position) {
+                ConfigToggle toggle = mConfigToggles[position];
+                holder.bind(toggle);
+            }
+
+            @Override
+            public int getItemCount() {
+                return mConfigToggles.length;
+            }
+        });
+        configView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,
+                false));
+        configView.setHasFixedSize(true);
+    }
+
+    abstract ConfigToggle[] createConfigToggles();
+
+    public ItemTouchHelper createItemTouchHelper() {
+        mCallback = createCallback();
+        return new ItemTouchHelper(mCallback);
+    }
+
+    public ItemTouchHelper.Callback createCallback() {
+        return new ItemTouchHelper.Callback() {
+            @Override
+            public int getMovementFlags(RecyclerView recyclerView,
+                    RecyclerView.ViewHolder viewHolder) {
+                return ItemTouchHelperActivity.this.getMovementFlags(recyclerView, viewHolder);
+            }
+
+            @Override
+            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
+                    RecyclerView.ViewHolder target) {
+                mAdapter.move(viewHolder.getAdapterPosition(), target.getAdapterPosition());
+                return true;
+            }
+
+            @Override
+            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+                mAdapter.delete(viewHolder.getAdapterPosition());
+            }
+
+            @Override
+            public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+                super.onSelectedChanged(viewHolder, actionState);
+                ItemTouchHelperActivity.this.onSelectedChanged(viewHolder, actionState);
+            }
+
+            @Override
+            public void onChildDraw(Canvas c, RecyclerView recyclerView,
+                    RecyclerView.ViewHolder viewHolder,
+                    float dX, float dY, int actionState, boolean isCurrentlyActive) {
+                if (ItemTouchHelperActivity.this.onChildDraw(c, recyclerView, viewHolder,
+                        dX, dY, actionState, isCurrentlyActive)) {
+                    return;
+                }
+                super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState,
+                        isCurrentlyActive);
+            }
+
+            @Override
+            public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
+                    RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
+                    boolean isCurrentlyActive) {
+                if (ItemTouchHelperActivity.this.onChildDrawOver(c, recyclerView, viewHolder,
+                        dX, dY, actionState, isCurrentlyActive)) {
+                    return;
+                }
+                super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState,
+                        isCurrentlyActive);
+            }
+
+            @Override
+            public boolean isLongPressDragEnabled() {
+                return ItemTouchHelperActivity.this.isLongPressDragEnabled();
+            }
+
+            @Override
+            public boolean isItemViewSwipeEnabled() {
+                return ItemTouchHelperActivity.this.isPointerSwipeEnabled();
+            }
+
+            @Override
+            public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+                super.clearView(recyclerView, viewHolder);
+                ItemTouchHelperActivity.this.clearView(viewHolder);
+            }
+        };
+    }
+
+    /**
+     * @return True if we should NOT call parent
+     */
+    public boolean onChildDraw(Canvas c, RecyclerView recyclerView,
+            RecyclerView.ViewHolder viewHolder,
+            float dX, float dY, int actionState, boolean isCurrentlyActive) {
+        return false;
+    }
+
+    /**
+     * @return True if we should NOT call parent
+     */
+    public boolean onChildDrawOver(Canvas c, RecyclerView recyclerView,
+            RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
+            boolean isCurrentlyActive) {
+        return false;
+    }
+
+    public void clearView(RecyclerView.ViewHolder viewHolder) {
+
+    }
+
+    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+
+    }
+
+    public boolean isLongPressDragEnabled() {
+        return true;
+    }
+
+    public boolean isPointerSwipeEnabled() {
+        return true;
+    }
+
+    public ItemTouchViewHolder onCreateViewHolder(ViewGroup parent) {
+        ItemTouchViewHolder itemTouchViewHolder = new ItemTouchViewHolder(
+                LayoutInflater.from(parent.getContext())
+                        .inflate(R.layout.touch_item, parent, false));
+        return itemTouchViewHolder;
+    }
+
+    abstract public int getMovementFlags(RecyclerView recyclerView,
+            RecyclerView.ViewHolder viewHolder);
+
+    public ItemTouchAdapter createAdapter() {
+        return new ItemTouchAdapter();
+    }
+
+    public void onBind(ItemTouchViewHolder viewHolder) {
+
+    }
+
+    public void onCreateViewHolder(ItemTouchViewHolder viewHolder) {
+
+    }
+
+    public class ItemTouchViewHolder extends RecyclerView.ViewHolder {
+
+        public final TextView textView;
+
+        public final Button actionButton;
+
+        public final CardView cardView;
+
+        public final View overlay;
+
+        public ItemTouchViewHolder(View itemView) {
+            super(itemView);
+            cardView = (CardView) itemView;
+            textView = (TextView) itemView.findViewById(R.id.text_view);
+            actionButton = (Button) itemView.findViewById(R.id.action_button);
+            overlay = itemView.findViewById(R.id.overlay);
+        }
+    }
+
+    public class ItemTouchAdapter extends RecyclerView.Adapter<ItemTouchViewHolder> {
+
+        private List<String> mItems = new ArrayList<String>();
+
+        public ItemTouchAdapter() {
+            mItems.addAll(Arrays.asList(Cheeses.sCheeseStrings));
+        }
+
+        @Override
+        public ItemTouchViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            return ItemTouchHelperActivity.this.onCreateViewHolder(parent);
+        }
+
+        @Override
+        public void onBindViewHolder(ItemTouchViewHolder holder, int position) {
+            holder.textView.setText(mItems.get(position));
+            onBind(holder);
+        }
+
+        public void delete(int position) {
+            mItems.remove(position);
+            notifyItemRemoved(position);
+        }
+
+        public void move(int from, int to) {
+            String prev = mItems.remove(from);
+            mItems.add(to > from ? to - 1 : to, prev);
+            notifyItemMoved(from, to);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mItems.size();
+        }
+    }
+
+
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/SwipeToDismissActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/SwipeToDismissActivity.java
new file mode 100644
index 0000000..bb7e27e
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/touch/SwipeToDismissActivity.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv7.widget.touch;
+
+import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+
+import android.annotation.TargetApi;
+import android.graphics.Canvas;
+import android.os.Build;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class SwipeToDismissActivity extends ItemTouchHelperActivity {
+    boolean mSwipeStartEnabled = true;
+    boolean mSwipeEndEnabled = true;
+    boolean mPointerSwipeEnabled = true;
+    boolean mCustomSwipeEnabled = false;
+
+    @Override
+    ConfigToggle[] createConfigToggles() {
+        ConfigToggle[] configToggles = {
+                new ConfigToggle(this, R.string.swipe_start) {
+                    @Override
+                    public boolean isChecked() {
+                        return mSwipeStartEnabled;
+                    }
+
+                    @Override
+                    public void onChange(boolean newValue) {
+                        mSwipeStartEnabled = newValue;
+                    }
+                },
+                new ConfigToggle(this, R.string.swipe_end) {
+                    @Override
+                    public boolean isChecked() {
+                        return mSwipeEndEnabled;
+                    }
+
+                    @Override
+                    public void onChange(boolean newValue) {
+                        mSwipeEndEnabled = newValue;
+                    }
+                },
+                new ConfigToggle(this, R.string.pointer_swipe_enabled) {
+                    @Override
+                    public boolean isChecked() {
+                        return mPointerSwipeEnabled;
+                    }
+
+                    @Override
+                    public void onChange(boolean newValue) {
+                        mPointerSwipeEnabled = newValue;
+                        mAdapter.notifyDataSetChanged();
+                    }
+                }
+        };
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            ConfigToggle[] copy = new ConfigToggle[configToggles.length + 1];
+            System.arraycopy(configToggles, 0, copy, 0, configToggles.length);
+            copy[copy.length - 1] = new ConfigToggle(this, R.string.custom_swipe_enabled) {
+                @Override
+                public boolean isChecked() {
+                    return mCustomSwipeEnabled;
+                }
+
+                @Override
+                public void onChange(boolean newValue) {
+                    mCustomSwipeEnabled = newValue;
+                }
+            };
+            return copy;
+        } else {
+            return configToggles;
+        }
+    }
+
+    @Override
+    public void onBind(ItemTouchViewHolder viewHolder) {
+        super.onBind(viewHolder);
+        viewHolder.actionButton.setVisibility(mPointerSwipeEnabled ? View.GONE : View.VISIBLE);
+    }
+
+    @Override
+    public void clearView(RecyclerView.ViewHolder viewHolder) {
+        super.clearView(viewHolder);
+        ItemTouchViewHolder touchVH = (ItemTouchViewHolder) viewHolder;
+        touchVH.cardView.setCardBackgroundColor(getResources().getColor(android.R.color.white));
+        touchVH.overlay.setVisibility(View.GONE);
+    }
+
+    @Override
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+        ItemTouchViewHolder touchVH = (ItemTouchViewHolder) viewHolder;
+        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
+            touchVH.cardView.setCardBackgroundColor(getResources().getColor(R.color.card_aquatic));
+            if (mCustomSwipeEnabled) {
+                // hide it
+                touchVH.overlay.setTranslationX(viewHolder.itemView.getWidth());
+                touchVH.overlay.setVisibility(View.VISIBLE);
+            }
+        }
+        super.onSelectedChanged(viewHolder, actionState);
+    }
+
+    @Override
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    public boolean onChildDraw(Canvas c, RecyclerView recyclerView,
+            RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
+            boolean isCurrentlyActive) {
+        if (!mCustomSwipeEnabled) {
+            return false;
+        }
+        ItemTouchViewHolder touchVH = (ItemTouchViewHolder) viewHolder;
+        final float dir = Math.signum(dX);
+        if (dir == 0) {
+            touchVH.overlay.setTranslationX(-touchVH.overlay.getWidth());
+        } else {
+            final float overlayOffset = dX - dir * viewHolder.itemView.getWidth();
+            touchVH.overlay.setTranslationX(overlayOffset);
+        }
+        float alpha = (float) (.2 + .8 * Math.abs(dX) / viewHolder.itemView.getWidth());
+        touchVH.overlay.setAlpha(alpha);
+        return true;
+    }
+
+    @Override
+    public ItemTouchViewHolder onCreateViewHolder(ViewGroup parent) {
+        final ItemTouchViewHolder vh = super.onCreateViewHolder(parent);
+        vh.actionButton.setText(R.string.swipe);
+        vh.actionButton.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+                    mItemTouchHelper.startSwipe(vh);
+                }
+                return false;
+            }
+        });
+        return vh;
+    }
+
+    @Override
+    public boolean isPointerSwipeEnabled() {
+        return mPointerSwipeEnabled;
+    }
+
+    @Override
+    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+        return mCallback.makeMovementFlags(0,
+                (mSwipeStartEnabled ? ItemTouchHelper.START : 0) |
+                        (mSwipeEndEnabled ? ItemTouchHelper.END : 0));
+    }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/util/ConfigToggle.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/util/ConfigToggle.java
new file mode 100644
index 0000000..eae04b0
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/util/ConfigToggle.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv7.widget.util;
+
+import android.content.Context;
+
+abstract public class ConfigToggle {
+    private String mLabel;
+
+    protected ConfigToggle(Context context, int labelId) {
+        mLabel = context.getResources().getString(labelId);
+    }
+
+    public String getText() {
+        return mLabel;
+    }
+
+    abstract public boolean isChecked();
+
+    abstract public void onChange(boolean newValue);
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/util/ConfigViewHolder.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/util/ConfigViewHolder.java
new file mode 100644
index 0000000..1bdf155
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/util/ConfigViewHolder.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv7.widget.util;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+
+public class ConfigViewHolder extends RecyclerView.ViewHolder
+        implements CompoundButton.OnCheckedChangeListener {
+
+    private CheckBox mCheckBox;
+
+    private ConfigToggle mConfigToggle;
+
+    public ConfigViewHolder(View itemView) {
+        super(itemView);
+        mCheckBox = (CheckBox) itemView;
+        mCheckBox.setOnCheckedChangeListener(this);
+    }
+
+    public void bind(ConfigToggle toggle) {
+        mConfigToggle = toggle;
+        mCheckBox.setText(toggle.getText());
+        mCheckBox.setChecked(toggle.isChecked());
+    }
+
+    @Override
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (mConfigToggle != null) {
+            mConfigToggle.onChange(isChecked);
+        }
+    }
+}