BrowserBookmarksPage.java revision b9b2a8290874e447444c7791647cbade915bc47d
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 com.android.browser.BookmarkDragHandler.BookmarkDragController;
20import com.android.browser.view.BookmarkExpandableGridView;
21import com.android.browser.view.BookmarkExpandableGridView.BookmarkContextMenuInfo;
22
23import android.app.Activity;
24import android.app.Fragment;
25import android.app.LoaderManager;
26import android.content.ClipData;
27import android.content.ClipboardManager;
28import android.content.ContentUris;
29import android.content.Context;
30import android.content.CursorLoader;
31import android.content.Intent;
32import android.content.Loader;
33import android.content.SharedPreferences;
34import android.content.SharedPreferences.Editor;
35import android.content.res.Configuration;
36import android.content.res.Resources;
37import android.database.Cursor;
38import android.graphics.Bitmap;
39import android.graphics.BitmapFactory;
40import android.net.Uri;
41import android.os.AsyncTask;
42import android.os.Bundle;
43import android.preference.PreferenceManager;
44import android.provider.BrowserContract;
45import android.provider.BrowserContract.Accounts;
46import android.provider.BrowserContract.ChromeSyncColumns;
47import android.view.ContextMenu;
48import android.view.ContextMenu.ContextMenuInfo;
49import android.view.LayoutInflater;
50import android.view.Menu;
51import android.view.MenuInflater;
52import android.view.MenuItem;
53import android.view.View;
54import android.view.ViewGroup;
55import android.webkit.WebIconDatabase.IconListener;
56import android.widget.ExpandableListView;
57import android.widget.ExpandableListView.OnChildClickListener;
58import android.widget.ListView;
59import android.widget.PopupMenu.OnMenuItemClickListener;
60import android.widget.Toast;
61
62import java.util.HashMap;
63
64interface BookmarksPageCallbacks {
65    // Return true if handled
66    boolean onBookmarkSelected(Cursor c, boolean isFolder);
67    // Return true if handled
68    boolean onOpenInNewWindow(Cursor c);
69}
70
71/**
72 *  View showing the user's bookmarks in the browser.
73 */
74public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener,
75        LoaderManager.LoaderCallbacks<Cursor>, IconListener,
76        BreadCrumbView.Controller, OnMenuItemClickListener, OnChildClickListener {
77
78    static final String LOGTAG = "browser";
79
80    static final int LOADER_ACCOUNTS = 1;
81    static final int LOADER_BOOKMARKS = 100;
82
83    static final String EXTRA_DISABLE_WINDOW = "disable_new_window";
84
85    static final String ACCOUNT_TYPE = "account_type";
86    static final String ACCOUNT_NAME = "account_name";
87
88    static final int VIEW_THUMBNAILS = 1;
89    static final int VIEW_LIST = 2;
90    static final String PREF_SELECTED_VIEW = "bookmarks_view";
91
92    BookmarksPageCallbacks mCallbacks;
93    View mRoot;
94    BookmarkExpandableGridView mGrid;
95    ListView mList;
96    boolean mDisableNewWindow;
97    boolean mEnableContextMenu = true;
98    View mEmptyView;
99    int mCurrentView;
100    View mHeader;
101    HashMap<Integer, BrowserBookmarksAdapter> mBookmarkAdapters = new HashMap<Integer, BrowserBookmarksAdapter>();
102    BookmarkDragHandler mDragHandler;
103
104    static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb,
105            Bundle args, ViewGroup headerContainer) {
106        BrowserBookmarksPage bbp = new BrowserBookmarksPage();
107        bbp.mCallbacks = cb;
108        bbp.setArguments(args);
109        return bbp;
110    }
111
112    @Override
113    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
114        if (id == LOADER_ACCOUNTS) {
115            return new AccountsLoader(getActivity());
116        } else if (id >= LOADER_BOOKMARKS) {
117            String accountType = args.getString(ACCOUNT_TYPE);
118            String accountName = args.getString(ACCOUNT_NAME);
119            BookmarksLoader bl = new BookmarksLoader(getActivity(),
120                    accountType, accountName);
121            return bl;
122        } else {
123            throw new UnsupportedOperationException("Unknown loader id " + id);
124        }
125    }
126
127    @Override
128    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
129        if (loader.getId() == LOADER_ACCOUNTS) {
130            LoaderManager lm = getLoaderManager();
131            int id = LOADER_BOOKMARKS;
132            while (cursor.moveToNext()) {
133                String accountName = cursor.getString(0);
134                String accountType = cursor.getString(1);
135                Bundle args = new Bundle();
136                args.putString(ACCOUNT_NAME, accountName);
137                args.putString(ACCOUNT_TYPE, accountType);
138                BrowserBookmarksAdapter adapter = new BrowserBookmarksAdapter(
139                        getActivity(), mCurrentView);
140                mBookmarkAdapters.put(id, adapter);
141                mGrid.addAccount(accountName, adapter);
142                lm.restartLoader(id, args, this);
143                id++;
144            }
145            // TODO: Figure out what a reload of these means
146            // Currently, a reload is triggered whenever bookmarks change
147            // This is less than ideal
148            // It also causes UI flickering as a new adapter is created
149            // instead of re-using an existing one when the account_name is the
150            // same.
151            // For now, this is a one-shot load
152            getLoaderManager().destroyLoader(LOADER_ACCOUNTS);
153        } else if (loader.getId() >= LOADER_BOOKMARKS) {
154            BrowserBookmarksAdapter adapter = mBookmarkAdapters.get(loader.getId());
155            adapter.changeCursor(cursor);
156        }
157    }
158
159    @Override
160    public void onLoaderReset(Loader<Cursor> loader) {
161        // TODO: Figure out what to do here (if anything?)
162    }
163
164    long getFolderId() {
165        LoaderManager manager = getLoaderManager();
166        BookmarksLoader loader =
167                (BookmarksLoader) ((Loader<?>)manager.getLoader(LOADER_BOOKMARKS));
168
169        Uri uri = loader.getUri();
170        if (uri != null) {
171            try {
172                return ContentUris.parseId(uri);
173            } catch (NumberFormatException nfx) {
174                return -1;
175            }
176        }
177        return -1;
178    }
179
180    @Override
181    public boolean onContextItemSelected(MenuItem item) {
182        final Activity activity = getActivity();
183        BookmarkContextMenuInfo i = (BookmarkContextMenuInfo)item.getMenuInfo();
184        // If we have no menu info, we can't tell which item was selected.
185        if (i == null) {
186            return false;
187        }
188        BrowserBookmarksAdapter adapter = getChildAdapter(i.groupPosition);
189
190        switch (item.getItemId()) {
191        case R.id.open_context_menu_id:
192            loadUrl(adapter, i.childPosition);
193            break;
194        case R.id.edit_context_menu_id:
195            editBookmark(adapter, i.childPosition);
196            break;
197        case R.id.shortcut_context_menu_id:
198            Cursor c = adapter.getItem(i.childPosition);
199            activity.sendBroadcast(createShortcutIntent(getActivity(), c));
200            break;
201        case R.id.delete_context_menu_id:
202            displayRemoveBookmarkDialog(adapter, i.childPosition);
203            break;
204        case R.id.new_window_context_menu_id:
205            openInNewWindow(adapter, i.childPosition);
206            break;
207        case R.id.share_link_context_menu_id: {
208            Cursor cursor = adapter.getItem(i.childPosition);
209            Controller.sharePage(activity,
210                    cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE),
211                    cursor.getString(BookmarksLoader.COLUMN_INDEX_URL),
212                    getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON),
213                    getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL));
214            break;
215        }
216        case R.id.copy_url_context_menu_id:
217            copy(getUrl(adapter, i.childPosition));
218            break;
219        case R.id.homepage_context_menu_id: {
220            BrowserSettings.getInstance().setHomePage(getUrl(adapter, i.childPosition));
221            Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
222            break;
223        }
224        // Only for the Most visited page
225        case R.id.save_to_bookmarks_menu_id: {
226            Cursor cursor = adapter.getItem(i.childPosition);
227            String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
228            String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
229            // If the site is bookmarked, the item becomes remove from
230            // bookmarks.
231            Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name);
232            break;
233        }
234        default:
235            return super.onContextItemSelected(item);
236        }
237        return true;
238    }
239
240    static Bitmap getBitmap(Cursor cursor, int columnIndex) {
241        byte[] data = cursor.getBlob(columnIndex);
242        if (data == null) {
243            return null;
244        }
245        return BitmapFactory.decodeByteArray(data, 0, data.length);
246    }
247
248    private MenuItem.OnMenuItemClickListener mContextItemClickListener =
249            new MenuItem.OnMenuItemClickListener() {
250        @Override
251        public boolean onMenuItemClick(MenuItem item) {
252            return onContextItemSelected(item);
253        }
254    };
255
256    @Override
257    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
258        inflater.inflate(R.menu.bookmark, menu);
259        if (!BrowserActivity.isTablet(getActivity())) {
260            MenuItem item = menu.findItem(R.id.add_bookmark);
261            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
262        }
263    }
264
265    @Override
266    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
267        BookmarkContextMenuInfo info = (BookmarkContextMenuInfo) menuInfo;
268        BrowserBookmarksAdapter adapter = getChildAdapter(info.groupPosition);
269        Cursor cursor = adapter.getItem(info.childPosition);
270        if (!canEdit(cursor)) {
271            return;
272        }
273        boolean isFolder
274                = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
275
276        final Activity activity = getActivity();
277        MenuInflater inflater = activity.getMenuInflater();
278        inflater.inflate(R.menu.bookmarkscontext, menu);
279        if (isFolder) {
280            menu.setGroupVisible(R.id.FOLDER_CONTEXT_MENU, true);
281        } else {
282            menu.setGroupVisible(R.id.BOOKMARK_CONTEXT_MENU, true);
283            if (mDisableNewWindow) {
284                menu.findItem(R.id.new_window_context_menu_id).setVisible(false);
285            }
286        }
287        BookmarkItem header = new BookmarkItem(activity);
288        populateBookmarkItem(cursor, header, isFolder);
289        menu.setHeaderView(header);
290
291        int count = menu.size();
292        for (int i = 0; i < count; i++) {
293            menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener);
294        }
295    }
296
297    boolean canEdit(Cursor c) {
298        String unique = c.getString(BookmarksLoader.COLUMN_INDEX_SERVER_UNIQUE);
299        return !ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS.equals(unique);
300    }
301
302    private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) {
303        item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
304        if (isFolder) {
305            item.setUrl(null);
306            Bitmap bitmap =
307                BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder_holo_dark);
308            item.setFavicon(bitmap);
309            new LookupBookmarkCount(getActivity(), item)
310                    .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
311        } else {
312            String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
313            item.setUrl(url);
314            Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
315            if (bitmap == null) {
316                bitmap = CombinedBookmarkHistoryView.getIconListenerSet().getFavicon(url);
317            }
318            item.setFavicon(bitmap);
319        }
320    }
321
322    /**
323     *  Create a new BrowserBookmarksPage.
324     */
325    @Override
326    public void onCreate(Bundle icicle) {
327        super.onCreate(icicle);
328        SharedPreferences prefs = PreferenceManager
329            .getDefaultSharedPreferences(getActivity());
330        mCurrentView = prefs.getInt(PREF_SELECTED_VIEW, getDefaultView());
331        // TODO: Support list view
332        mCurrentView = VIEW_THUMBNAILS;
333
334        Bundle args = getArguments();
335        mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
336
337        setHasOptionsMenu(true);
338    }
339
340    @Override
341    public View onCreateView(LayoutInflater inflater, ViewGroup container,
342            Bundle savedInstanceState) {
343        mRoot = inflater.inflate(R.layout.bookmarks, container, false);
344        mEmptyView = mRoot.findViewById(android.R.id.empty);
345
346        mGrid = (BookmarkExpandableGridView) mRoot.findViewById(R.id.grid);
347        mGrid.setOnChildClickListener(this);
348        mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
349        mGrid.setBreadcrumbController(this);
350        mList = (ListView) mRoot.findViewById(R.id.list);
351        // TODO: mList.setOnItemClickListener(this);
352        setEnableContextMenu(mEnableContextMenu);
353        mDragHandler = new BookmarkDragHandler(getActivity(), mDragController,
354                mGrid.getDragAdapter());
355
356        // Start the loaders
357        LoaderManager lm = getLoaderManager();
358        lm.restartLoader(LOADER_ACCOUNTS, null, this);
359
360        // Add our own listener in case there are favicons that have yet to be loaded.
361        CombinedBookmarkHistoryView.getIconListenerSet().addListener(this);
362
363        return mRoot;
364    }
365
366     private int getDefaultView() {
367        if (BrowserActivity.isTablet(getActivity())) {
368            return VIEW_THUMBNAILS;
369        }
370        return VIEW_LIST;
371    }
372
373    @Override
374    public void onDestroyView() {
375        super.onDestroyView();
376        mGrid.setBreadcrumbController(null);
377        LoaderManager lm = getLoaderManager();
378        lm.destroyLoader(LOADER_ACCOUNTS);
379        for (int id : mBookmarkAdapters.keySet()) {
380            lm.destroyLoader(id);
381        }
382        mBookmarkAdapters.clear();
383
384        CombinedBookmarkHistoryView.getIconListenerSet().removeListener(this);
385    }
386
387    @Override
388    public void onReceivedIcon(String url, Bitmap icon) {
389        // A new favicon has been loaded, so let anything attached to the adapter know about it
390        // so new icons will be loaded.
391        // TODO: Notify all of data set changed
392        // TODO: Wait, is this even needed? Won't this trigger a DB change anyway?
393    }
394
395    private BrowserBookmarksAdapter getChildAdapter(int groupPosition) {
396        if (mCurrentView == VIEW_THUMBNAILS) {
397            return mGrid.getChildAdapter(groupPosition);
398        } else {
399            // TODO: Support expandable list
400            return null;
401        }
402    }
403
404    private BreadCrumbView getBreadCrumbs(int groupPosition) {
405        if (mCurrentView == VIEW_THUMBNAILS) {
406            return mGrid.getBreadCrumbs(groupPosition);
407        } else {
408            // TODO: Support expandable list
409            return null;
410        }
411    }
412
413    @Override
414    public boolean onChildClick(ExpandableListView parent, View v,
415            int groupPosition, int childPosition, long id) {
416        BrowserBookmarksAdapter adapter = getChildAdapter(groupPosition);
417        Cursor cursor = adapter.getItem(childPosition);
418        boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
419        if (mCallbacks != null &&
420                mCallbacks.onBookmarkSelected(cursor, isFolder)) {
421            return true;
422        }
423
424        // TODO: Folder stuff
425        if (isFolder) {
426            String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
427            Uri uri = ContentUris.withAppendedId(
428                    BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
429            BreadCrumbView crumbs = getBreadCrumbs(groupPosition);
430            if (crumbs != null) {
431                // update crumbs
432                crumbs.pushView(title, uri);
433            }
434            loadFolder(groupPosition, uri);
435        }
436        return true;
437    }
438
439    /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
440        String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
441        String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
442        Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
443        Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
444        return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
445    }
446
447    private void loadUrl(BrowserBookmarksAdapter adapter, int position) {
448        if (mCallbacks != null && adapter != null) {
449            mCallbacks.onBookmarkSelected(adapter.getItem(position), false);
450        }
451    }
452
453    private void openInNewWindow(BrowserBookmarksAdapter adapter, int position) {
454        if (mCallbacks != null) {
455            Cursor c = adapter.getItem(position);
456            boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
457            if (isFolder) {
458                long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
459                new OpenAllInTabsTask(id).execute();
460            } else {
461                mCallbacks.onOpenInNewWindow(c);
462            }
463        }
464    }
465
466    class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> {
467        long mFolderId;
468        public OpenAllInTabsTask(long id) {
469            mFolderId = id;
470        }
471
472        @Override
473        protected Cursor doInBackground(Void... params) {
474            Context c = getActivity();
475            if (c == null) return null;
476            return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c),
477                    BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?",
478                    new String[] { Long.toString(mFolderId) }, null);
479        }
480
481        @Override
482        protected void onPostExecute(Cursor result) {
483            if (mCallbacks != null) {
484                while (result.moveToNext()) {
485                    mCallbacks.onOpenInNewWindow(result);
486                }
487            }
488        }
489
490    }
491
492    private void editBookmark(BrowserBookmarksAdapter adapter, int position) {
493        Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
494        Cursor cursor = adapter.getItem(position);
495        Bundle item = new Bundle();
496        item.putString(BrowserContract.Bookmarks.TITLE,
497                cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
498        item.putString(BrowserContract.Bookmarks.URL,
499                cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
500        byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
501        if (data != null) {
502            item.putParcelable(BrowserContract.Bookmarks.FAVICON,
503                    BitmapFactory.decodeByteArray(data, 0, data.length));
504        }
505        item.putLong(BrowserContract.Bookmarks._ID,
506                cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
507        item.putLong(BrowserContract.Bookmarks.PARENT,
508                cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
509        intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item);
510        intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER,
511                cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1);
512        startActivity(intent);
513    }
514
515    private void displayRemoveBookmarkDialog(BrowserBookmarksAdapter adapter,
516            int position) {
517        // Put up a dialog asking if the user really wants to
518        // delete the bookmark
519        Cursor cursor = adapter.getItem(position);
520        long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
521        String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
522        Context context = getActivity();
523        BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null);
524    }
525
526    private String getUrl(BrowserBookmarksAdapter adapter, int position) {
527        return getUrl(adapter.getItem(position));
528    }
529
530    /* package */ static String getUrl(Cursor c) {
531        return c.getString(BookmarksLoader.COLUMN_INDEX_URL);
532    }
533
534    private void copy(CharSequence text) {
535        ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
536                Context.CLIPBOARD_SERVICE);
537        cm.setPrimaryClip(ClipData.newRawUri(null, Uri.parse(text.toString())));
538    }
539
540    @Override
541    public boolean onOptionsItemSelected(MenuItem item) {
542        switch (item.getItemId()) {
543        case R.id.thumbnail_view:
544            selectView(VIEW_THUMBNAILS);
545            return true;
546        case R.id.list_view:
547            selectView(VIEW_LIST);
548            return true;
549        }
550        return super.onOptionsItemSelected(item);
551    }
552
553    @Override
554    public void onConfigurationChanged(Configuration newConfig) {
555        super.onConfigurationChanged(newConfig);
556        Resources res = getActivity().getResources();
557        int horizontalSpacing = (int) res.getDimension(R.dimen.combo_horizontalSpacing);
558        mGrid.setHorizontalSpacing(horizontalSpacing);
559        mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
560        int paddingLeftRight = (int) res.getDimension(R.dimen.combo_paddingLeftRight);
561        int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop);
562        mRoot.setPadding(paddingLeftRight, paddingTop,
563                paddingLeftRight, 0);
564        getActivity().invalidateOptionsMenu();
565    }
566
567    @Override
568    public void onPrepareOptionsMenu(Menu menu) {
569        super.onPrepareOptionsMenu(menu);
570        menu.findItem(R.id.list_view).setVisible(mCurrentView != VIEW_LIST);
571        menu.findItem(R.id.thumbnail_view).setVisible(mCurrentView != VIEW_THUMBNAILS);
572    }
573
574    void selectView(int view) {
575        // TODO: Support list view
576        view = mCurrentView;
577        if (view == mCurrentView) {
578            return;
579        }
580        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
581        Editor edit = prefs.edit();
582        edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
583        edit.apply();
584        if (mEmptyView.getVisibility() == View.VISIBLE) {
585            return;
586        }
587        setupBookmarkView();
588    }
589
590    private void setupBookmarkView() {
591        // TODO: Support list view
592//        mAdapter.selectView(mCurrentView);
593//        switch (mCurrentView) {
594//        case VIEW_THUMBNAILS:
595//            mList.setAdapter(null);
596//            SharedPreferences prefs = PreferenceManager
597//                    .getDefaultSharedPreferences(getActivity());
598//            String accountName = prefs.getString(PREF_ACCOUNT_NAME, null);
599//            mGrid.addAccount(accountName, mAdapter);
600//            mGrid.setVisibility(View.VISIBLE);
601//            mList.setVisibility(View.GONE);
602//            break;
603//        case VIEW_LIST:
604//            mGrid.clearAccounts();
605//            if (mList.getAdapter() != mAdapter) {
606//                mList.setAdapter(mAdapter);
607//            }
608//            mGrid.setVisibility(View.GONE);
609//            mList.setVisibility(View.VISIBLE);
610//            break;
611//        }
612    }
613
614    /**
615     * BreadCrumb controller callback
616     */
617    @Override
618    public void onTop(BreadCrumbView view, int level, Object data) {
619        int groupPosition = (Integer) view.getTag(R.id.group_position);
620        Uri uri = (Uri) data;
621        if (uri == null) {
622            // top level
623            uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
624        }
625        loadFolder(groupPosition, uri);
626    }
627
628    /**
629     * @param uri
630     */
631    private void loadFolder(int groupPosition, Uri uri) {
632        LoaderManager manager = getLoaderManager();
633        // This assumes groups are ordered the same as loaders
634        BookmarksLoader loader = (BookmarksLoader) ((Loader<?>)
635                manager.getLoader(LOADER_BOOKMARKS + groupPosition));
636        loader.setUri(uri);
637        loader.forceLoad();
638    }
639
640    @Override
641    public boolean onMenuItemClick(MenuItem item) {
642        switch (item.getItemId()) {
643        case R.id.list_view:
644            selectView(BrowserBookmarksPage.VIEW_LIST);
645            return true;
646        case R.id.thumbnail_view:
647            selectView(BrowserBookmarksPage.VIEW_THUMBNAILS);
648            return true;
649        }
650        return false;
651    }
652
653    public boolean onBackPressed() {
654        return false;
655    }
656
657    public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
658        mCallbacks = callbackListener;
659    }
660
661    public void setEnableContextMenu(boolean enable) {
662        mEnableContextMenu = enable;
663        if (mGrid != null) {
664            if (mEnableContextMenu) {
665                registerForContextMenu(mGrid);
666            } else {
667                unregisterForContextMenu(mGrid);
668                mGrid.setLongClickable(false);
669            }
670        }
671        if (mList != null) {
672            if (mEnableContextMenu) {
673                registerForContextMenu(mList);
674            } else {
675                unregisterForContextMenu(mList);
676                mList.setLongClickable(false);
677            }
678        }
679    }
680
681    private BookmarkDragController mDragController = new BookmarkDragController() {
682
683        @Override
684        public boolean startDrag(Cursor item) {
685            return canEdit(item);
686        }
687    };
688
689    private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
690        Context mContext;
691        BookmarkItem mHeader;
692
693        public LookupBookmarkCount(Context context, BookmarkItem header) {
694            mContext = context;
695            mHeader = header;
696        }
697
698        @Override
699        protected Integer doInBackground(Long... params) {
700            if (params.length != 1) {
701                throw new IllegalArgumentException("Missing folder id!");
702            }
703            Uri uri = BookmarkUtils.getBookmarksUri(mContext);
704            Cursor c = mContext.getContentResolver().query(uri,
705                    null, BrowserContract.Bookmarks.PARENT + "=?",
706                    new String[] {params[0].toString()}, null);
707            return c.getCount();
708        }
709
710        @Override
711        protected void onPostExecute(Integer result) {
712            if (result > 0) {
713                mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount,
714                        result));
715            } else if (result == 0) {
716                mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty));
717            }
718        }
719    }
720
721    static class AccountsLoader extends CursorLoader {
722
723        static String[] ACCOUNTS_PROJECTION = new String[] {
724            Accounts.ACCOUNT_NAME,
725            Accounts.ACCOUNT_TYPE
726        };
727
728        public AccountsLoader(Context context) {
729            super(context, Accounts.CONTENT_URI, ACCOUNTS_PROJECTION, null, null,
730                    Accounts.ACCOUNT_NAME + " ASC");
731        }
732
733    }
734}
735