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