BrowserBookmarksPage.java revision e3063ae6057d572f47515ee47974810cefcc063d
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.BreadCrumbView.Crumb;
20
21import android.app.Activity;
22import android.app.Fragment;
23import android.app.LoaderManager;
24import android.content.ClipData;
25import android.content.ClipboardManager;
26import android.content.ContentUris;
27import android.content.Context;
28import android.content.Intent;
29import android.content.Loader;
30import android.content.SharedPreferences;
31import android.content.SharedPreferences.Editor;
32import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
33import android.content.res.Configuration;
34import android.content.res.Resources;
35import android.database.Cursor;
36import android.graphics.Bitmap;
37import android.graphics.BitmapFactory;
38import android.net.Uri;
39import android.os.AsyncTask;
40import android.os.Bundle;
41import android.preference.PreferenceManager;
42import android.provider.BrowserContract;
43import android.provider.BrowserContract.ChromeSyncColumns;
44import android.view.ContextMenu;
45import android.view.ContextMenu.ContextMenuInfo;
46import android.view.LayoutInflater;
47import android.view.Menu;
48import android.view.MenuInflater;
49import android.view.MenuItem;
50import android.view.View;
51import android.view.ViewGroup;
52import android.webkit.WebIconDatabase.IconListener;
53import android.widget.AdapterView;
54import android.widget.AdapterView.OnItemClickListener;
55import android.widget.GridView;
56import android.widget.ListView;
57import android.widget.PopupMenu.OnMenuItemClickListener;
58import android.widget.Toast;
59
60interface BookmarksPageCallbacks {
61    // Return true if handled
62    boolean onBookmarkSelected(Cursor c, boolean isFolder);
63    // Return true if handled
64    boolean onOpenInNewWindow(Cursor c);
65    void onFolderChanged(int level, Uri uri);
66}
67
68/**
69 *  View showing the user's bookmarks in the browser.
70 */
71public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener,
72        LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, IconListener,
73        BreadCrumbView.Controller, OnMenuItemClickListener, OnSharedPreferenceChangeListener {
74
75    static final String LOGTAG = "browser";
76
77    static final int LOADER_BOOKMARKS = 1;
78
79    static final String EXTRA_DISABLE_WINDOW = "disable_new_window";
80
81    static final String ACCOUNT_NAME_UNSYNCED = "Unsynced";
82
83    public static final String PREF_ACCOUNT_TYPE = "acct_type";
84    public static final String PREF_ACCOUNT_NAME = "acct_name";
85
86    static final int VIEW_THUMBNAILS = 1;
87    static final int VIEW_LIST = 2;
88    static final String PREF_SELECTED_VIEW = "bookmarks_view";
89
90    BookmarksPageCallbacks mCallbacks;
91    View mRoot;
92    GridView mGrid;
93    ListView mList;
94    BrowserBookmarksAdapter mAdapter;
95    boolean mDisableNewWindow;
96    boolean mCanceled = false;
97    boolean mEnableContextMenu = true;
98    boolean mShowRootFolder = false;
99    View mEmptyView;
100    int mCurrentView;
101    View mHeader;
102    ViewGroup mHeaderContainer;
103    BreadCrumbView mCrumbs;
104    int mCrumbVisibility = View.VISIBLE;
105    int mCrumbMaxVisible = -1;
106    boolean mCrumbBackButton = false;
107
108    static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb,
109            Bundle args, ViewGroup headerContainer) {
110        BrowserBookmarksPage bbp = new BrowserBookmarksPage();
111        bbp.mCallbacks = cb;
112        bbp.mHeaderContainer = headerContainer;
113        bbp.setArguments(args);
114        return bbp;
115    }
116
117    @Override
118    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
119        switch (id) {
120            case LOADER_BOOKMARKS: {
121                SharedPreferences prefs = PreferenceManager
122                        .getDefaultSharedPreferences(getActivity());
123                String accountType = prefs.getString(PREF_ACCOUNT_TYPE, null);
124                String accountName = prefs.getString(PREF_ACCOUNT_NAME, null);
125                BookmarksLoader bl = new BookmarksLoader(getActivity(),
126                        accountType, accountName);
127                if (mCrumbs != null) {
128                    Uri uri = (Uri) mCrumbs.getTopData();
129                    if (uri != null) {
130                        bl.setUri(uri);
131                    }
132                }
133                return bl;
134            }
135        }
136        throw new UnsupportedOperationException("Unknown loader id " + id);
137    }
138
139    @Override
140    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
141        switch (loader.getId()) {
142            case LOADER_BOOKMARKS: {
143                // Set the visibility of the empty vs. content views
144                if (cursor == null || cursor.getCount() == 0) {
145                    mEmptyView.setVisibility(View.VISIBLE);
146                    mGrid.setVisibility(View.GONE);
147                    mList.setVisibility(View.GONE);
148                } else {
149                    mEmptyView.setVisibility(View.GONE);
150                    setupBookmarkView();
151                }
152
153                // Give the new data to the adapter
154                mAdapter.changeCursor(cursor);
155                break;
156            }
157        }
158    }
159
160    @Override
161    public void onLoaderReset(Loader<Cursor> loader) {
162        onLoadFinished(loader, null);
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        // It is possible that the view has been canceled when we get to
185        // this point as back has a higher priority
186        if (mCanceled) {
187            return false;
188        }
189        AdapterView.AdapterContextMenuInfo i =
190            (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
191        // If we have no menu info, we can't tell which item was selected.
192        if (i == null) {
193            return false;
194        }
195
196        switch (item.getItemId()) {
197        case R.id.open_context_menu_id:
198            loadUrl(i.position);
199            break;
200        case R.id.edit_context_menu_id:
201            editBookmark(i.position);
202            break;
203        case R.id.shortcut_context_menu_id:
204            Cursor c = mAdapter.getItem(i.position);
205            activity.sendBroadcast(createShortcutIntent(getActivity(), c));
206            break;
207        case R.id.delete_context_menu_id:
208            displayRemoveBookmarkDialog(i.position);
209            break;
210        case R.id.new_window_context_menu_id:
211            openInNewWindow(i.position);
212            break;
213        case R.id.share_link_context_menu_id: {
214            Cursor cursor = mAdapter.getItem(i.position);
215            Controller.sharePage(activity,
216                    cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE),
217                    cursor.getString(BookmarksLoader.COLUMN_INDEX_URL),
218                    getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON),
219                    getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL));
220            break;
221        }
222        case R.id.copy_url_context_menu_id:
223            copy(getUrl(i.position));
224            break;
225        case R.id.homepage_context_menu_id: {
226            BrowserSettings.getInstance().setHomePage(activity, getUrl(i.position));
227            Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
228            break;
229        }
230        // Only for the Most visited page
231        case R.id.save_to_bookmarks_menu_id: {
232            Cursor cursor = mAdapter.getItem(i.position);
233            String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
234            String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
235            // If the site is bookmarked, the item becomes remove from
236            // bookmarks.
237            Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name);
238            break;
239        }
240        default:
241            return super.onContextItemSelected(item);
242        }
243        return true;
244    }
245
246    static Bitmap getBitmap(Cursor cursor, int columnIndex) {
247        byte[] data = cursor.getBlob(columnIndex);
248        if (data == null) {
249            return null;
250        }
251        return BitmapFactory.decodeByteArray(data, 0, data.length);
252    }
253
254    private MenuItem.OnMenuItemClickListener mContextItemClickListener =
255            new MenuItem.OnMenuItemClickListener() {
256        @Override
257        public boolean onMenuItemClick(MenuItem item) {
258            return onContextItemSelected(item);
259        }
260    };
261
262    @Override
263    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
264        inflater.inflate(R.menu.bookmark, menu);
265    }
266
267    @Override
268    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
269        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
270        Cursor cursor = mAdapter.getItem(info.position);
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
330        setHasOptionsMenu(true);
331
332        Bundle args = getArguments();
333        mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
334    }
335
336    @Override
337    public View onCreateView(LayoutInflater inflater, ViewGroup container,
338            Bundle savedInstanceState) {
339        Context context = getActivity();
340
341        mRoot = inflater.inflate(R.layout.bookmarks, container, false);
342        mEmptyView = mRoot.findViewById(android.R.id.empty);
343
344        mGrid = (GridView) mRoot.findViewById(R.id.grid);
345        mGrid.setOnItemClickListener(this);
346        mGrid.setColumnWidth(Controller.getDesiredThumbnailWidth(getActivity()));
347        mList = (ListView) mRoot.findViewById(R.id.list);
348        mList.setOnItemClickListener(this);
349        setEnableContextMenu(mEnableContextMenu);
350
351        // Prep the header
352        ViewGroup hc = mHeaderContainer;
353        if (hc == null) {
354            hc = (ViewGroup) mRoot.findViewById(R.id.header_container);
355            hc.setVisibility(View.VISIBLE);
356        }
357        mHeader = inflater.inflate(R.layout.bookmarks_header, hc, false);
358        hc.addView(mHeader);
359        mCrumbs = (BreadCrumbView) mHeader.findViewById(R.id.crumbs);
360        mCrumbs.setController(this);
361        mCrumbs.setUseBackButton(mCrumbBackButton);
362        mCrumbs.setMaxVisible(mCrumbMaxVisible);
363        mCrumbs.setVisibility(mCrumbVisibility);
364        String name = getString(R.string.bookmarks);
365        mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
366        if (mCallbacks != null) {
367            mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
368        }
369        // Start the loaders
370        LoaderManager lm = getLoaderManager();
371        SharedPreferences prefs = PreferenceManager
372                .getDefaultSharedPreferences(getActivity());
373        prefs.registerOnSharedPreferenceChangeListener(this);
374        mCurrentView =
375            prefs.getInt(PREF_SELECTED_VIEW, BrowserBookmarksPage.VIEW_THUMBNAILS);
376        mAdapter = new BrowserBookmarksAdapter(getActivity(), mCurrentView);
377        lm.restartLoader(LOADER_BOOKMARKS, null, this);
378
379        // Add our own listener in case there are favicons that have yet to be loaded.
380        CombinedBookmarkHistoryView.getIconListenerSet().addListener(this);
381
382        return mRoot;
383    }
384
385    @Override
386    public void onDestroyView() {
387        super.onDestroyView();
388        SharedPreferences prefs = PreferenceManager
389                .getDefaultSharedPreferences(getActivity());
390        prefs.unregisterOnSharedPreferenceChangeListener(this);
391        if (mHeaderContainer != null) {
392            mHeaderContainer.removeView(mHeader);
393        }
394        mCrumbs.setController(null);
395        mCrumbs = null;
396        getLoaderManager().destroyLoader(LOADER_BOOKMARKS);
397        mAdapter = null;
398        CombinedBookmarkHistoryView.getIconListenerSet().removeListener(this);
399    }
400
401    @Override
402    public void onReceivedIcon(String url, Bitmap icon) {
403        // A new favicon has been loaded, so let anything attached to the adapter know about it
404        // so new icons will be loaded.
405        mAdapter.notifyDataSetChanged();
406    }
407
408    @Override
409    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
410        // It is possible that the view has been canceled when we get to
411        // this point as back has a higher priority
412        if (mCanceled) {
413            android.util.Log.e(LOGTAG, "item clicked when dismissing");
414            return;
415        }
416
417        Cursor cursor = mAdapter.getItem(position);
418        boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
419        if (mCallbacks != null &&
420                mCallbacks.onBookmarkSelected(cursor, isFolder)) {
421            return;
422        }
423
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            if (mCrumbs != null) {
429                // update crumbs
430                mCrumbs.pushView(title, uri);
431            }
432            loadFolder(uri);
433        }
434    }
435
436    /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
437        String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
438        String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
439        Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
440        Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
441        return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
442    }
443
444    private void loadUrl(int position) {
445        if (mCallbacks != null) {
446            mCallbacks.onBookmarkSelected(mAdapter.getItem(position), false);
447        }
448    }
449
450    private void openInNewWindow(int position) {
451        if (mCallbacks != null) {
452            Cursor c = mAdapter.getItem(position);
453            boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
454            if (isFolder) {
455                long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
456                new OpenAllInTabsTask(id).execute();
457            } else {
458                mCallbacks.onOpenInNewWindow(c);
459            }
460        }
461    }
462
463    class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> {
464        long mFolderId;
465        public OpenAllInTabsTask(long id) {
466            mFolderId = id;
467        }
468
469        @Override
470        protected Cursor doInBackground(Void... params) {
471            Context c = getActivity();
472            if (c == null) return null;
473            return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c),
474                    BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?",
475                    new String[] { Long.toString(mFolderId) }, null);
476        }
477
478        @Override
479        protected void onPostExecute(Cursor result) {
480            if (mCallbacks != null) {
481                while (result.moveToNext()) {
482                    mCallbacks.onOpenInNewWindow(result);
483                }
484            }
485        }
486
487    }
488
489    private void editBookmark(int position) {
490        Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
491        Cursor cursor = mAdapter.getItem(position);
492        Bundle item = new Bundle();
493        item.putString(BrowserContract.Bookmarks.TITLE,
494                cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
495        item.putString(BrowserContract.Bookmarks.URL,
496                cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
497        byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
498        if (data != null) {
499            item.putParcelable(BrowserContract.Bookmarks.FAVICON,
500                    BitmapFactory.decodeByteArray(data, 0, data.length));
501        }
502        item.putLong(BrowserContract.Bookmarks._ID,
503                cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
504        item.putLong(BrowserContract.Bookmarks.PARENT,
505                cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
506        intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item);
507        intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER,
508                cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1);
509        startActivity(intent);
510    }
511
512    private void displayRemoveBookmarkDialog(final int position) {
513        // Put up a dialog asking if the user really wants to
514        // delete the bookmark
515        Cursor cursor = mAdapter.getItem(position);
516        long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
517        String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
518        Context context = getActivity();
519        BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null);
520    }
521
522    private String getUrl(int position) {
523        return getUrl(mAdapter.getItem(position));
524    }
525
526    /* package */ static String getUrl(Cursor c) {
527        return c.getString(BookmarksLoader.COLUMN_INDEX_URL);
528    }
529
530    private void copy(CharSequence text) {
531        ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
532                Context.CLIPBOARD_SERVICE);
533        cm.setPrimaryClip(ClipData.newRawUri(null, Uri.parse(text.toString())));
534    }
535
536    @Override
537    public boolean onOptionsItemSelected(MenuItem item) {
538        switch (item.getItemId()) {
539        case R.id.thumbnail_view:
540            selectView(VIEW_THUMBNAILS);
541            return true;
542        case R.id.list_view:
543            selectView(VIEW_LIST);
544            return true;
545        }
546        return super.onOptionsItemSelected(item);
547    }
548
549    @Override
550    public void onConfigurationChanged(Configuration newConfig) {
551        super.onConfigurationChanged(newConfig);
552        Resources res = getActivity().getResources();
553        int horizontalSpacing = (int) res.getDimension(R.dimen.combo_horizontalSpacing);
554        mGrid.setHorizontalSpacing(horizontalSpacing);
555        int paddingLeftRight = (int) res.getDimension(R.dimen.combo_paddingLeftRight);
556        int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop);
557        mRoot.setPadding(paddingLeftRight, paddingTop,
558                paddingLeftRight, 0);
559    }
560
561    @Override
562    public void onPrepareOptionsMenu(Menu menu) {
563        super.onPrepareOptionsMenu(menu);
564        menu.findItem(R.id.list_view).setVisible(mCurrentView != VIEW_LIST);
565        menu.findItem(R.id.thumbnail_view).setVisible(mCurrentView != VIEW_THUMBNAILS);
566    }
567
568    void selectView(int view) {
569        if (view == mCurrentView) {
570            return;
571        }
572        mCurrentView = view;
573        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
574        Editor edit = prefs.edit();
575        edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
576        edit.apply();
577        if (mEmptyView.getVisibility() == View.VISIBLE) {
578            return;
579        }
580        setupBookmarkView();
581    }
582
583    private void setupBookmarkView() {
584        mAdapter.selectView(mCurrentView);
585        switch (mCurrentView) {
586        case VIEW_THUMBNAILS:
587            mList.setAdapter(null);
588            mGrid.setAdapter(mAdapter);
589            mGrid.setVisibility(View.VISIBLE);
590            mList.setVisibility(View.GONE);
591            break;
592        case VIEW_LIST:
593            mGrid.setAdapter(null);
594            mList.setAdapter(mAdapter);
595            mGrid.setVisibility(View.GONE);
596            mList.setVisibility(View.VISIBLE);
597            break;
598        }
599    }
600
601    /**
602     * BreadCrumb controller callback
603     */
604    @Override
605    public void onTop(int level, Object data) {
606        Uri uri = (Uri) data;
607        if (uri == null) {
608            // top level
609            uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
610        }
611        loadFolder(uri);
612    }
613
614    /**
615     * @param uri
616     */
617    private void loadFolder(Uri uri) {
618        LoaderManager manager = getLoaderManager();
619        BookmarksLoader loader =
620                (BookmarksLoader) ((Loader<?>) manager.getLoader(LOADER_BOOKMARKS));
621        loader.setUri(uri);
622        loader.forceLoad();
623        if (mCallbacks != null) {
624            mCallbacks.onFolderChanged(mCrumbs.getTopLevel(), uri);
625        }
626    }
627
628    @Override
629    public boolean onMenuItemClick(MenuItem item) {
630        switch (item.getItemId()) {
631        case R.id.list_view:
632            selectView(BrowserBookmarksPage.VIEW_LIST);
633            return true;
634        case R.id.thumbnail_view:
635            selectView(BrowserBookmarksPage.VIEW_THUMBNAILS);
636            return true;
637        }
638        return false;
639    }
640
641    public boolean onBackPressed() {
642        if (canGoBack()) {
643            mCrumbs.popView();
644            return true;
645        }
646        return false;
647    }
648
649    private boolean canGoBack() {
650        Crumb c = mCrumbs.getTopCrumb();
651        return c != null && c.canGoBack;
652    }
653
654    public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
655        mCallbacks = callbackListener;
656    }
657
658    public void setEnableContextMenu(boolean enable) {
659        mEnableContextMenu = enable;
660        if (mGrid != null) {
661            if (mEnableContextMenu) {
662                registerForContextMenu(mGrid);
663            } else {
664                unregisterForContextMenu(mGrid);
665                mGrid.setLongClickable(false);
666            }
667        }
668        if (mList != null) {
669            if (mEnableContextMenu) {
670                registerForContextMenu(mList);
671            } else {
672                unregisterForContextMenu(mList);
673                mList.setLongClickable(false);
674            }
675        }
676    }
677
678    private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
679        Context mContext;
680        BookmarkItem mHeader;
681
682        public LookupBookmarkCount(Context context, BookmarkItem header) {
683            mContext = context;
684            mHeader = header;
685        }
686
687        @Override
688        protected Integer doInBackground(Long... params) {
689            if (params.length != 1) {
690                throw new IllegalArgumentException("Missing folder id!");
691            }
692            Uri uri = BookmarkUtils.getBookmarksUri(mContext);
693            Cursor c = mContext.getContentResolver().query(uri,
694                    null, BrowserContract.Bookmarks.PARENT + "=?",
695                    new String[] {params[0].toString()}, null);
696            return c.getCount();
697        }
698
699        @Override
700        protected void onPostExecute(Integer result) {
701            if (result > 0) {
702                mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount,
703                        result));
704            } else if (result == 0) {
705                mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty));
706            }
707        }
708    }
709
710    public void setBreadCrumbVisibility(int visibility) {
711        mCrumbVisibility = visibility;
712        if (mCrumbs != null) {
713            mCrumbs.setVisibility(mCrumbVisibility);
714        }
715    }
716
717    public void setBreadCrumbUseBackButton(boolean use) {
718        mCrumbBackButton = use;
719        if (mCrumbs != null) {
720            mCrumbs.setUseBackButton(mCrumbBackButton);
721        }
722    }
723
724    public void setBreadCrumbMaxVisible(int max) {
725        mCrumbMaxVisible = max;
726        if (mCrumbs != null) {
727            mCrumbs.setMaxVisible(mCrumbMaxVisible);
728        }
729    }
730
731    @Override
732    public void onSharedPreferenceChanged(
733            SharedPreferences sharedPreferences, String key) {
734        if (PREF_ACCOUNT_NAME.equals(key) || PREF_ACCOUNT_TYPE.equals(key)) {
735            mCrumbs.setController(null);
736            mCrumbs.clear();
737            LoaderManager lm = getLoaderManager();
738            lm.restartLoader(LOADER_BOOKMARKS, null, this);
739            mCrumbs.setController(this);
740            String name = getString(R.string.bookmarks);
741            mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
742            if (mCallbacks != null) {
743                mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
744            }
745        }
746    }
747}
748