Initial bookmark drag & drop

 Currently can only re-parent (drop into folders, between accounts)
 Has no visual feedback yet either

Change-Id: If02c32a98a836c4567f274f1cb1654a25f469b0f
diff --git a/src/com/android/browser/BookmarkDragHandler.java b/src/com/android/browser/BookmarkDragHandler.java
new file mode 100644
index 0000000..0707058
--- /dev/null
+++ b/src/com/android/browser/BookmarkDragHandler.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 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.android.browser;
+
+import android.content.ClipData;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.BrowserContract;
+import android.provider.BrowserContract.Bookmarks;
+import android.view.DragEvent;
+import android.view.View;
+import android.view.View.OnDragListener;
+
+public class BookmarkDragHandler {
+
+    public static interface BookmarkDragController {
+        boolean startDrag(Cursor item);
+    }
+
+    public static interface BookmarkDragAdapter {
+        void setBookmarkDragHandler(BookmarkDragHandler handler);
+        Cursor getItemForView(View v);
+    }
+
+    static class BookmarkDragState {
+        long id;
+        long parent;
+    }
+
+    static final String BOOKMARK_DRAG_LABEL = "com.android.browser.BOOKMARK_LABEL";
+
+    private Context mContext;
+    private BookmarkDragController mDragController;
+    private BookmarkDragAdapter mDragAdapter;
+
+    public BookmarkDragHandler(Context context, BookmarkDragController controller,
+            BookmarkDragAdapter adapter) {
+        mContext = context;
+        mDragController = controller;
+        mDragAdapter = adapter;
+        mDragAdapter.setBookmarkDragHandler(this);
+    }
+
+    public boolean startDrag(View view, Cursor item, long id) {
+        if (!mDragController.startDrag(item)) {
+            return false;
+        }
+        Uri uri = ContentUris.withAppendedId(
+                BrowserContract.Bookmarks.CONTENT_URI, id);
+        ClipData data = ClipData.newRawUri(BOOKMARK_DRAG_LABEL, uri);
+        BookmarkDragState state = new BookmarkDragState();
+        state.id = id;
+        state.parent = item.getLong(BookmarksLoader.COLUMN_INDEX_PARENT);
+        view.startDrag(data, new View.DragShadowBuilder(view), state, 0);
+        return true;
+    }
+
+    public void registerBookmarkDragHandler(View view) {
+        view.setOnDragListener(mBookmarkDragListener);
+    }
+
+    private OnDragListener mBookmarkDragListener = new OnDragListener() {
+
+        @Override
+        public boolean onDrag(View v, DragEvent event) {
+            Cursor c = mDragAdapter.getItemForView(v);
+            BookmarkDragState state = (BookmarkDragState) event.getLocalState();
+            switch (event.getAction()) {
+            case DragEvent.ACTION_DRAG_STARTED:
+                return true;
+            case DragEvent.ACTION_DROP:
+                long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
+                if (id == state.id) {
+                    // We dropped onto ourselves, show the context menu
+                    v.showContextMenu();
+                    return false;
+                }
+                long parent = c.getLong(BookmarksLoader.COLUMN_INDEX_PARENT);
+                if (isFolder(c)) {
+                    parent = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
+                }
+                if (parent != state.parent) {
+                    ContentResolver cr = mContext.getContentResolver();
+                    ContentValues values = new ContentValues();
+                    values.put(Bookmarks.PARENT, parent);
+                    Uri uri = event.getClipData().getItemAt(0).getUri();
+                    cr.update(uri, values, null, null);
+                }
+                break;
+            }
+            return false;
+        }
+    };
+
+    static boolean isFolder(Cursor c) {
+        return c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
+    }
+}
diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java
index 962d21c..448f881 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -16,6 +16,7 @@
 
 package com.android.browser;
 
+import com.android.browser.BookmarkDragHandler.BookmarkDragController;
 import com.android.browser.view.BookmarkExpandableGridView;
 import com.android.browser.view.BookmarkExpandableGridView.BookmarkContextMenuInfo;
 
@@ -101,6 +102,7 @@
     int mCurrentView;
     View mHeader;
     HashMap<Integer, BrowserBookmarksAdapter> mBookmarkAdapters = new HashMap<Integer, BrowserBookmarksAdapter>();
+    BookmarkDragHandler mDragHandler;
 
     static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb,
             Bundle args, ViewGroup headerContainer) {
@@ -351,6 +353,8 @@
         mList = (ListView) mRoot.findViewById(R.id.list);
         // TODO: mList.setOnItemClickListener(this);
         setEnableContextMenu(mEnableContextMenu);
+        mDragHandler = new BookmarkDragHandler(getActivity(), mDragController,
+                mGrid.getDragAdapter());
 
         // Start the loaders
         LoaderManager lm = getLoaderManager();
@@ -677,6 +681,14 @@
         }
     }
 
