BrowserBookmarksPage.java revision 8af906474c84854598da1886edacfd5f10cae70f
1/*
2 * Copyright (C) 2006 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.app.AlertDialog;
21import android.app.Fragment;
22import android.app.LoaderManager;
23import android.content.ClipData;
24import android.content.ClipboardManager;
25import android.content.ContentResolver;
26import android.content.ContentUris;
27import android.content.ContentValues;
28import android.content.Context;
29import android.content.CursorLoader;
30import android.content.DialogInterface;
31import android.content.Intent;
32import android.content.Loader;
33import android.content.SharedPreferences;
34import android.content.SharedPreferences.Editor;
35import android.database.Cursor;
36import android.graphics.Bitmap;
37import android.graphics.BitmapFactory;
38import android.net.Uri;
39import android.os.Bundle;
40import android.preference.PreferenceManager;
41import android.provider.BrowserContract;
42import android.provider.BrowserContract.Accounts;
43import android.text.TextUtils;
44import android.view.ContextMenu;
45import android.view.ContextMenu.ContextMenuInfo;
46import android.view.LayoutInflater;
47import android.view.MenuInflater;
48import android.view.MenuItem;
49import android.view.View;
50import android.view.ViewGroup;
51import android.webkit.WebIconDatabase.IconListener;
52import android.widget.Adapter;
53import android.widget.AdapterView;
54import android.widget.AdapterView.OnItemClickListener;
55import android.widget.AdapterView.OnItemSelectedListener;
56import android.widget.GridView;
57import android.widget.ListView;
58import android.widget.Toast;
59
60/**
61 *  View showing the user's bookmarks in the browser.
62 */
63public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener,
64        LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, IconListener,
65        OnItemSelectedListener {
66
67    static final int BOOKMARKS_SAVE = 1;
68    static final String LOGTAG = "browser";
69
70    static final int LOADER_BOOKMARKS = 1;
71    static final int LOADER_ACCOUNTS_THEN_BOOKMARKS = 2;
72
73    static final String EXTRA_SHORTCUT = "create_shortcut";
74    static final String EXTRA_DISABLE_WINDOW = "disable_new_window";
75
76    static final String ACCOUNT_NAME_UNSYNCED = "Unsynced";
77
78    public static final String PREF_ACCOUNT_TYPE = "acct_type";
79    public static final String PREF_ACCOUNT_NAME = "acct_name";
80
81    static final String DEFAULT_ACCOUNT = "local";
82    static final int VIEW_THUMBNAILS = 1;
83    static final int VIEW_LIST = 2;
84    static final String PREF_SELECTED_VIEW = "bookmarks_view";
85
86    BookmarksHistoryCallbacks mCallbacks;
87    GridView mGrid;
88    ListView mList;
89    BrowserBookmarksAdapter mAdapter;
90    boolean mDisableNewWindow;
91    BookmarkItem mContextHeader;
92    boolean mCanceled = false;
93    boolean mCreateShortcut;
94    View mEmptyView;
95    int mCurrentView;
96
97    BreadCrumbView mCrumbs;
98
99    static BrowserBookmarksPage newInstance(BookmarksHistoryCallbacks cb,
100            BreadCrumbView crumbs, Bundle args) {
101        BrowserBookmarksPage bbp = new BrowserBookmarksPage();
102        bbp.mCallbacks = cb;
103        bbp.setArguments(args);
104        bbp.mCrumbs = crumbs;
105        return bbp;
106    }
107
108    @Override
109    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
110        switch (id) {
111            case LOADER_BOOKMARKS: {
112                String accountType = null;
113                String accountName = null;
114                if (args != null) {
115                    accountType = args.getString(BookmarksLoader.ARG_ACCOUNT_TYPE);
116                    accountName = args.getString(BookmarksLoader.ARG_ACCOUNT_NAME);
117                }
118                BookmarksLoader bl = new BookmarksLoader(getActivity(), accountType, accountName);
119                if (mCrumbs != null) {
120                    Uri uri = (Uri) mCrumbs.getTopData();
121                    if (uri != null) {
122                        bl.setUri(uri);
123                    }
124                }
125                return bl;
126            }
127            case LOADER_ACCOUNTS_THEN_BOOKMARKS: {
128                return new CursorLoader(getActivity(), Accounts.CONTENT_URI,
129                        new String[] { Accounts.ACCOUNT_TYPE, Accounts.ACCOUNT_NAME }, null, null,
130                        null);
131            }
132        }
133        throw new UnsupportedOperationException("Unknown loader id " + id);
134    }
135
136    @Override
137    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
138        switch (loader.getId()) {
139            case LOADER_BOOKMARKS: {
140                // Set the visibility of the empty vs. content views
141                if (cursor == null || cursor.getCount() == 0) {
142                    mEmptyView.setVisibility(View.VISIBLE);
143                    mGrid.setVisibility(View.GONE);
144                    mList.setVisibility(View.GONE);
145                } else {
146                    mEmptyView.setVisibility(View.GONE);
147                    setupBookmarkView();
148                }
149
150                // Give the new data to the adapter
151                mAdapter.changeCursor(cursor);
152                break;
153            }
154
155            case LOADER_ACCOUNTS_THEN_BOOKMARKS: {
156                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
157                        getActivity());
158                String storedAccountType = prefs.getString(PREF_ACCOUNT_TYPE, null);
159                String storedAccountName = prefs.getString(PREF_ACCOUNT_NAME, null);
160                String accountType =
161                        TextUtils.isEmpty(storedAccountType) ? DEFAULT_ACCOUNT : storedAccountType;
162                String accountName =
163                        TextUtils.isEmpty(storedAccountName) ? DEFAULT_ACCOUNT : storedAccountName;
164
165                Bundle args = null;
166                if (cursor == null || !cursor.moveToFirst()) {
167                    // No accounts, set the prefs to the default
168                    accountType = DEFAULT_ACCOUNT;
169                    accountName = DEFAULT_ACCOUNT;
170                } else {
171                    int accountPosition = -1;
172
173                    if (!DEFAULT_ACCOUNT.equals(accountType) &&
174                            !DEFAULT_ACCOUNT.equals(accountName)) {
175                        // Check to see if the account in prefs still exists
176                        cursor.moveToFirst();
177                        do {
178                            if (accountType.equals(cursor.getString(0))
179                                    && accountName.equals(cursor.getString(1))) {
180                                accountPosition = cursor.getPosition();
181                                break;
182                            }
183                        } while (cursor.moveToNext());
184                    }
185
186                    if (accountPosition == -1) {
187                        if (!(DEFAULT_ACCOUNT.equals(accountType)
188                                && DEFAULT_ACCOUNT.equals(accountName))) {
189                            // No account is set in prefs and there is at least one,
190                            // so pick the first one as the default
191                            cursor.moveToFirst();
192                            accountType = cursor.getString(0);
193                            accountName = cursor.getString(1);
194                        }
195                    }
196
197                    args = new Bundle();
198                    args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType);
199                    args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName);
200                }
201
202                // The stored account name wasn't found, update the stored account with a valid one
203                if (!accountType.equals(storedAccountType)
204                        || !accountName.equals(storedAccountName)) {
205                    prefs.edit()
206                            .putString(PREF_ACCOUNT_TYPE, accountType)
207                            .putString(PREF_ACCOUNT_NAME, accountName)
208                            .apply();
209                }
210                getLoaderManager().initLoader(LOADER_BOOKMARKS, args, this);
211
212                break;
213            }
214        }
215    }
216
217    long getFolderId() {
218        LoaderManager manager = getLoaderManager();
219        BookmarksLoader loader =
220                (BookmarksLoader) ((Loader)(manager.getLoader(LOADER_BOOKMARKS)));
221
222        Uri uri = loader.getUri();
223        if (uri != null) {
224            try {
225                return ContentUris.parseId(uri);
226            } catch (NumberFormatException nfx) {
227                return -1;
228            }
229        }
230        return -1;
231    }
232
233    public void onFolderChange(int level, Object data) {
234        Uri uri = (Uri) data;
235        if (uri == null) {
236            // top level
237            uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
238        }
239        LoaderManager manager = getLoaderManager();
240        BookmarksLoader loader =
241                (BookmarksLoader) ((Loader) manager.getLoader(LOADER_BOOKMARKS));
242        loader.setUri(uri);
243        loader.forceLoad();
244
245    }
246
247    @Override
248    public boolean onContextItemSelected(MenuItem item) {
249        final Activity activity = getActivity();
250        // It is possible that the view has been canceled when we get to
251        // this point as back has a higher priority
252        if (mCanceled) {
253            return false;
254        }
255        AdapterView.AdapterContextMenuInfo i =
256            (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
257        // If we have no menu info, we can't tell which item was selected.
258        if (i == null) {
259            return false;
260        }
261
262        switch (item.getItemId()) {
263        case R.id.open_context_menu_id:
264            loadUrl(i.position);
265            break;
266        case R.id.edit_context_menu_id:
267            editBookmark(i.position);
268            break;
269        case R.id.shortcut_context_menu_id:
270            activity.sendBroadcast(createShortcutIntent(i.position));
271            break;
272        case R.id.delete_context_menu_id:
273            displayRemoveBookmarkDialog(i.position);
274            break;
275        case R.id.new_window_context_menu_id:
276            openInNewWindow(i.position);
277            break;
278        case R.id.share_link_context_menu_id: {
279            Cursor cursor = (Cursor) mAdapter.getItem(i.position);
280            Controller.sharePage(activity,
281                    cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE),
282                    cursor.getString(BookmarksLoader.COLUMN_INDEX_URL),
283                    getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON),
284                    getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL));
285            break;
286        }
287        case R.id.copy_url_context_menu_id:
288            copy(getUrl(i.position));
289            break;
290        case R.id.homepage_context_menu_id: {
291            BrowserSettings.getInstance().setHomePage(activity, getUrl(i.position));
292            Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
293            break;
294        }
295        // Only for the Most visited page
296        case R.id.save_to_bookmarks_menu_id: {
297            Cursor cursor = (Cursor) mAdapter.getItem(i.position);
298            String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
299            String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
300            // If the site is bookmarked, the item becomes remove from
301            // bookmarks.
302            Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name);
303            break;
304        }
305        default:
306            return super.onContextItemSelected(item);
307        }
308        return true;
309    }
310
311    Bitmap getBitmap(Cursor cursor, int columnIndex) {
312        byte[] data = cursor.getBlob(columnIndex);
313        if (data == null) {
314            return null;
315        }
316        return BitmapFactory.decodeByteArray(data, 0, data.length);
317    }
318
319    @Override
320    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
321        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
322        Cursor cursor = (Cursor) mAdapter.getItem(info.position);
323        boolean isFolder
324                = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
325        if (isFolder) return;
326
327        final Activity activity = getActivity();
328        MenuInflater inflater = activity.getMenuInflater();
329        inflater.inflate(R.menu.bookmarkscontext, menu);
330
331        if (mDisableNewWindow) {
332            menu.findItem(R.id.new_window_context_menu_id).setVisible(false);
333        }
334
335        if (mContextHeader == null) {
336            mContextHeader = new BookmarkItem(activity);
337        } else if (mContextHeader.getParent() != null) {
338            ((ViewGroup) mContextHeader.getParent()).removeView(mContextHeader);
339        }
340
341        populateBookmarkItem(cursor, mContextHeader);
342
343        menu.setHeaderView(mContextHeader);
344    }
345
346    private void populateBookmarkItem(Cursor cursor, BookmarkItem item) {
347        String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
348        item.setUrl(url);
349        item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
350        Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
351        if (bitmap == null) {
352            bitmap = CombinedBookmarkHistoryView.getIconListenerSet().getFavicon(url);
353        }
354        item.setFavicon(bitmap);
355    }
356
357    /**
358     *  Create a new BrowserBookmarksPage.
359     */
360    @Override
361    public void onCreate(Bundle icicle) {
362        super.onCreate(icicle);
363
364        Bundle args = getArguments();
365        mCreateShortcut = args == null ? false : args.getBoolean(EXTRA_SHORTCUT, false);
366        mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
367    }
368
369    @Override
370    public View onCreateView(LayoutInflater inflater, ViewGroup container,
371            Bundle savedInstanceState) {
372        Context context = getActivity();
373
374        View root = inflater.inflate(R.layout.bookmarks, container, false);
375        mEmptyView = root.findViewById(android.R.id.empty);
376
377        mGrid = (GridView) root.findViewById(R.id.grid);
378        mGrid.setOnItemClickListener(this);
379        mGrid.setColumnWidth(Controller.getDesiredThumbnailWidth(getActivity()));
380        if (!mCreateShortcut) {
381            mGrid.setOnCreateContextMenuListener(this);
382        }
383        mList = (ListView) root.findViewById(R.id.list);
384        mList.setOnItemClickListener(this);
385        if (!mCreateShortcut) {
386            mList.setOnCreateContextMenuListener(this);
387            registerForContextMenu(mList);
388        }
389
390        // Start the loaders
391        LoaderManager lm = getLoaderManager();
392        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
393        mCurrentView =
394            prefs.getInt(PREF_SELECTED_VIEW, BrowserBookmarksPage.VIEW_THUMBNAILS);
395        mAdapter = new BrowserBookmarksAdapter(getActivity(), mCurrentView);
396        String accountType = prefs.getString(PREF_ACCOUNT_TYPE, DEFAULT_ACCOUNT);
397        String accountName = prefs.getString(PREF_ACCOUNT_NAME, DEFAULT_ACCOUNT);
398        if (!TextUtils.isEmpty(accountType) && !TextUtils.isEmpty(accountName)) {
399            // There is an account set, load up that one
400            Bundle args = null;
401            if (!DEFAULT_ACCOUNT.equals(accountType) && !DEFAULT_ACCOUNT.equals(accountName)) {
402                args = new Bundle();
403                args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType);
404                args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName);
405            }
406            lm.restartLoader(LOADER_BOOKMARKS, args, this);
407        } else {
408            // No account set, load the account list first
409            lm.restartLoader(LOADER_ACCOUNTS_THEN_BOOKMARKS, null, this);
410        }
411
412        // Add our own listener in case there are favicons that have yet to be loaded.
413        CombinedBookmarkHistoryView.getIconListenerSet().addListener(this);
414
415        return root;
416    }
417
418    @Override
419    public void onReceivedIcon(String url, Bitmap icon) {
420        // A new favicon has been loaded, so let anything attached to the adapter know about it
421        // so new icons will be loaded.
422        mAdapter.notifyDataSetChanged();
423    }
424
425    @Override
426    public void onItemClick(AdapterView parent, View v, int position, long id) {
427        // It is possible that the view has been canceled when we get to
428        // this point as back has a higher priority
429        if (mCanceled) {
430            android.util.Log.e(LOGTAG, "item clicked when dismissing");
431            return;
432        }
433
434        if (mCreateShortcut) {
435            Intent intent = createShortcutIntent(position);
436            // the activity handles the intent in startActivityFromFragment
437            startActivity(intent);
438            return;
439        }
440
441        Cursor cursor = (Cursor) mAdapter.getItem(position);
442        boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
443        if (!isFolder) {
444            mCallbacks.onUrlSelected(getUrl(position), false);
445        } else {
446            String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
447            LoaderManager manager = getLoaderManager();
448            BookmarksLoader loader =
449                    (BookmarksLoader) ((Loader) manager.getLoader(LOADER_BOOKMARKS));
450            Uri uri = ContentUris.withAppendedId(
451                    BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
452            if (mCrumbs != null) {
453                // update crumbs
454                mCrumbs.pushView(title, uri);
455            }
456            loader.setUri(uri);
457            loader.forceLoad();
458        }
459    }
460
461    @Override
462    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
463        Adapter adapter = parent.getAdapter();
464        String accountType = "com.google";
465        String accountName = adapter.getItem(position).toString();
466
467        Bundle args = null;
468        if (ACCOUNT_NAME_UNSYNCED.equals(accountName)) {
469            accountType = DEFAULT_ACCOUNT;
470            accountName = DEFAULT_ACCOUNT;
471        } else {
472            args = new Bundle();
473            args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType);
474            args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName);
475        }
476
477        // Remember the selection for later
478        PreferenceManager.getDefaultSharedPreferences(getActivity()).edit()
479                .putString(PREF_ACCOUNT_TYPE, accountType)
480                .putString(PREF_ACCOUNT_NAME, accountName)
481                .apply();
482
483        getLoaderManager().restartLoader(LOADER_BOOKMARKS, args, this);
484    }
485
486    @Override
487    public void onNothingSelected(AdapterView<?> parent) {
488        // Do nothing
489    }
490
491    private Intent createShortcutIntent(int position) {
492        Cursor cursor = (Cursor) mAdapter.getItem(position);
493        String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
494        String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
495        Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
496        Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
497        return BookmarkUtils.createAddToHomeIntent(getActivity(), url, title, touchIcon, favicon);
498    }
499
500    private void loadUrl(int position) {
501        mCallbacks.onUrlSelected(getUrl(position), false);
502    }
503
504    private void openInNewWindow(int position) {
505        mCallbacks.onUrlSelected(getUrl(position), true);
506    }
507
508    private void editBookmark(int position) {
509        Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
510        Cursor cursor = (Cursor) mAdapter.getItem(position);
511        Bundle item = new Bundle();
512        item.putString(BrowserContract.Bookmarks.TITLE,
513                cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
514        item.putString(BrowserContract.Bookmarks.URL,
515                cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
516        byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
517        if (data != null) {
518            item.putParcelable(BrowserContract.Bookmarks.FAVICON,
519                    BitmapFactory.decodeByteArray(data, 0, data.length));
520        }
521        item.putInt("id", cursor.getInt(BookmarksLoader.COLUMN_INDEX_ID));
522        item.putLong(BrowserContract.Bookmarks.PARENT,
523                cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
524        intent.putExtra("bookmark", item);
525        startActivityForResult(intent, BOOKMARKS_SAVE);
526    }
527
528    @Override
529    public void onActivityResult(int requestCode, int resultCode, Intent data) {
530        switch(requestCode) {
531            case BOOKMARKS_SAVE:
532                if (resultCode == Activity.RESULT_OK) {
533                    Bundle extras;
534                    if (data != null && (extras = data.getExtras()) != null) {
535                        // If there are extras, then we need to save
536                        // the edited bookmark. This is done in updateRow()
537                        String title = extras.getString(BrowserContract.Bookmarks.TITLE);
538                        String url = extras.getString(BrowserContract.Bookmarks.URL);
539                        if (title != null && url != null) {
540                            updateRow(extras);
541                        }
542                    }
543                }
544                break;
545        }
546    }
547
548    /**
549     *  Update a row in the database with new information.
550     *  @param map  Bundle storing id, title and url of new information
551     */
552    public void updateRow(Bundle map) {
553
554        // Find the record
555        int id = map.getInt("id");
556        int position = -1;
557        Cursor cursor = mAdapter.getCursor();
558        for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
559            if (cursor.getInt(BookmarksLoader.COLUMN_INDEX_ID) == id) {
560                position = cursor.getPosition();
561                break;
562            }
563        }
564        if (position < 0) {
565            return;
566        }
567
568        cursor.moveToPosition(position);
569        ContentValues values = new ContentValues();
570        String title = map.getString(BrowserContract.Bookmarks.TITLE);
571        if (!title.equals(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE))) {
572            values.put(BrowserContract.Bookmarks.TITLE, title);
573        }
574        String url = map.getString(BrowserContract.Bookmarks.URL);
575        if (!url.equals(cursor.getString(BookmarksLoader.COLUMN_INDEX_URL))) {
576            values.put(BrowserContract.Bookmarks.URL, url);
577        }
578
579        if (map.getBoolean(AddBookmarkPage.REMOVE_THUMBNAIL)) {
580            values.putNull(BrowserContract.Bookmarks.THUMBNAIL);
581        }
582
583        if (values.size() > 0) {
584            getActivity().getContentResolver().update(
585                    ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, id),
586                    values, null, null);
587        }
588    }
589
590    private void displayRemoveBookmarkDialog(final int position) {
591        // Put up a dialog asking if the user really wants to
592        // delete the bookmark
593        Cursor cursor = (Cursor) mAdapter.getItem(position);
594        Context context = getActivity();
595        final ContentResolver resolver = context.getContentResolver();
596        final Uri uri = ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI,
597                cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
598
599        new AlertDialog.Builder(context)
600                .setTitle(R.string.delete_bookmark)
601                .setIcon(android.R.drawable.ic_dialog_alert)
602                .setMessage(context.getString(R.string.delete_bookmark_warning,
603                        cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE)))
604                .setPositiveButton(R.string.ok,
605                        new DialogInterface.OnClickListener() {
606                            @Override
607                            public void onClick(DialogInterface dialog, int whichButton) {
608                                resolver.delete(uri, null, null);
609                            }
610                        })
611                .setNegativeButton(R.string.cancel, null)
612                .show();
613    }
614
615    private String getUrl(int position) {
616        Cursor cursor = (Cursor) mAdapter.getItem(position);
617        return cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
618    }
619
620    private void copy(CharSequence text) {
621        ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
622                Context.CLIPBOARD_SERVICE);
623        cm.setPrimaryClip(ClipData.newRawUri(null, null, Uri.parse(text.toString())));
624    }
625
626    void selectView(int view) {
627        if (view == mCurrentView) {
628            return;
629        }
630        mCurrentView = view;
631        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
632        Editor edit = prefs.edit();
633        edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
634        edit.apply();
635        if (mEmptyView.getVisibility() == View.VISIBLE) {
636            return;
637        }
638        setupBookmarkView();
639    }
640
641    private void setupBookmarkView() {
642        mAdapter.selectView(mCurrentView);
643        switch (mCurrentView) {
644        case VIEW_THUMBNAILS:
645            mList.setAdapter(null);
646            mGrid.setAdapter(mAdapter);
647            mGrid.setVisibility(View.VISIBLE);
648            mList.setVisibility(View.GONE);
649            break;
650        case VIEW_LIST:
651            mGrid.setAdapter(null);
652            mList.setAdapter(mAdapter);
653            mGrid.setVisibility(View.GONE);
654            mList.setVisibility(View.VISIBLE);
655            break;
656        }
657    }
658}
659