BrowserBookmarksPage.java revision 522a438d69486914a364c2fe0934c08269b1129f
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    }
398
399    @Override
400    public void onReceivedIcon(String url, Bitmap icon) {
401        // A new favicon has been loaded, so let anything attached to the adapter know about it
402        // so new icons will be loaded.
403        mAdapter.notifyDataSetChanged();
404    }
405
406    @Override
407    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
408        // It is possible that the view has been canceled when we get to
409        // this point as back has a higher priority
410        if (mCanceled) {
411            android.util.Log.e(LOGTAG, "item clicked when dismissing");
412            return;
413        }
414
415        Cursor cursor = mAdapter.getItem(position);
416        boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
417        if (mCallbacks != null &&
418                mCallbacks.onBookmarkSelected(cursor, isFolder)) {
419            return;
420        }
421
422        if (isFolder) {
423            String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
424            Uri uri = ContentUris.withAppendedId(
425                    BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
426            if (mCrumbs != null) {
427                // update crumbs
428                mCrumbs.pushView(title, uri);
429            }
430            loadFolder(uri);
431        }
432    }
433
434    /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
435        String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
436        String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
437        Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
438        Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
439        return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
440    }
441
442    private void loadUrl(int position) {
443        if (mCallbacks != null) {
444            mCallbacks.onBookmarkSelected(mAdapter.getItem(position), false);
445        }
446    }
447
448    private void openInNewWindow(int position) {
449        if (mCallbacks != null) {
450            Cursor c = mAdapter.getItem(position);
451            boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
452            if (isFolder) {
453                long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
454                new OpenAllInTabsTask(id).execute();
455            } else {
456                mCallbacks.onOpenInNewWindow(c);
457            }
458        }
459    }
460
461    class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> {
462        long mFolderId;
463        public OpenAllInTabsTask(long id) {
464            mFolderId = id;
465        }
466
467        @Override
468        protected Cursor doInBackground(Void... params) {
469            Context c = getActivity();
470            if (c == null) return null;
471            return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c),
472                    BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?",
473                    new String[] { Long.toString(mFolderId) }, null);
474        }
475
476        @Override
477        protected void onPostExecute(Cursor result) {
478            if (mCallbacks != null) {
479                while (result.moveToNext()) {
480                    mCallbacks.onOpenInNewWindow(result);
481                }
482            }
483        }
484
485    }
486
487    private void editBookmark(int position) {
488        Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
489        Cursor cursor = mAdapter.getItem(position);
490        Bundle item = new Bundle();
491        item.putString(BrowserContract.Bookmarks.TITLE,
492                cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
493        item.putString(BrowserContract.Bookmarks.URL,
494                cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
495        byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
496        if (data != null) {
497            item.putParcelable(BrowserContract.Bookmarks.FAVICON,
498                    BitmapFactory.decodeByteArray(data, 0, data.length));
499        }
500        item.putLong(BrowserContract.Bookmarks._ID,
501                cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
502        item.putLong(BrowserContract.Bookmarks.PARENT,
503                cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
504        intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item);
505        intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER,
506                cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1);
507        startActivity(intent);
508    }
509
510    private void displayRemoveBookmarkDialog(final int position) {
511        // Put up a dialog asking if the user really wants to
512        // delete the bookmark
513        Cursor cursor = mAdapter.getItem(position);
514        long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
515        String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
516        Context context = getActivity();
517        BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null);
518    }
519
520    private String getUrl(int position) {
521        return getUrl(mAdapter.getItem(position));
522    }
523
524    /* package */ static String getUrl(Cursor c) {
525        return c.getString(BookmarksLoader.COLUMN_INDEX_URL);
526    }
527
528    private void copy(CharSequence text) {
529        ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
530                Context.CLIPBOARD_SERVICE);
531        cm.setPrimaryClip(ClipData.newRawUri(null, Uri.parse(text.toString())));
532    }
533
534    @Override
535    public boolean onOptionsItemSelected(MenuItem item) {
536        switch (item.getItemId()) {
537        case R.id.thumbnail_view:
538            selectView(VIEW_THUMBNAILS);
539            return true;
540        case R.id.list_view:
541            selectView(VIEW_LIST);
542            return true;
543        }
544        return super.onOptionsItemSelected(item);
545    }
546
547    @Override
548    public void onConfigurationChanged(Configuration newConfig) {
549        super.onConfigurationChanged(newConfig);
550        Resources res = getActivity().getResources();
551        int horizontalSpacing = (int) res.getDimension(R.dimen.combo_horizontalSpacing);
552        mGrid.setHorizontalSpacing(horizontalSpacing);
553        int paddingLeftRight = (int) res.getDimension(R.dimen.combo_paddingLeftRight);
554        int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop);
555        mRoot.setPadding(paddingLeftRight, paddingTop,
556                paddingLeftRight, 0);
557    }
558
559    @Override
560    public void onPrepareOptionsMenu(Menu menu) {
561        super.onPrepareOptionsMenu(menu);
562        menu.findItem(R.id.list_view).setVisible(mCurrentView != VIEW_LIST);
563        menu.findItem(R.id.thumbnail_view).setVisible(mCurrentView != VIEW_THUMBNAILS);
564    }
565
566    void selectView(int view) {
567        if (view == mCurrentView) {
568            return;
569        }
570        mCurrentView = view;
571        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
572        Editor edit = prefs.edit();
573        edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
574        edit.apply();
575        if (mEmptyView.getVisibility() == View.VISIBLE) {
576            return;
577        }
578        setupBookmarkView();
579    }
580
581    private void setupBookmarkView() {
582        mAdapter.selectView(mCurrentView);
583        switch (mCurrentView) {
584        case VIEW_THUMBNAILS:
585            mList.setAdapter(null);
586            mGrid.setAdapter(mAdapter);
587            mGrid.setVisibility(View.VISIBLE);
588            mList.setVisibility(View.GONE);
589            break;
590        case VIEW_LIST:
591            mGrid.setAdapter(null);
592            mList.setAdapter(mAdapter);
593            mGrid.setVisibility(View.GONE);
594            mList.setVisibility(View.VISIBLE);
595            break;
596        }
597    }
598
599    /**
600     * BreadCrumb controller callback
601     */
602    @Override
603    public void onTop(int level, Object data) {
604        Uri uri = (Uri) data;
605        if (uri == null) {
606            // top level
607            uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
608        }
609        loadFolder(uri);
610    }
611
612    /**
613     * @param uri
614     */
615    private void loadFolder(Uri uri) {
616        LoaderManager manager = getLoaderManager();
617        BookmarksLoader loader =
618                (BookmarksLoader) ((Loader<?>) manager.getLoader(LOADER_BOOKMARKS));
619        loader.setUri(uri);
620        loader.forceLoad();
621        if (mCallbacks != null) {
622            mCallbacks.onFolderChanged(mCrumbs.getTopLevel(), uri);
623        }
624    }
625
626    @Override
627    public boolean onMenuItemClick(MenuItem item) {
628        switch (item.getItemId()) {
629        case R.id.list_view:
630            selectView(BrowserBookmarksPage.VIEW_LIST);
631            return true;
632        case R.id.thumbnail_view:
633            selectView(BrowserBookmarksPage.VIEW_THUMBNAILS);
634            return true;
635        }
636        return false;
637    }
638
639    public boolean onBackPressed() {
640        if (canGoBack()) {
641            mCrumbs.popView();
642            return true;
643        }
644        return false;
645    }
646
647    private boolean canGoBack() {
648        Crumb c = mCrumbs.getTopCrumb();
649        return c != null && c.canGoBack;
650    }
651
652    public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
653        mCallbacks = callbackListener;
654    }
655
656    public void setEnableContextMenu(boolean enable) {
657        mEnableContextMenu = enable;
658        if (mGrid != null) {
659            if (mEnableContextMenu) {
660                registerForContextMenu(mGrid);
661            } else {
662                unregisterForContextMenu(mGrid);
663                mGrid.setLongClickable(false);
664            }
665        }
666        if (mList != null) {
667            if (mEnableContextMenu) {
668                registerForContextMenu(mList);
669            } else {
670                unregisterForContextMenu(mList);
671                mList.setLongClickable(false);
672            }
673        }
674    }
675
676    private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
677        Context mContext;
678        BookmarkItem mHeader;
679
680        public LookupBookmarkCount(Context context, BookmarkItem header) {
681            mContext = context;
682            mHeader = header;
683        }
684
685        @Override
686        protected Integer doInBackground(Long... params) {
687            if (params.length != 1) {
688                throw new IllegalArgumentException("Missing folder id!");
689            }
690            Uri uri = BookmarkUtils.getBookmarksUri(mContext);
691            Cursor c = mContext.getContentResolver().query(uri,
692                    null, BrowserContract.Bookmarks.PARENT + "=?",
693                    new String[] {params[0].toString()}, null);
694            return c.getCount();
695        }
696
697        @Override
698        protected void onPostExecute(Integer result) {
699            if (result > 0) {
700                mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount,
701                        result));
702            } else if (result == 0) {
703                mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty));
704            }
705        }
706    }
707
708    public void setBreadCrumbVisibility(int visibility) {
709        mCrumbVisibility = visibility;
710        if (mCrumbs != null) {
711            mCrumbs.setVisibility(mCrumbVisibility);
712        }
713    }
714
715    public void setBreadCrumbUseBackButton(boolean use) {
716        mCrumbBackButton = use;
717        if (mCrumbs != null) {
718            mCrumbs.setUseBackButton(mCrumbBackButton);
719        }
720    }
721
722    public void setBreadCrumbMaxVisible(int max) {
723        mCrumbMaxVisible = max;
724        if (mCrumbs != null) {
725            mCrumbs.setMaxVisible(mCrumbMaxVisible);
726        }
727    }
728
729    @Override
730    public void onSharedPreferenceChanged(
731            SharedPreferences sharedPreferences, String key) {
732        if (PREF_ACCOUNT_NAME.equals(key) || PREF_ACCOUNT_TYPE.equals(key)) {
733            mCrumbs.setController(null);
734            mCrumbs.clear();
735            LoaderManager lm = getLoaderManager();
736            lm.restartLoader(LOADER_BOOKMARKS, null, this);
737            mCrumbs.setController(this);
738            String name = getString(R.string.bookmarks);
739            mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
740            if (mCallbacks != null) {
741                mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
742            }
743        }
744    }
745}
746