BrowserBookmarksPage.java revision 9fdd981a245b59952338374ba6a264742498fc4c
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        if (!BrowserActivity.isTablet(getActivity())) {
266            MenuItem item = menu.findItem(R.id.add_bookmark);
267            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
268        }
269    }
270
271    @Override
272    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
273        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
274        Cursor cursor = mAdapter.getItem(info.position);
275        if (!canEdit(cursor)) {
276            return;
277        }
278        boolean isFolder
279                = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
280
281        final Activity activity = getActivity();
282        MenuInflater inflater = activity.getMenuInflater();
283        inflater.inflate(R.menu.bookmarkscontext, menu);
284        if (isFolder) {
285            menu.setGroupVisible(R.id.FOLDER_CONTEXT_MENU, true);
286        } else {
287            menu.setGroupVisible(R.id.BOOKMARK_CONTEXT_MENU, true);
288            if (mDisableNewWindow) {
289                menu.findItem(R.id.new_window_context_menu_id).setVisible(false);
290            }
291        }
292        BookmarkItem header = new BookmarkItem(activity);
293        populateBookmarkItem(cursor, header, isFolder);
294        menu.setHeaderView(header);
295
296        int count = menu.size();
297        for (int i = 0; i < count; i++) {
298            menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener);
299        }
300    }
301
302    boolean canEdit(Cursor c) {
303        String unique = c.getString(BookmarksLoader.COLUMN_INDEX_SERVER_UNIQUE);
304        return !ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS.equals(unique);
305    }
306
307    private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) {
308        item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
309        if (isFolder) {
310            item.setUrl(null);
311            Bitmap bitmap =
312                BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder_holo_dark);
313            item.setFavicon(bitmap);
314            new LookupBookmarkCount(getActivity(), item)
315                    .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
316        } else {
317            String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
318            item.setUrl(url);
319            Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
320            if (bitmap == null) {
321                bitmap = CombinedBookmarkHistoryView.getIconListenerSet().getFavicon(url);
322            }
323            item.setFavicon(bitmap);
324        }
325    }
326
327    /**
328     *  Create a new BrowserBookmarksPage.
329     */
330    @Override
331    public void onCreate(Bundle icicle) {
332        super.onCreate(icicle);
333
334        setHasOptionsMenu(true);
335
336        Bundle args = getArguments();
337        mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
338    }
339
340    @Override
341    public View onCreateView(LayoutInflater inflater, ViewGroup container,
342            Bundle savedInstanceState) {
343        Context context = getActivity();
344
345        mRoot = inflater.inflate(R.layout.bookmarks, container, false);
346        mEmptyView = mRoot.findViewById(android.R.id.empty);
347
348        mGrid = (GridView) mRoot.findViewById(R.id.grid);
349        mGrid.setOnItemClickListener(this);
350        mGrid.setColumnWidth(Controller.getDesiredThumbnailWidth(getActivity()));
351        mList = (ListView) mRoot.findViewById(R.id.list);
352        mList.setOnItemClickListener(this);
353        setEnableContextMenu(mEnableContextMenu);
354
355        // Prep the header
356        ViewGroup hc = mHeaderContainer;
357        if (hc == null) {
358            hc = (ViewGroup) mRoot.findViewById(R.id.header_container);
359            hc.setVisibility(View.VISIBLE);
360        }
361        mHeader = inflater.inflate(R.layout.bookmarks_header, hc, false);
362        hc.addView(mHeader);
363        mCrumbs = (BreadCrumbView) mHeader.findViewById(R.id.crumbs);
364        mCrumbs.setController(this);
365        mCrumbs.setUseBackButton(mCrumbBackButton);
366        mCrumbs.setMaxVisible(mCrumbMaxVisible);
367        mCrumbs.setVisibility(mCrumbVisibility);
368        String name = getString(R.string.bookmarks);
369        mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
370        if (mCallbacks != null) {
371            mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
372        }
373        // Start the loaders
374        LoaderManager lm = getLoaderManager();
375        SharedPreferences prefs = PreferenceManager
376                .getDefaultSharedPreferences(getActivity());
377        prefs.registerOnSharedPreferenceChangeListener(this);
378        mCurrentView =
379            prefs.getInt(PREF_SELECTED_VIEW, getDefaultView());
380        mAdapter = new BrowserBookmarksAdapter(getActivity(), mCurrentView);
381        lm.restartLoader(LOADER_BOOKMARKS, null, this);
382
383        // Add our own listener in case there are favicons that have yet to be loaded.
384        CombinedBookmarkHistoryView.getIconListenerSet().addListener(this);
385
386        return mRoot;
387    }
388
389     private int getDefaultView() {
390        if (BrowserActivity.isTablet(getActivity())) {
391            return VIEW_THUMBNAILS;
392        }
393        return VIEW_LIST;
394    }
395
396    @Override
397    public void onDestroyView() {
398        super.onDestroyView();
399        SharedPreferences prefs = PreferenceManager
400                .getDefaultSharedPreferences(getActivity());
401        prefs.unregisterOnSharedPreferenceChangeListener(this);
402        if (mHeaderContainer != null) {
403            mHeaderContainer.removeView(mHeader);
404        }
405        mCrumbs.setController(null);
406        mCrumbs = null;
407        getLoaderManager().destroyLoader(LOADER_BOOKMARKS);
408        mAdapter = null;
409        CombinedBookmarkHistoryView.getIconListenerSet().removeListener(this);
410    }
411
412    @Override
413    public void onReceivedIcon(String url, Bitmap icon) {
414        // A new favicon has been loaded, so let anything attached to the adapter know about it
415        // so new icons will be loaded.
416        mAdapter.notifyDataSetChanged();
417    }
418
419    @Override
420    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
421        // It is possible that the view has been canceled when we get to
422        // this point as back has a higher priority
423        if (mCanceled) {
424            android.util.Log.e(LOGTAG, "item clicked when dismissing");
425            return;
426        }
427
428        Cursor cursor = mAdapter.getItem(position);
429        boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
430        if (mCallbacks != null &&
431                mCallbacks.onBookmarkSelected(cursor, isFolder)) {
432            return;
433        }
434
435        if (isFolder) {
436            String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
437            Uri uri = ContentUris.withAppendedId(
438                    BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
439            if (mCrumbs != null) {
440                // update crumbs
441                mCrumbs.pushView(title, uri);
442            }
443            loadFolder(uri);
444        }
445    }
446
447    /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
448        String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
449        String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
450        Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
451        Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
452        return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
453    }
454
455    private void loadUrl(int position) {
456        if (mCallbacks != null && mAdapter != null) {
457            mCallbacks.onBookmarkSelected(mAdapter.getItem(position), false);
458        }
459    }
460
461    private void openInNewWindow(int position) {
462        if (mCallbacks != null) {
463            Cursor c = mAdapter.getItem(position);
464            boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
465            if (isFolder) {
466                long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
467                new OpenAllInTabsTask(id).execute();
468            } else {
469                mCallbacks.onOpenInNewWindow(c);
470            }
471        }
472    }
473
474    class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> {
475        long mFolderId;
476        public OpenAllInTabsTask(long id) {
477            mFolderId = id;
478        }
479
480        @Override
481        protected Cursor doInBackground(Void... params) {
482            Context c = getActivity();
483            if (c == null) return null;
484            return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c),
485                    BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?",
486                    new String[] { Long.toString(mFolderId) }, null);
487        }
488
489        @Override
490        protected void onPostExecute(Cursor result) {
491            if (mCallbacks != null) {
492                while (result.moveToNext()) {
493                    mCallbacks.onOpenInNewWindow(result);
494                }
495            }
496        }
497
498    }
499
500    private void editBookmark(int position) {
501        Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
502        Cursor cursor = mAdapter.getItem(position);
503        Bundle item = new Bundle();
504        item.putString(BrowserContract.Bookmarks.TITLE,
505                cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
506        item.putString(BrowserContract.Bookmarks.URL,
507                cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
508        byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
509        if (data != null) {
510            item.putParcelable(BrowserContract.Bookmarks.FAVICON,
511                    BitmapFactory.decodeByteArray(data, 0, data.length));
512        }
513        item.putLong(BrowserContract.Bookmarks._ID,
514                cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
515        item.putLong(BrowserContract.Bookmarks.PARENT,
516                cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
517        intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item);
518        intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER,
519                cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1);
520        startActivity(intent);
521    }
522
523    private void displayRemoveBookmarkDialog(final int position) {
524        // Put up a dialog asking if the user really wants to
525        // delete the bookmark
526        Cursor cursor = mAdapter.getItem(position);
527        long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
528        String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
529        Context context = getActivity();
530        BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null);
531    }
532
533    private String getUrl(int position) {
534        return getUrl(mAdapter.getItem(position));
535    }
536
537    /* package */ static String getUrl(Cursor c) {
538        return c.getString(BookmarksLoader.COLUMN_INDEX_URL);
539    }
540
541    private void copy(CharSequence text) {
542        ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
543                Context.CLIPBOARD_SERVICE);
544        cm.setPrimaryClip(ClipData.newRawUri(null, Uri.parse(text.toString())));
545    }
546
547    @Override
548    public boolean onOptionsItemSelected(MenuItem item) {
549        switch (item.getItemId()) {
550        case R.id.thumbnail_view:
551            selectView(VIEW_THUMBNAILS);
552            return true;
553        case R.id.list_view:
554            selectView(VIEW_LIST);
555            return true;
556        }
557        return super.onOptionsItemSelected(item);
558    }
559
560    @Override
561    public void onConfigurationChanged(Configuration newConfig) {
562        super.onConfigurationChanged(newConfig);
563        Resources res = getActivity().getResources();
564        int horizontalSpacing = (int) res.getDimension(R.dimen.combo_horizontalSpacing);
565        mGrid.setHorizontalSpacing(horizontalSpacing);
566        int paddingLeftRight = (int) res.getDimension(R.dimen.combo_paddingLeftRight);
567        int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop);
568        mRoot.setPadding(paddingLeftRight, paddingTop,
569                paddingLeftRight, 0);
570        getActivity().invalidateOptionsMenu();
571    }
572
573    @Override
574    public void onPrepareOptionsMenu(Menu menu) {
575        super.onPrepareOptionsMenu(menu);
576        menu.findItem(R.id.list_view).setVisible(mCurrentView != VIEW_LIST);
577        menu.findItem(R.id.thumbnail_view).setVisible(mCurrentView != VIEW_THUMBNAILS);
578    }
579
580    void selectView(int view) {
581        if (view == mCurrentView) {
582            return;
583        }
584        mCurrentView = view;
585        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
586        Editor edit = prefs.edit();
587        edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
588        edit.apply();
589        if (mEmptyView.getVisibility() == View.VISIBLE) {
590            return;
591        }
592        setupBookmarkView();
593    }
594
595    private void setupBookmarkView() {
596        mAdapter.selectView(mCurrentView);
597        switch (mCurrentView) {
598        case VIEW_THUMBNAILS:
599            mList.setAdapter(null);
600            if (mGrid.getAdapter() != mAdapter) {
601                mGrid.setAdapter(mAdapter);
602            }
603            mGrid.setVisibility(View.VISIBLE);
604            mList.setVisibility(View.GONE);
605            break;
606        case VIEW_LIST:
607            mGrid.setAdapter(null);
608            if (mList.getAdapter() != mAdapter) {
609                mList.setAdapter(mAdapter);
610            }
611            mGrid.setVisibility(View.GONE);
612            mList.setVisibility(View.VISIBLE);
613            break;
614        }
615    }
616
617    /**
618     * BreadCrumb controller callback
619     */
620    @Override
621    public void onTop(int level, Object data) {
622        Uri uri = (Uri) data;
623        if (uri == null) {
624            // top level
625            uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
626        }
627        loadFolder(uri);
628    }
629
630    /**
631     * @param uri
632     */
633    private void loadFolder(Uri uri) {
634        LoaderManager manager = getLoaderManager();
635        BookmarksLoader loader =
636                (BookmarksLoader) ((Loader<?>) manager.getLoader(LOADER_BOOKMARKS));
637        loader.setUri(uri);
638        loader.forceLoad();
639        if (mCallbacks != null) {
640            mCallbacks.onFolderChanged(mCrumbs.getTopLevel(), uri);
641        }
642    }
643
644    @Override
645    public boolean onMenuItemClick(MenuItem item) {
646        switch (item.getItemId()) {
647        case R.id.list_view:
648            selectView(BrowserBookmarksPage.VIEW_LIST);
649            return true;
650        case R.id.thumbnail_view:
651            selectView(BrowserBookmarksPage.VIEW_THUMBNAILS);
652            return true;
653        }
654        return false;
655    }
656
657    public boolean onBackPressed() {
658        if (canGoBack()) {
659            mCrumbs.popView();
660            return true;
661        }
662        return false;
663    }
664
665    private boolean canGoBack() {
666        Crumb c = mCrumbs.getTopCrumb();
667        return c != null && c.canGoBack;
668    }
669
670    public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
671        mCallbacks = callbackListener;
672    }
673
674    public void setEnableContextMenu(boolean enable) {
675        mEnableContextMenu = enable;
676        if (mGrid != null) {
677            if (mEnableContextMenu) {
678                registerForContextMenu(mGrid);
679            } else {
680                unregisterForContextMenu(mGrid);
681                mGrid.setLongClickable(false);
682            }
683        }
684        if (mList != null) {
685            if (mEnableContextMenu) {
686                registerForContextMenu(mList);
687            } else {
688                unregisterForContextMenu(mList);
689                mList.setLongClickable(false);
690            }
691        }
692    }
693
694    private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
695        Context mContext;
696        BookmarkItem mHeader;
697
698        public LookupBookmarkCount(Context context, BookmarkItem header) {
699            mContext = context;
700            mHeader = header;
701        }
702
703        @Override
704        protected Integer doInBackground(Long... params) {
705            if (params.length != 1) {
706                throw new IllegalArgumentException("Missing folder id!");
707            }
708            Uri uri = BookmarkUtils.getBookmarksUri(mContext);
709            Cursor c = mContext.getContentResolver().query(uri,
710                    null, BrowserContract.Bookmarks.PARENT + "=?",
711                    new String[] {params[0].toString()}, null);
712            return c.getCount();
713        }
714
715        @Override
716        protected void onPostExecute(Integer result) {
717            if (result > 0) {
718                mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount,
719                        result));
720            } else if (result == 0) {
721                mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty));
722            }
723        }
724    }
725
726    public void setBreadCrumbVisibility(int visibility) {
727        mCrumbVisibility = visibility;
728        if (mCrumbs != null) {
729            mCrumbs.setVisibility(mCrumbVisibility);
730        }
731    }
732
733    public void setBreadCrumbUseBackButton(boolean use) {
734        mCrumbBackButton = use;
735        if (mCrumbs != null) {
736            mCrumbs.setUseBackButton(mCrumbBackButton);
737        }
738    }
739
740    public void setBreadCrumbMaxVisible(int max) {
741        mCrumbMaxVisible = max;
742        if (mCrumbs != null) {
743            mCrumbs.setMaxVisible(mCrumbMaxVisible);
744        }
745    }
746
747    @Override
748    public void onSharedPreferenceChanged(
749            SharedPreferences sharedPreferences, String key) {
750        if (PREF_ACCOUNT_NAME.equals(key) || PREF_ACCOUNT_TYPE.equals(key)) {
751            mCrumbs.setController(null);
752            mCrumbs.clear();
753            LoaderManager lm = getLoaderManager();
754            lm.restartLoader(LOADER_BOOKMARKS, null, this);
755            mCrumbs.setController(this);
756            String name = getString(R.string.bookmarks);
757            mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
758            if (mCallbacks != null) {
759                mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
760            }
761        }
762    }
763}
764