+    private BookmarkDragController mDragController = new BookmarkDragController() {
+
+        @Override
+        public boolean startDrag(Cursor item) {
+            return canEdit(item);
+        }
+    };
+
     private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
         Context mContext;
         BookmarkItem mHeader;
diff --git a/src/com/android/browser/view/BookmarkExpandableGridView.java b/src/com/android/browser/view/BookmarkExpandableGridView.java
index 1d603cc..0c8f669 100644
--- a/src/com/android/browser/view/BookmarkExpandableGridView.java
+++ b/src/com/android/browser/view/BookmarkExpandableGridView.java
@@ -16,12 +16,15 @@
 
 package com.android.browser.view;
 
+import com.android.browser.BookmarkDragHandler;
 import com.android.browser.BreadCrumbView;
 import com.android.browser.BrowserBookmarksAdapter;
 import com.android.browser.R;
+import com.android.browser.BookmarkDragHandler.BookmarkDragAdapter;
 import com.android.internal.view.menu.MenuBuilder;
 
 import android.content.Context;
+import android.database.Cursor;
 import android.database.DataSetObserver;
 import android.provider.BrowserContract;
 import android.util.AttributeSet;
@@ -51,6 +54,7 @@
     private OnCreateContextMenuListener mOnCreateContextMenuListener;
     private boolean mLongClickable;
     private BreadCrumbView.Controller mBreadcrumbController;
+    private BookmarkDragHandler mDragHandler;
 
     public BookmarkExpandableGridView(Context context) {
         super(context);
@@ -169,8 +173,8 @@
         int groupPosition = (Integer) originalView.getTag(R.id.group_position);
         int childPosition = (Integer) originalView.getTag(R.id.child_position);
 
-        mContextMenuInfo = new BookmarkContextMenuInfo(originalView,
-                childPosition, groupPosition);
+        mContextMenuInfo = new BookmarkContextMenuInfo(childPosition,
+                groupPosition);
         if (getParent() != null) {
             getParent().showContextMenuForChild(this);
         }
@@ -198,6 +202,25 @@
         return mAdapter.mChildren.get(groupPosition);
     }
 
+    public BookmarkDragAdapter getDragAdapter() {
+        return mDragAdapter;
+    }
+
+    private BookmarkDragAdapter mDragAdapter = new BookmarkDragAdapter() {
+
+        @Override
+        public void setBookmarkDragHandler(BookmarkDragHandler handler) {
+            mDragHandler = handler;
+        }
+
+        @Override
+        public Cursor getItemForView(View v) {
+            int groupPosition = (Integer) v.getTag(R.id.group_position);
+            int childPosition = (Integer) v.getTag(R.id.child_position);
+            return getChildAdapter(groupPosition).getItem(childPosition);
+        }
+    };
+
     private OnClickListener mChildClickListener = new OnClickListener() {
 
         @Override
@@ -225,6 +248,18 @@
         }
     };
 
+    private OnLongClickListener mChildOnLongClickListener = new OnLongClickListener() {
+
+        @Override
+        public boolean onLongClick(View v) {
+            int groupPosition = (Integer) v.getTag(R.id.group_position);
+            int childPosition = (Integer) v.getTag(R.id.child_position);
+            long id = (Long) v.getTag(R.id.child_id);
+            Cursor c = getChildAdapter(groupPosition).getItem(childPosition);
+            return mDragHandler.startDrag(v, c, id);
+        }
+    };
+
     public BreadCrumbView getBreadCrumbs(int groupPosition) {
         return mAdapter.getBreadCrumbView(groupPosition);
     }
@@ -302,6 +337,10 @@
                     v.setTag(R.id.child_id, childAdapter.getItemId(realChildPosition));
                     v.setOnClickListener(mChildClickListener);
                     v.setLongClickable(mLongClickable);
+                    if (mDragHandler != null) {
+                        v.setOnLongClickListener(mChildOnLongClickListener);
+                        mDragHandler.registerBookmarkDragHandler(v);
+                    }
                     if (cv == null) {
                         row.addView(v);
                     } else if (cv != v) {
@@ -409,14 +448,11 @@
 
     public static class BookmarkContextMenuInfo implements ContextMenuInfo {
 
-        private BookmarkContextMenuInfo(View targetView, int childPosition,
-                int groupPosition) {
-            this.targetView = targetView;
+        private BookmarkContextMenuInfo(int childPosition, int groupPosition) {
             this.childPosition = childPosition;
             this.groupPosition = groupPosition;
         }
 
-        public View targetView;
         public int childPosition;
         public int groupPosition;
     }