mobile/android/base/home/BookmarksPanel.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/base/home/BookmarksPanel.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,251 @@
     1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +package org.mozilla.gecko.home;
    1.10 +
    1.11 +import java.util.List;
    1.12 +
    1.13 +import org.mozilla.gecko.R;
    1.14 +import org.mozilla.gecko.db.BrowserContract.Bookmarks;
    1.15 +import org.mozilla.gecko.db.BrowserDB;
    1.16 +import org.mozilla.gecko.home.BookmarksListAdapter.FolderInfo;
    1.17 +import org.mozilla.gecko.home.BookmarksListAdapter.OnRefreshFolderListener;
    1.18 +import org.mozilla.gecko.home.BookmarksListAdapter.RefreshType;
    1.19 +import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
    1.20 +
    1.21 +import android.app.Activity;
    1.22 +import android.content.Context;
    1.23 +import android.content.res.Configuration;
    1.24 +import android.database.Cursor;
    1.25 +import android.os.Bundle;
    1.26 +import android.support.v4.app.LoaderManager.LoaderCallbacks;
    1.27 +import android.support.v4.content.Loader;
    1.28 +import android.view.LayoutInflater;
    1.29 +import android.view.View;
    1.30 +import android.view.ViewGroup;
    1.31 +import android.view.ViewStub;
    1.32 +import android.widget.ImageView;
    1.33 +import android.widget.TextView;
    1.34 +
    1.35 +/**
    1.36 + * A page in about:home that displays a ListView of bookmarks.
    1.37 + */
    1.38 +public class BookmarksPanel extends HomeFragment {
    1.39 +    public static final String LOGTAG = "GeckoBookmarksPanel";
    1.40 +
    1.41 +    // Cursor loader ID for list of bookmarks.
    1.42 +    private static final int LOADER_ID_BOOKMARKS_LIST = 0;
    1.43 +
    1.44 +    // Information about the target bookmarks folder.
    1.45 +    private static final String BOOKMARKS_FOLDER_INFO = "folder_info";
    1.46 +
    1.47 +    // Refresh type for folder refreshing loader.
    1.48 +    private static final String BOOKMARKS_REFRESH_TYPE = "refresh_type";
    1.49 +
    1.50 +    // List of bookmarks.
    1.51 +    private BookmarksListView mList;
    1.52 +
    1.53 +    // Adapter for list of bookmarks.
    1.54 +    private BookmarksListAdapter mListAdapter;
    1.55 +
    1.56 +    // Adapter's parent stack.
    1.57 +    private List<FolderInfo> mSavedParentStack;
    1.58 +
    1.59 +    // Reference to the View to display when there are no results.
    1.60 +    private View mEmptyView;
    1.61 +
    1.62 +    // Callback for cursor loaders.
    1.63 +    private CursorLoaderCallbacks mLoaderCallbacks;
    1.64 +
    1.65 +    @Override
    1.66 +    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    1.67 +        final View view = inflater.inflate(R.layout.home_bookmarks_panel, container, false);
    1.68 +
    1.69 +        mList = (BookmarksListView) view.findViewById(R.id.bookmarks_list);
    1.70 +
    1.71 +        mList.setContextMenuInfoFactory(new HomeContextMenuInfo.Factory() {
    1.72 +            @Override
    1.73 +            public HomeContextMenuInfo makeInfoForCursor(View view, int position, long id, Cursor cursor) {
    1.74 +                final int type = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE));
    1.75 +                if (type == Bookmarks.TYPE_FOLDER) {
    1.76 +                    // We don't show a context menu for folders
    1.77 +                    return null;
    1.78 +                }
    1.79 +                final HomeContextMenuInfo info = new HomeContextMenuInfo(view, position, id);
    1.80 +                info.url = cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.URL));
    1.81 +                info.title = cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.TITLE));
    1.82 +                info.bookmarkId = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID));
    1.83 +                return info;
    1.84 +            }
    1.85 +        });
    1.86 +
    1.87 +        return view;
    1.88 +    }
    1.89 +
    1.90 +    @Override
    1.91 +    public void onViewCreated(View view, Bundle savedInstanceState) {
    1.92 +        super.onViewCreated(view, savedInstanceState);
    1.93 +
    1.94 +        OnUrlOpenListener listener = null;
    1.95 +        try {
    1.96 +            listener = (OnUrlOpenListener) getActivity();
    1.97 +        } catch (ClassCastException e) {
    1.98 +            throw new ClassCastException(getActivity().toString()
    1.99 +                    + " must implement HomePager.OnUrlOpenListener");
   1.100 +        }
   1.101 +
   1.102 +        mList.setTag(HomePager.LIST_TAG_BOOKMARKS);
   1.103 +        mList.setOnUrlOpenListener(listener);
   1.104 +
   1.105 +        registerForContextMenu(mList);
   1.106 +    }
   1.107 +
   1.108 +    @Override
   1.109 +    public void onActivityCreated(Bundle savedInstanceState) {
   1.110 +        super.onActivityCreated(savedInstanceState);
   1.111 +
   1.112 +        final Activity activity = getActivity();
   1.113 +
   1.114 +        // Setup the list adapter.
   1.115 +        mListAdapter = new BookmarksListAdapter(activity, null, mSavedParentStack);
   1.116 +        mListAdapter.setOnRefreshFolderListener(new OnRefreshFolderListener() {
   1.117 +            @Override
   1.118 +            public void onRefreshFolder(FolderInfo folderInfo, RefreshType refreshType) {
   1.119 +                // Restart the loader with folder as the argument.
   1.120 +                Bundle bundle = new Bundle();
   1.121 +                bundle.putParcelable(BOOKMARKS_FOLDER_INFO, folderInfo);
   1.122 +                bundle.putParcelable(BOOKMARKS_REFRESH_TYPE, refreshType);
   1.123 +                getLoaderManager().restartLoader(LOADER_ID_BOOKMARKS_LIST, bundle, mLoaderCallbacks);
   1.124 +            }
   1.125 +        });
   1.126 +        mList.setAdapter(mListAdapter);
   1.127 +
   1.128 +        // Create callbacks before the initial loader is started.
   1.129 +        mLoaderCallbacks = new CursorLoaderCallbacks();
   1.130 +        loadIfVisible();
   1.131 +    }
   1.132 +
   1.133 +    @Override
   1.134 +    public void onDestroyView() {
   1.135 +        mList = null;
   1.136 +        mListAdapter = null;
   1.137 +        mEmptyView = null;
   1.138 +        super.onDestroyView();
   1.139 +    }
   1.140 +
   1.141 +    @Override
   1.142 +    public void onConfigurationChanged(Configuration newConfig) {
   1.143 +        super.onConfigurationChanged(newConfig);
   1.144 +
   1.145 +        // Reattach the fragment, forcing a reinflation of its view.
   1.146 +        // We use commitAllowingStateLoss() instead of commit() here to avoid
   1.147 +        // an IllegalStateException. If the phone is rotated while Fennec
   1.148 +        // is in the background, onConfigurationChanged() is fired.
   1.149 +        // onConfigurationChanged() is called before onResume(), so
   1.150 +        // using commit() would throw an IllegalStateException since it can't
   1.151 +        // be used between the Activity's onSaveInstanceState() and
   1.152 +        // onResume().
   1.153 +        if (isVisible()) {
   1.154 +            // The parent stack is saved just so that the folder state can be
   1.155 +            // restored on rotation.
   1.156 +            mSavedParentStack = mListAdapter.getParentStack();
   1.157 +
   1.158 +            getFragmentManager().beginTransaction()
   1.159 +                                .detach(this)
   1.160 +                                .attach(this)
   1.161 +                                .commitAllowingStateLoss();
   1.162 +        }
   1.163 +    }
   1.164 +
   1.165 +    @Override
   1.166 +    protected void load() {
   1.167 +        getLoaderManager().initLoader(LOADER_ID_BOOKMARKS_LIST, null, mLoaderCallbacks);
   1.168 +    }
   1.169 +
   1.170 +    private void updateUiFromCursor(Cursor c) {
   1.171 +        if ((c == null || c.getCount() == 0) && mEmptyView == null) {
   1.172 +            // Set empty page view. We delay this so that the empty view won't flash.
   1.173 +            final ViewStub emptyViewStub = (ViewStub) getView().findViewById(R.id.home_empty_view_stub);
   1.174 +            mEmptyView = emptyViewStub.inflate();
   1.175 +
   1.176 +            final ImageView emptyIcon = (ImageView) mEmptyView.findViewById(R.id.home_empty_image);
   1.177 +            emptyIcon.setImageResource(R.drawable.icon_bookmarks_empty);
   1.178 +
   1.179 +            final TextView emptyText = (TextView) mEmptyView.findViewById(R.id.home_empty_text);
   1.180 +            emptyText.setText(R.string.home_bookmarks_empty);
   1.181 +
   1.182 +            mList.setEmptyView(mEmptyView);
   1.183 +        }
   1.184 +    }
   1.185 +
   1.186 +    /**
   1.187 +     * Loader for the list for bookmarks.
   1.188 +     */
   1.189 +    private static class BookmarksLoader extends SimpleCursorLoader {
   1.190 +        private final FolderInfo mFolderInfo;
   1.191 +        private final RefreshType mRefreshType;
   1.192 +
   1.193 +        public BookmarksLoader(Context context) {
   1.194 +            this(context, new FolderInfo(Bookmarks.FIXED_ROOT_ID), RefreshType.CHILD);
   1.195 +        }
   1.196 +
   1.197 +        public BookmarksLoader(Context context, FolderInfo folderInfo, RefreshType refreshType) {
   1.198 +            super(context);
   1.199 +            mFolderInfo = folderInfo;
   1.200 +            mRefreshType = refreshType;
   1.201 +        }
   1.202 +
   1.203 +        @Override
   1.204 +        public Cursor loadCursor() {
   1.205 +            return BrowserDB.getBookmarksInFolder(getContext().getContentResolver(), mFolderInfo.id);
   1.206 +        }
   1.207 +
   1.208 +        @Override
   1.209 +        public void onContentChanged() {
   1.210 +            // Invalidate the cached value that keeps track of whether or
   1.211 +            // not desktop bookmarks exist.
   1.212 +            BrowserDB.invalidateCachedState();
   1.213 +            super.onContentChanged();
   1.214 +        }
   1.215 +
   1.216 +        public FolderInfo getFolderInfo() {
   1.217 +            return mFolderInfo;
   1.218 +        }
   1.219 +
   1.220 +        public RefreshType getRefreshType() {
   1.221 +            return mRefreshType;
   1.222 +        }
   1.223 +    }
   1.224 +
   1.225 +    /**
   1.226 +     * Loader callbacks for the LoaderManager of this fragment.
   1.227 +     */
   1.228 +    private class CursorLoaderCallbacks implements LoaderCallbacks<Cursor> {
   1.229 +        @Override
   1.230 +        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
   1.231 +            if (args == null) {
   1.232 +                return new BookmarksLoader(getActivity());
   1.233 +            } else {
   1.234 +                FolderInfo folderInfo = (FolderInfo) args.getParcelable(BOOKMARKS_FOLDER_INFO);
   1.235 +                RefreshType refreshType = (RefreshType) args.getParcelable(BOOKMARKS_REFRESH_TYPE);
   1.236 +                return new BookmarksLoader(getActivity(), folderInfo, refreshType);
   1.237 +            }
   1.238 +        }
   1.239 +
   1.240 +        @Override
   1.241 +        public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
   1.242 +            BookmarksLoader bl = (BookmarksLoader) loader;
   1.243 +            mListAdapter.swapCursor(c, bl.getFolderInfo(), bl.getRefreshType());
   1.244 +            updateUiFromCursor(c);
   1.245 +        }
   1.246 +
   1.247 +        @Override
   1.248 +        public void onLoaderReset(Loader<Cursor> loader) {
   1.249 +            if (mList != null) {
   1.250 +                mListAdapter.swapCursor(null);
   1.251 +            }
   1.252 +        }
   1.253 +    }
   1.254 +}

mercurial