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