166302e5f0622fce8f0250afcd722c5597ba76261John Reck/* 266302e5f0622fce8f0250afcd722c5597ba76261John Reck * Copyright (C) 2011 The Android Open Source Project 366302e5f0622fce8f0250afcd722c5597ba76261John Reck * 466302e5f0622fce8f0250afcd722c5597ba76261John Reck * Licensed under the Apache License, Version 2.0 (the "License"); 566302e5f0622fce8f0250afcd722c5597ba76261John Reck * you may not use this file except in compliance with the License. 666302e5f0622fce8f0250afcd722c5597ba76261John Reck * You may obtain a copy of the License at 766302e5f0622fce8f0250afcd722c5597ba76261John Reck * 866302e5f0622fce8f0250afcd722c5597ba76261John Reck * http://www.apache.org/licenses/LICENSE-2.0 966302e5f0622fce8f0250afcd722c5597ba76261John Reck * 1066302e5f0622fce8f0250afcd722c5597ba76261John Reck * Unless required by applicable law or agreed to in writing, software 1166302e5f0622fce8f0250afcd722c5597ba76261John Reck * distributed under the License is distributed on an "AS IS" BASIS, 1266302e5f0622fce8f0250afcd722c5597ba76261John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1366302e5f0622fce8f0250afcd722c5597ba76261John Reck * See the License for the specific language governing permissions and 1466302e5f0622fce8f0250afcd722c5597ba76261John Reck * limitations under the License. 1566302e5f0622fce8f0250afcd722c5597ba76261John Reck */ 1666302e5f0622fce8f0250afcd722c5597ba76261John Reck 1766302e5f0622fce8f0250afcd722c5597ba76261John Reckpackage com.android.browser; 1866302e5f0622fce8f0250afcd722c5597ba76261John Reck 19e7c97de989b75a591d598da63e0bef51831462d4John Reckimport android.app.Activity; 2066302e5f0622fce8f0250afcd722c5597ba76261John Reckimport android.content.ClipData; 2166302e5f0622fce8f0250afcd722c5597ba76261John Reckimport android.content.ContentResolver; 2266302e5f0622fce8f0250afcd722c5597ba76261John Reckimport android.content.ContentUris; 2366302e5f0622fce8f0250afcd722c5597ba76261John Reckimport android.content.ContentValues; 2466302e5f0622fce8f0250afcd722c5597ba76261John Reckimport android.database.Cursor; 2566302e5f0622fce8f0250afcd722c5597ba76261John Reckimport android.net.Uri; 2666302e5f0622fce8f0250afcd722c5597ba76261John Reckimport android.provider.BrowserContract; 27e7c97de989b75a591d598da63e0bef51831462d4John Reckimport android.view.ActionMode; 28e7c97de989b75a591d598da63e0bef51831462d4John Reckimport android.view.ActionMode.Callback; 2966302e5f0622fce8f0250afcd722c5597ba76261John Reckimport android.view.DragEvent; 30e7c97de989b75a591d598da63e0bef51831462d4John Reckimport android.view.Menu; 31e7c97de989b75a591d598da63e0bef51831462d4John Reckimport android.view.MenuItem; 3266302e5f0622fce8f0250afcd722c5597ba76261John Reckimport android.view.View; 3366302e5f0622fce8f0250afcd722c5597ba76261John Reckimport android.view.View.OnDragListener; 34e7c97de989b75a591d598da63e0bef51831462d4John Reckimport android.view.ViewGroup; 3566302e5f0622fce8f0250afcd722c5597ba76261John Reck 36e7c97de989b75a591d598da63e0bef51831462d4John Reckpublic class BookmarkDragHandler implements Callback { 3766302e5f0622fce8f0250afcd722c5597ba76261John Reck 3866302e5f0622fce8f0250afcd722c5597ba76261John Reck public static interface BookmarkDragController { 3966302e5f0622fce8f0250afcd722c5597ba76261John Reck boolean startDrag(Cursor item); 40e7c97de989b75a591d598da63e0bef51831462d4John Reck 41e7c97de989b75a591d598da63e0bef51831462d4John Reck ViewGroup getActionModeView(ActionMode mode, BookmarkDragState state); 42e7c97de989b75a591d598da63e0bef51831462d4John Reck void actionItemClicked(View v, BookmarkDragState state); 4366302e5f0622fce8f0250afcd722c5597ba76261John Reck } 4466302e5f0622fce8f0250afcd722c5597ba76261John Reck 4566302e5f0622fce8f0250afcd722c5597ba76261John Reck public static interface BookmarkDragAdapter { 4666302e5f0622fce8f0250afcd722c5597ba76261John Reck void setBookmarkDragHandler(BookmarkDragHandler handler); 4766302e5f0622fce8f0250afcd722c5597ba76261John Reck Cursor getItemForView(View v); 4866302e5f0622fce8f0250afcd722c5597ba76261John Reck } 4966302e5f0622fce8f0250afcd722c5597ba76261John Reck 50e7c97de989b75a591d598da63e0bef51831462d4John Reck public static class BookmarkDragState { 51e7c97de989b75a591d598da63e0bef51831462d4John Reck public long id; 52e7c97de989b75a591d598da63e0bef51831462d4John Reck public long parent; 53e7c97de989b75a591d598da63e0bef51831462d4John Reck public Object extraState; 5466302e5f0622fce8f0250afcd722c5597ba76261John Reck } 5566302e5f0622fce8f0250afcd722c5597ba76261John Reck 5666302e5f0622fce8f0250afcd722c5597ba76261John Reck static final String BOOKMARK_DRAG_LABEL = "com.android.browser.BOOKMARK_LABEL"; 5766302e5f0622fce8f0250afcd722c5597ba76261John Reck 58e7c97de989b75a591d598da63e0bef51831462d4John Reck private Activity mActivity; 5966302e5f0622fce8f0250afcd722c5597ba76261John Reck private BookmarkDragController mDragController; 6066302e5f0622fce8f0250afcd722c5597ba76261John Reck private BookmarkDragAdapter mDragAdapter; 61e7c97de989b75a591d598da63e0bef51831462d4John Reck private ActionMode mActionMode; 62e7c97de989b75a591d598da63e0bef51831462d4John Reck private BookmarkDragState mDragState; 6366302e5f0622fce8f0250afcd722c5597ba76261John Reck 64e7c97de989b75a591d598da63e0bef51831462d4John Reck public BookmarkDragHandler(Activity activity, BookmarkDragController controller, 6566302e5f0622fce8f0250afcd722c5597ba76261John Reck BookmarkDragAdapter adapter) { 66e7c97de989b75a591d598da63e0bef51831462d4John Reck mActivity = activity; 6766302e5f0622fce8f0250afcd722c5597ba76261John Reck mDragController = controller; 6866302e5f0622fce8f0250afcd722c5597ba76261John Reck mDragAdapter = adapter; 6966302e5f0622fce8f0250afcd722c5597ba76261John Reck mDragAdapter.setBookmarkDragHandler(this); 7066302e5f0622fce8f0250afcd722c5597ba76261John Reck } 7166302e5f0622fce8f0250afcd722c5597ba76261John Reck 72e7c97de989b75a591d598da63e0bef51831462d4John Reck public boolean startDrag(View view, Cursor item, long id, Object extraState) { 7366302e5f0622fce8f0250afcd722c5597ba76261John Reck if (!mDragController.startDrag(item)) { 7466302e5f0622fce8f0250afcd722c5597ba76261John Reck return false; 7566302e5f0622fce8f0250afcd722c5597ba76261John Reck } 7666302e5f0622fce8f0250afcd722c5597ba76261John Reck Uri uri = ContentUris.withAppendedId( 7766302e5f0622fce8f0250afcd722c5597ba76261John Reck BrowserContract.Bookmarks.CONTENT_URI, id); 7866302e5f0622fce8f0250afcd722c5597ba76261John Reck ClipData data = ClipData.newRawUri(BOOKMARK_DRAG_LABEL, uri); 7966302e5f0622fce8f0250afcd722c5597ba76261John Reck BookmarkDragState state = new BookmarkDragState(); 8066302e5f0622fce8f0250afcd722c5597ba76261John Reck state.id = id; 8166302e5f0622fce8f0250afcd722c5597ba76261John Reck state.parent = item.getLong(BookmarksLoader.COLUMN_INDEX_PARENT); 82e7c97de989b75a591d598da63e0bef51831462d4John Reck state.extraState = extraState; 83e7c97de989b75a591d598da63e0bef51831462d4John Reck mDragState = state; 8466302e5f0622fce8f0250afcd722c5597ba76261John Reck view.startDrag(data, new View.DragShadowBuilder(view), state, 0); 85e7c97de989b75a591d598da63e0bef51831462d4John Reck mActionMode = view.startActionMode(this); 8666302e5f0622fce8f0250afcd722c5597ba76261John Reck return true; 8766302e5f0622fce8f0250afcd722c5597ba76261John Reck } 8866302e5f0622fce8f0250afcd722c5597ba76261John Reck 8966302e5f0622fce8f0250afcd722c5597ba76261John Reck public void registerBookmarkDragHandler(View view) { 9066302e5f0622fce8f0250afcd722c5597ba76261John Reck view.setOnDragListener(mBookmarkDragListener); 9166302e5f0622fce8f0250afcd722c5597ba76261John Reck } 9266302e5f0622fce8f0250afcd722c5597ba76261John Reck 9366302e5f0622fce8f0250afcd722c5597ba76261John Reck private OnDragListener mBookmarkDragListener = new OnDragListener() { 9466302e5f0622fce8f0250afcd722c5597ba76261John Reck 9566302e5f0622fce8f0250afcd722c5597ba76261John Reck @Override 9666302e5f0622fce8f0250afcd722c5597ba76261John Reck public boolean onDrag(View v, DragEvent event) { 9766302e5f0622fce8f0250afcd722c5597ba76261John Reck Cursor c = mDragAdapter.getItemForView(v); 9866302e5f0622fce8f0250afcd722c5597ba76261John Reck BookmarkDragState state = (BookmarkDragState) event.getLocalState(); 9966302e5f0622fce8f0250afcd722c5597ba76261John Reck switch (event.getAction()) { 10066302e5f0622fce8f0250afcd722c5597ba76261John Reck case DragEvent.ACTION_DRAG_STARTED: 10166302e5f0622fce8f0250afcd722c5597ba76261John Reck return true; 10266302e5f0622fce8f0250afcd722c5597ba76261John Reck case DragEvent.ACTION_DROP: 10366302e5f0622fce8f0250afcd722c5597ba76261John Reck long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID); 10466302e5f0622fce8f0250afcd722c5597ba76261John Reck if (id == state.id) { 10566302e5f0622fce8f0250afcd722c5597ba76261John Reck // We dropped onto ourselves, show the context menu 10666302e5f0622fce8f0250afcd722c5597ba76261John Reck v.showContextMenu(); 10766302e5f0622fce8f0250afcd722c5597ba76261John Reck return false; 10866302e5f0622fce8f0250afcd722c5597ba76261John Reck } 10966302e5f0622fce8f0250afcd722c5597ba76261John Reck long parent = c.getLong(BookmarksLoader.COLUMN_INDEX_PARENT); 11066302e5f0622fce8f0250afcd722c5597ba76261John Reck if (isFolder(c)) { 11166302e5f0622fce8f0250afcd722c5597ba76261John Reck parent = c.getLong(BookmarksLoader.COLUMN_INDEX_ID); 11266302e5f0622fce8f0250afcd722c5597ba76261John Reck } 11366302e5f0622fce8f0250afcd722c5597ba76261John Reck if (parent != state.parent) { 114e7c97de989b75a591d598da63e0bef51831462d4John Reck ContentResolver cr = mActivity.getContentResolver(); 11566302e5f0622fce8f0250afcd722c5597ba76261John Reck ContentValues values = new ContentValues(); 116e7c97de989b75a591d598da63e0bef51831462d4John Reck values.put(BrowserContract.Bookmarks.PARENT, parent); 11766302e5f0622fce8f0250afcd722c5597ba76261John Reck Uri uri = event.getClipData().getItemAt(0).getUri(); 11866302e5f0622fce8f0250afcd722c5597ba76261John Reck cr.update(uri, values, null, null); 11966302e5f0622fce8f0250afcd722c5597ba76261John Reck } 12066302e5f0622fce8f0250afcd722c5597ba76261John Reck break; 12166302e5f0622fce8f0250afcd722c5597ba76261John Reck } 12266302e5f0622fce8f0250afcd722c5597ba76261John Reck return false; 12366302e5f0622fce8f0250afcd722c5597ba76261John Reck } 12466302e5f0622fce8f0250afcd722c5597ba76261John Reck }; 12566302e5f0622fce8f0250afcd722c5597ba76261John Reck 126e7c97de989b75a591d598da63e0bef51831462d4John Reck private OnDragListener mActionModeDragListener = new OnDragListener() { 127e7c97de989b75a591d598da63e0bef51831462d4John Reck 128e7c97de989b75a591d598da63e0bef51831462d4John Reck @Override 129e7c97de989b75a591d598da63e0bef51831462d4John Reck public boolean onDrag(View v, DragEvent event) { 130e7c97de989b75a591d598da63e0bef51831462d4John Reck BookmarkDragState state = (BookmarkDragState) event.getLocalState(); 131e7c97de989b75a591d598da63e0bef51831462d4John Reck switch (event.getAction()) { 132e7c97de989b75a591d598da63e0bef51831462d4John Reck case DragEvent.ACTION_DRAG_STARTED: 133e7c97de989b75a591d598da63e0bef51831462d4John Reck return true; 134e7c97de989b75a591d598da63e0bef51831462d4John Reck case DragEvent.ACTION_DROP: 135e7c97de989b75a591d598da63e0bef51831462d4John Reck mDragController.actionItemClicked(v, state); 136e7c97de989b75a591d598da63e0bef51831462d4John Reck // fall through 137e7c97de989b75a591d598da63e0bef51831462d4John Reck case DragEvent.ACTION_DRAG_ENDED: 138e7c97de989b75a591d598da63e0bef51831462d4John Reck if (mActionMode != null) { 139e7c97de989b75a591d598da63e0bef51831462d4John Reck mActionMode.finish(); 140e7c97de989b75a591d598da63e0bef51831462d4John Reck mActionMode = null; 141e7c97de989b75a591d598da63e0bef51831462d4John Reck } 142e7c97de989b75a591d598da63e0bef51831462d4John Reck return true; 143e7c97de989b75a591d598da63e0bef51831462d4John Reck } 144e7c97de989b75a591d598da63e0bef51831462d4John Reck return false; 145e7c97de989b75a591d598da63e0bef51831462d4John Reck } 146e7c97de989b75a591d598da63e0bef51831462d4John Reck }; 147e7c97de989b75a591d598da63e0bef51831462d4John Reck 14866302e5f0622fce8f0250afcd722c5597ba76261John Reck static boolean isFolder(Cursor c) { 14966302e5f0622fce8f0250afcd722c5597ba76261John Reck return c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0; 15066302e5f0622fce8f0250afcd722c5597ba76261John Reck } 151e7c97de989b75a591d598da63e0bef51831462d4John Reck 152e7c97de989b75a591d598da63e0bef51831462d4John Reck @Override 153e7c97de989b75a591d598da63e0bef51831462d4John Reck public boolean onCreateActionMode(ActionMode mode, Menu menu) { 154e7c97de989b75a591d598da63e0bef51831462d4John Reck ViewGroup view = mDragController.getActionModeView(mode, mDragState); 155e7c97de989b75a591d598da63e0bef51831462d4John Reck int count = view.getChildCount(); 156e7c97de989b75a591d598da63e0bef51831462d4John Reck for (int i = 0; i < count; i++) { 157e7c97de989b75a591d598da63e0bef51831462d4John Reck view.getChildAt(i).setOnDragListener(mActionModeDragListener); 158e7c97de989b75a591d598da63e0bef51831462d4John Reck } 159e7c97de989b75a591d598da63e0bef51831462d4John Reck mode.setCustomView(view); 160e7c97de989b75a591d598da63e0bef51831462d4John Reck return true; 161e7c97de989b75a591d598da63e0bef51831462d4John Reck } 162e7c97de989b75a591d598da63e0bef51831462d4John Reck 163e7c97de989b75a591d598da63e0bef51831462d4John Reck @Override 164e7c97de989b75a591d598da63e0bef51831462d4John Reck public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 165e7c97de989b75a591d598da63e0bef51831462d4John Reck return true; 166e7c97de989b75a591d598da63e0bef51831462d4John Reck } 167e7c97de989b75a591d598da63e0bef51831462d4John Reck 168e7c97de989b75a591d598da63e0bef51831462d4John Reck @Override 169e7c97de989b75a591d598da63e0bef51831462d4John Reck public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 170e7c97de989b75a591d598da63e0bef51831462d4John Reck return false; 171e7c97de989b75a591d598da63e0bef51831462d4John Reck } 172e7c97de989b75a591d598da63e0bef51831462d4John Reck 173e7c97de989b75a591d598da63e0bef51831462d4John Reck @Override 174e7c97de989b75a591d598da63e0bef51831462d4John Reck public void onDestroyActionMode(ActionMode mode) { 175e7c97de989b75a591d598da63e0bef51831462d4John Reck } 176e7c97de989b75a591d598da63e0bef51831462d4John Reck 17766302e5f0622fce8f0250afcd722c5597ba76261John Reck} 178