1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.browser;
18
19import android.app.Activity;
20import android.content.ClipData;
21import android.content.ContentResolver;
22import android.content.ContentUris;
23import android.content.ContentValues;
24import android.database.Cursor;
25import android.net.Uri;
26import android.provider.BrowserContract;
27import android.view.ActionMode;
28import android.view.ActionMode.Callback;
29import android.view.DragEvent;
30import android.view.Menu;
31import android.view.MenuItem;
32import android.view.View;
33import android.view.View.OnDragListener;
34import android.view.ViewGroup;
35
36public class BookmarkDragHandler implements Callback {
37
38    public static interface BookmarkDragController {
39        boolean startDrag(Cursor item);
40
41        ViewGroup getActionModeView(ActionMode mode, BookmarkDragState state);
42        void actionItemClicked(View v, BookmarkDragState state);
43    }
44
45    public static interface BookmarkDragAdapter {
46        void setBookmarkDragHandler(BookmarkDragHandler handler);
47        Cursor getItemForView(View v);
48    }
49
50    public static class BookmarkDragState {
51        public long id;
52        public long parent;
53        public Object extraState;
54    }
55
56    static final String BOOKMARK_DRAG_LABEL = "com.android.browser.BOOKMARK_LABEL";
57
58    private Activity mActivity;
59    private BookmarkDragController mDragController;
60    private BookmarkDragAdapter mDragAdapter;
61    private ActionMode mActionMode;
62    private BookmarkDragState mDragState;
63
64    public BookmarkDragHandler(Activity activity, BookmarkDragController controller,
65            BookmarkDragAdapter adapter) {
66        mActivity = activity;
67        mDragController = controller;
68        mDragAdapter = adapter;
69        mDragAdapter.setBookmarkDragHandler(this);
70    }
71
72    public boolean startDrag(View view, Cursor item, long id, Object extraState) {
73        if (!mDragController.startDrag(item)) {
74            return false;
75        }
76        Uri uri = ContentUris.withAppendedId(
77                BrowserContract.Bookmarks.CONTENT_URI, id);
78        ClipData data = ClipData.newRawUri(BOOKMARK_DRAG_LABEL, uri);
79        BookmarkDragState state = new BookmarkDragState();
80        state.id = id;
81        state.parent = item.getLong(BookmarksLoader.COLUMN_INDEX_PARENT);
82        state.extraState = extraState;
83        mDragState = state;
84        view.startDrag(data, new View.DragShadowBuilder(view), state, 0);
85        mActionMode = view.startActionMode(this);
86        return true;
87    }
88
89    public void registerBookmarkDragHandler(View view) {
90        view.setOnDragListener(mBookmarkDragListener);
91    }
92
93    private OnDragListener mBookmarkDragListener = new OnDragListener() {
94
95        @Override
96        public boolean onDrag(View v, DragEvent event) {
97            Cursor c = mDragAdapter.getItemForView(v);
98            BookmarkDragState state = (BookmarkDragState) event.getLocalState();
99            switch (event.getAction()) {
100            case DragEvent.ACTION_DRAG_STARTED:
101                return true;
102            case DragEvent.ACTION_DROP:
103                long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
104                if (id == state.id) {
105                    // We dropped onto ourselves, show the context menu
106                    v.showContextMenu();
107                    return false;
108                }
109                long parent = c.getLong(BookmarksLoader.COLUMN_INDEX_PARENT);
110                if (isFolder(c)) {
111                    parent = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
112                }
113                if (parent != state.parent) {
114                    ContentResolver cr = mActivity.getContentResolver();
115                    ContentValues values = new ContentValues();
116                    values.put(BrowserContract.Bookmarks.PARENT, parent);
117                    Uri uri = event.getClipData().getItemAt(0).getUri();
118                    cr.update(uri, values, null, null);
119                }
120                break;
121            }
122            return false;
123        }
124    };
125
126    private OnDragListener mActionModeDragListener = new OnDragListener() {
127
128        @Override
129        public boolean onDrag(View v, DragEvent event) {
130            BookmarkDragState state = (BookmarkDragState) event.getLocalState();
131            switch (event.getAction()) {
132            case DragEvent.ACTION_DRAG_STARTED:
133                return true;
134            case DragEvent.ACTION_DROP:
135                mDragController.actionItemClicked(v, state);
136                // fall through
137            case DragEvent.ACTION_DRAG_ENDED:
138                if (mActionMode != null) {
139                    mActionMode.finish();
140                    mActionMode = null;
141                }
142                return true;
143            }
144            return false;
145        }
146    };
147
148    static boolean isFolder(Cursor c) {
149        return c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
150    }
151
152    @Override
153    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
154        ViewGroup view = mDragController.getActionModeView(mode, mDragState);
155        int count = view.getChildCount();
156        for (int i = 0; i < count; i++) {
157            view.getChildAt(i).setOnDragListener(mActionModeDragListener);
158        }
159        mode.setCustomView(view);
160        return true;
161    }
162
163    @Override
164    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
165        return true;
166    }
167
168    @Override
169    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
170        return false;
171    }
172
173    @Override
174    public void onDestroyActionMode(ActionMode mode) {
175    }
176
177}
178