blob: 962d21c2ccc198012eb0973eb04a80b9009bca3f [file] [log] [blame]
The Android Open Source Project0c908882009-03-03 19:32:16 -08001/*
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
John Reck71efc2b2011-05-09 16:54:28 -070019import com.android.browser.view.BookmarkExpandableGridView;
20import com.android.browser.view.BookmarkExpandableGridView.BookmarkContextMenuInfo;
John Reckd4893b02010-12-07 17:38:34 -080021
The Android Open Source Project0c908882009-03-03 19:32:16 -080022import android.app.Activity;
Jeff Hamilton64144e42010-08-18 16:31:59 -050023import android.app.Fragment;
Jeff Hamilton84029622010-08-05 14:29:28 -050024import android.app.LoaderManager;
Dianne Hackborneb07b172010-08-26 22:18:14 -070025import android.content.ClipData;
Michael Kolbbef7a752010-08-25 17:11:35 -070026import android.content.ClipboardManager;
Jeff Hamilton84029622010-08-05 14:29:28 -050027import android.content.ContentUris;
Dianne Hackborn80f32622010-08-05 14:17:53 -070028import android.content.Context;
John Reck71efc2b2011-05-09 16:54:28 -070029import android.content.CursorLoader;
The Android Open Source Project0c908882009-03-03 19:32:16 -080030import android.content.Intent;
Jeff Hamilton84029622010-08-05 14:29:28 -050031import android.content.Loader;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050032import android.content.SharedPreferences;
John Reck8af90642010-11-23 10:27:29 -080033import android.content.SharedPreferences.Editor;
John Reckb3417f02011-01-14 11:01:05 -080034import android.content.res.Configuration;
35import android.content.res.Resources;
Jeff Hamilton84029622010-08-05 14:29:28 -050036import android.database.Cursor;
The Android Open Source Project0c908882009-03-03 19:32:16 -080037import android.graphics.Bitmap;
Jeff Hamilton84029622010-08-05 14:29:28 -050038import android.graphics.BitmapFactory;
39import android.net.Uri;
John Reckc8490812010-11-22 14:15:36 -080040import android.os.AsyncTask;
The Android Open Source Project0c908882009-03-03 19:32:16 -080041import android.os.Bundle;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050042import android.preference.PreferenceManager;
Jeff Hamilton69bd7072010-08-17 12:38:22 -050043import android.provider.BrowserContract;
John Reck71efc2b2011-05-09 16:54:28 -070044import android.provider.BrowserContract.Accounts;
John Reck1cebb442010-12-10 12:02:16 -080045import android.provider.BrowserContract.ChromeSyncColumns;
The Android Open Source Project0c908882009-03-03 19:32:16 -080046import android.view.ContextMenu;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050047import android.view.ContextMenu.ContextMenuInfo;
Jeff Hamilton64144e42010-08-18 16:31:59 -050048import android.view.LayoutInflater;
John Reckb3417f02011-01-14 11:01:05 -080049import android.view.Menu;
The Android Open Source Project0c908882009-03-03 19:32:16 -080050import android.view.MenuInflater;
51import android.view.MenuItem;
52import android.view.View;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050053import android.view.ViewGroup;
Patrick Scottc1cf63a2010-03-09 16:02:08 -050054import android.webkit.WebIconDatabase.IconListener;
John Reck71efc2b2011-05-09 16:54:28 -070055import android.widget.ExpandableListView;
56import android.widget.ExpandableListView.OnChildClickListener;
John Reck8af90642010-11-23 10:27:29 -080057import android.widget.ListView;
John Reck608baa72010-11-24 10:32:28 -080058import android.widget.PopupMenu.OnMenuItemClickListener;
Jeff Hamilton84029622010-08-05 14:29:28 -050059import android.widget.Toast;
The Android Open Source Project0c908882009-03-03 19:32:16 -080060
John Reck71efc2b2011-05-09 16:54:28 -070061import java.util.HashMap;
62
John Reck608baa72010-11-24 10:32:28 -080063interface BookmarksPageCallbacks {
64 // Return true if handled
65 boolean onBookmarkSelected(Cursor c, boolean isFolder);
66 // Return true if handled
67 boolean onOpenInNewWindow(Cursor c);
68}
69
The Android Open Source Project0c908882009-03-03 19:32:16 -080070/**
71 * View showing the user's bookmarks in the browser.
72 */
Jeff Hamilton64144e42010-08-18 16:31:59 -050073public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener,
John Reck71efc2b2011-05-09 16:54:28 -070074 LoaderManager.LoaderCallbacks<Cursor>, IconListener,
75 BreadCrumbView.Controller, OnMenuItemClickListener, OnChildClickListener {
The Android Open Source Project0c908882009-03-03 19:32:16 -080076
Jeff Hamilton84029622010-08-05 14:29:28 -050077 static final String LOGTAG = "browser";
Nicolas Catania095292f2010-03-15 09:00:14 -070078
John Reck71efc2b2011-05-09 16:54:28 -070079 static final int LOADER_ACCOUNTS = 1;
80 static final int LOADER_BOOKMARKS = 100;
Jeff Hamilton84029622010-08-05 14:29:28 -050081
Michael Kolb801ecb72010-08-25 12:57:38 -070082 static final String EXTRA_DISABLE_WINDOW = "disable_new_window";
83
Jeff Hamilton7f6cf3e2010-09-17 17:22:21 -050084 public static final String PREF_ACCOUNT_TYPE = "acct_type";
85 public static final String PREF_ACCOUNT_NAME = "acct_name";
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050086
John Reck71efc2b2011-05-09 16:54:28 -070087 static final String ACCOUNT_TYPE = "account_type";
88 static final String ACCOUNT_NAME = "account_name";
89
John Reck8af90642010-11-23 10:27:29 -080090 static final int VIEW_THUMBNAILS = 1;
91 static final int VIEW_LIST = 2;
92 static final String PREF_SELECTED_VIEW = "bookmarks_view";
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050093
John Reck608baa72010-11-24 10:32:28 -080094 BookmarksPageCallbacks mCallbacks;
John Reck0ce8a942011-01-14 19:57:09 -080095 View mRoot;
John Reck71efc2b2011-05-09 16:54:28 -070096 BookmarkExpandableGridView mGrid;
John Reck8af90642010-11-23 10:27:29 -080097 ListView mList;
Jeff Hamilton84029622010-08-05 14:29:28 -050098 boolean mDisableNewWindow;
John Reck608baa72010-11-24 10:32:28 -080099 boolean mEnableContextMenu = true;
Jeff Hamilton84029622010-08-05 14:29:28 -0500100 View mEmptyView;
John Reck8af90642010-11-23 10:27:29 -0800101 int mCurrentView;
John Reck608baa72010-11-24 10:32:28 -0800102 View mHeader;
John Reck71efc2b2011-05-09 16:54:28 -0700103 HashMap<Integer, BrowserBookmarksAdapter> mBookmarkAdapters = new HashMap<Integer, BrowserBookmarksAdapter>();
Michael Kolb370a4f32010-10-06 10:45:32 -0700104
John Reck608baa72010-11-24 10:32:28 -0800105 static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb,
106 Bundle args, ViewGroup headerContainer) {
Michael Kolbe421c242010-10-04 19:29:01 -0700107 BrowserBookmarksPage bbp = new BrowserBookmarksPage();
108 bbp.mCallbacks = cb;
109 bbp.setArguments(args);
110 return bbp;
111 }
112
Jeff Hamilton84029622010-08-05 14:29:28 -0500113 @Override
114 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
John Reck71efc2b2011-05-09 16:54:28 -0700115 if (id == LOADER_ACCOUNTS) {
116 return new AccountsLoader(getActivity());
117 } else if (id >= LOADER_BOOKMARKS) {
118 String accountType = args.getString(ACCOUNT_TYPE);
119 String accountName = args.getString(ACCOUNT_NAME);
120 BookmarksLoader bl = new BookmarksLoader(getActivity(),
121 accountType, accountName);
122 return bl;
123 } else {
124 throw new UnsupportedOperationException("Unknown loader id " + id);
Jeff Hamilton84029622010-08-05 14:29:28 -0500125 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500126 }
127
128 @Override
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500129 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
John Reck71efc2b2011-05-09 16:54:28 -0700130 if (loader.getId() == LOADER_ACCOUNTS) {
131 LoaderManager lm = getLoaderManager();
132 int id = LOADER_BOOKMARKS;
133 while (cursor.moveToNext()) {
134 String accountName = cursor.getString(0);
135 String accountType = cursor.getString(1);
136 Bundle args = new Bundle();
137 args.putString(ACCOUNT_NAME, accountName);
138 args.putString(ACCOUNT_TYPE, accountType);
139 BrowserBookmarksAdapter adapter = new BrowserBookmarksAdapter(
140 getActivity(), mCurrentView);
141 mBookmarkAdapters.put(id, adapter);
142 mGrid.addAccount(accountName, adapter);
143 lm.restartLoader(id, args, this);
144 id++;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500145 }
John Reck71efc2b2011-05-09 16:54:28 -0700146 // TODO: Figure out what a reload of these means
147 // Currently, a reload is triggered whenever bookmarks change
148 // This is less than ideal
149 // It also causes UI flickering as a new adapter is created
150 // instead of re-using an existing one when the account_name is the
151 // same.
152 // For now, this is a one-shot load
153 getLoaderManager().destroyLoader(LOADER_ACCOUNTS);
154 } else if (loader.getId() >= LOADER_BOOKMARKS) {
155 BrowserBookmarksAdapter adapter = mBookmarkAdapters.get(loader.getId());
156 adapter.changeCursor(cursor);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500157 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500158 }
159
John Reck522a4382011-01-26 13:23:47 -0800160 @Override
Dianne Hackborn39772c82010-12-16 00:43:54 -0800161 public void onLoaderReset(Loader<Cursor> loader) {
John Reck71efc2b2011-05-09 16:54:28 -0700162 // TODO: Figure out what to do here (if anything?)
Dianne Hackborn39772c82010-12-16 00:43:54 -0800163 }
164
Michael Kolb370a4f32010-10-06 10:45:32 -0700165 long getFolderId() {
166 LoaderManager manager = getLoaderManager();
167 BookmarksLoader loader =
John Reck608baa72010-11-24 10:32:28 -0800168 (BookmarksLoader) ((Loader<?>)manager.getLoader(LOADER_BOOKMARKS));
Michael Kolb370a4f32010-10-06 10:45:32 -0700169
170 Uri uri = loader.getUri();
171 if (uri != null) {
172 try {
173 return ContentUris.parseId(uri);
174 } catch (NumberFormatException nfx) {
175 return -1;
176 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500177 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700178 return -1;
179 }
180
The Android Open Source Project0c908882009-03-03 19:32:16 -0800181 @Override
182 public boolean onContextItemSelected(MenuItem item) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500183 final Activity activity = getActivity();
John Reck71efc2b2011-05-09 16:54:28 -0700184 BookmarkContextMenuInfo i = (BookmarkContextMenuInfo)item.getMenuInfo();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800185 // If we have no menu info, we can't tell which item was selected.
186 if (i == null) {
Leon Scrogginsc8cae082010-11-03 18:51:46 -0400187 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800188 }
John Reck71efc2b2011-05-09 16:54:28 -0700189 BrowserBookmarksAdapter adapter = getChildAdapter(i.groupPosition);
Nicolas Catania095292f2010-03-15 09:00:14 -0700190
The Android Open Source Project0c908882009-03-03 19:32:16 -0800191 switch (item.getItemId()) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800192 case R.id.open_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700193 loadUrl(adapter, i.childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800194 break;
195 case R.id.edit_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700196 editBookmark(adapter, i.childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800197 break;
198 case R.id.shortcut_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700199 Cursor c = adapter.getItem(i.childPosition);
John Reck608baa72010-11-24 10:32:28 -0800200 activity.sendBroadcast(createShortcutIntent(getActivity(), c));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800201 break;
202 case R.id.delete_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700203 displayRemoveBookmarkDialog(adapter, i.childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800204 break;
205 case R.id.new_window_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700206 openInNewWindow(adapter, i.childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800207 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500208 case R.id.share_link_context_menu_id: {
John Reck71efc2b2011-05-09 16:54:28 -0700209 Cursor cursor = adapter.getItem(i.childPosition);
Michael Kolb8233fac2010-10-26 16:08:53 -0700210 Controller.sharePage(activity,
Jeff Hamilton84029622010-08-05 14:29:28 -0500211 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE),
212 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL),
213 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON),
214 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800215 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500216 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800217 case R.id.copy_url_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700218 copy(getUrl(adapter, i.childPosition));
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400219 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500220 case R.id.homepage_context_menu_id: {
John Reck71efc2b2011-05-09 16:54:28 -0700221 BrowserSettings.getInstance().setHomePage(getUrl(adapter, i.childPosition));
Jeff Hamilton64144e42010-08-18 16:31:59 -0500222 Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400223 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500224 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400225 // Only for the Most visited page
Jeff Hamilton84029622010-08-05 14:29:28 -0500226 case R.id.save_to_bookmarks_menu_id: {
John Reck71efc2b2011-05-09 16:54:28 -0700227 Cursor cursor = adapter.getItem(i.childPosition);
Jeff Hamilton84029622010-08-05 14:29:28 -0500228 String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
229 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400230 // If the site is bookmarked, the item becomes remove from
231 // bookmarks.
Jeff Hamilton64144e42010-08-18 16:31:59 -0500232 Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400233 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500234 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800235 default:
236 return super.onContextItemSelected(item);
237 }
238 return true;
239 }
240
John Reck608baa72010-11-24 10:32:28 -0800241 static Bitmap getBitmap(Cursor cursor, int columnIndex) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500242 byte[] data = cursor.getBlob(columnIndex);
243 if (data == null) {
244 return null;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800245 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500246 return BitmapFactory.decodeByteArray(data, 0, data.length);
247 }
248
John Reckc8490812010-11-22 14:15:36 -0800249 private MenuItem.OnMenuItemClickListener mContextItemClickListener =
250 new MenuItem.OnMenuItemClickListener() {
251 @Override
252 public boolean onMenuItemClick(MenuItem item) {
253 return onContextItemSelected(item);
254 }
255 };
256
Jeff Hamilton84029622010-08-05 14:29:28 -0500257 @Override
John Reckb3417f02011-01-14 11:01:05 -0800258 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
259 inflater.inflate(R.menu.bookmark, menu);
John Recka5176f32011-05-17 12:35:37 -0700260 if (!BrowserActivity.isTablet(getActivity())) {
John Reck9d27ff52011-02-11 17:47:54 -0800261 MenuItem item = menu.findItem(R.id.add_bookmark);
262 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
263 }
John Reckb3417f02011-01-14 11:01:05 -0800264 }
265
266 @Override
Jeff Hamilton84029622010-08-05 14:29:28 -0500267 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
John Reck71efc2b2011-05-09 16:54:28 -0700268 BookmarkContextMenuInfo info = (BookmarkContextMenuInfo) menuInfo;
269 BrowserBookmarksAdapter adapter = getChildAdapter(info.groupPosition);
270 Cursor cursor = adapter.getItem(info.childPosition);
John Reck1cebb442010-12-10 12:02:16 -0800271 if (!canEdit(cursor)) {
272 return;
273 }
Leon Scroggins5e8a40f2010-09-27 17:13:35 -0400274 boolean isFolder
275 = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
Michael Kolb801ecb72010-08-25 12:57:38 -0700276
Jeff Hamilton64144e42010-08-18 16:31:59 -0500277 final Activity activity = getActivity();
278 MenuInflater inflater = activity.getMenuInflater();
Jeff Hamilton84029622010-08-05 14:29:28 -0500279 inflater.inflate(R.menu.bookmarkscontext, menu);
John Reckc8490812010-11-22 14:15:36 -0800280 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 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500287 }
John Reckc8490812010-11-22 14:15:36 -0800288 BookmarkItem header = new BookmarkItem(activity);
289 populateBookmarkItem(cursor, header, isFolder);
John Reckc8490812010-11-22 14:15:36 -0800290 menu.setHeaderView(header);
Jeff Hamilton84029622010-08-05 14:29:28 -0500291
John Reckc8490812010-11-22 14:15:36 -0800292 int count = menu.size();
293 for (int i = 0; i < count; i++) {
294 menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener);
Jeff Hamilton84029622010-08-05 14:29:28 -0500295 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500296 }
297
John Reck1cebb442010-12-10 12:02:16 -0800298 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
John Reckc8490812010-11-22 14:15:36 -0800303 private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500304 item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
John Reckc8490812010-11-22 14:15:36 -0800305 if (isFolder) {
306 item.setUrl(null);
307 Bitmap bitmap =
Michael Kolb5a72f182011-01-13 20:35:06 -0800308 BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder_holo_dark);
John Reckc8490812010-11-22 14:15:36 -0800309 item.setFavicon(bitmap);
John Reck60e33362010-12-02 17:52:38 -0800310 new LookupBookmarkCount(getActivity(), item)
311 .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
John Reckc8490812010-11-22 14:15:36 -0800312 } 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);
Jeff Hamilton84029622010-08-05 14:29:28 -0500320 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500321 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800322
323 /**
324 * Create a new BrowserBookmarksPage.
Nicolas Catania095292f2010-03-15 09:00:14 -0700325 */
The Android Open Source Project0c908882009-03-03 19:32:16 -0800326 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500327 public void onCreate(Bundle icicle) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800328 super.onCreate(icicle);
John Reck8f295d12011-03-18 15:25:18 -0700329 SharedPreferences prefs = PreferenceManager
John Reck71efc2b2011-05-09 16:54:28 -0700330 .getDefaultSharedPreferences(getActivity());
John Reck8f295d12011-03-18 15:25:18 -0700331 mCurrentView = prefs.getInt(PREF_SELECTED_VIEW, getDefaultView());
John Reck71efc2b2011-05-09 16:54:28 -0700332 // TODO: Support list view
333 mCurrentView = VIEW_THUMBNAILS;
John Reckb3417f02011-01-14 11:01:05 -0800334
Jeff Hamilton64144e42010-08-18 16:31:59 -0500335 Bundle args = getArguments();
Leon Scrogginsbc922852010-10-22 12:15:27 -0400336 mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
John Reck8f295d12011-03-18 15:25:18 -0700337
338 setHasOptionsMenu(true);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500339 }
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400340
Jeff Hamilton64144e42010-08-18 16:31:59 -0500341 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500342 public View onCreateView(LayoutInflater inflater, ViewGroup container,
343 Bundle savedInstanceState) {
John Reck0ce8a942011-01-14 19:57:09 -0800344 mRoot = inflater.inflate(R.layout.bookmarks, container, false);
345 mEmptyView = mRoot.findViewById(android.R.id.empty);
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400346
John Reck71efc2b2011-05-09 16:54:28 -0700347 mGrid = (BookmarkExpandableGridView) mRoot.findViewById(R.id.grid);
348 mGrid.setOnChildClickListener(this);
349 mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
350 mGrid.setBreadcrumbController(this);
John Reck0ce8a942011-01-14 19:57:09 -0800351 mList = (ListView) mRoot.findViewById(R.id.list);
John Reck71efc2b2011-05-09 16:54:28 -0700352 // TODO: mList.setOnItemClickListener(this);
John Reck608baa72010-11-24 10:32:28 -0800353 setEnableContextMenu(mEnableContextMenu);
354
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500355 // Start the loaders
356 LoaderManager lm = getLoaderManager();
John Reck71efc2b2011-05-09 16:54:28 -0700357 lm.restartLoader(LOADER_ACCOUNTS, null, this);
Jeff Hamilton84029622010-08-05 14:29:28 -0500358
359 // Add our own listener in case there are favicons that have yet to be loaded.
Michael Kolbe421c242010-10-04 19:29:01 -0700360 CombinedBookmarkHistoryView.getIconListenerSet().addListener(this);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800361
John Reck0ce8a942011-01-14 19:57:09 -0800362 return mRoot;
Jeff Hamilton64144e42010-08-18 16:31:59 -0500363 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700364
John Reck9d27ff52011-02-11 17:47:54 -0800365 private int getDefaultView() {
John Recka5176f32011-05-17 12:35:37 -0700366 if (BrowserActivity.isTablet(getActivity())) {
John Reck9d27ff52011-02-11 17:47:54 -0800367 return VIEW_THUMBNAILS;
368 }
369 return VIEW_LIST;
370 }
371
John Reck608baa72010-11-24 10:32:28 -0800372 @Override
373 public void onDestroyView() {
374 super.onDestroyView();
John Reck71efc2b2011-05-09 16:54:28 -0700375 mGrid.setBreadcrumbController(null);
376 LoaderManager lm = getLoaderManager();
377 lm.destroyLoader(LOADER_ACCOUNTS);
378 for (int id : mBookmarkAdapters.keySet()) {
379 lm.destroyLoader(id);
John Reck608baa72010-11-24 10:32:28 -0800380 }
John Reck71efc2b2011-05-09 16:54:28 -0700381 mBookmarkAdapters.clear();
382
John Recke3063ae2011-01-27 14:57:40 -0800383 CombinedBookmarkHistoryView.getIconListenerSet().removeListener(this);
John Reck608baa72010-11-24 10:32:28 -0800384 }
385
Nicolas Catania095292f2010-03-15 09:00:14 -0700386 @Override
Jeff Hamilton84029622010-08-05 14:29:28 -0500387 public void onReceivedIcon(String url, Bitmap icon) {
388 // A new favicon has been loaded, so let anything attached to the adapter know about it
389 // so new icons will be loaded.
John Reck71efc2b2011-05-09 16:54:28 -0700390 // TODO: Notify all of data set changed
391 // TODO: Wait, is this even needed? Won't this trigger a DB change anyway?
392 }
393
394 private BrowserBookmarksAdapter getChildAdapter(int groupPosition) {
395 if (mCurrentView == VIEW_THUMBNAILS) {
396 return mGrid.getChildAdapter(groupPosition);
397 } else {
398 // TODO: Support expandable list
399 return null;
400 }
401 }
402
403 private BreadCrumbView getBreadCrumbs(int groupPosition) {
404 if (mCurrentView == VIEW_THUMBNAILS) {
405 return mGrid.getBreadCrumbs(groupPosition);
406 } else {
407 // TODO: Support expandable list
408 return null;
409 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700410 }
411
Jeff Hamilton84029622010-08-05 14:29:28 -0500412 @Override
John Reck71efc2b2011-05-09 16:54:28 -0700413 public boolean onChildClick(ExpandableListView parent, View v,
414 int groupPosition, int childPosition, long id) {
415 BrowserBookmarksAdapter adapter = getChildAdapter(groupPosition);
416 Cursor cursor = adapter.getItem(childPosition);
John Reck608baa72010-11-24 10:32:28 -0800417 boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
418 if (mCallbacks != null &&
419 mCallbacks.onBookmarkSelected(cursor, isFolder)) {
John Reck71efc2b2011-05-09 16:54:28 -0700420 return true;
Ben Murdoch328ea872009-09-16 13:33:29 +0100421 }
422
John Reck71efc2b2011-05-09 16:54:28 -0700423 // TODO: Folder stuff
John Reck608baa72010-11-24 10:32:28 -0800424 if (isFolder) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700425 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500426 Uri uri = ContentUris.withAppendedId(
427 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
John Reck71efc2b2011-05-09 16:54:28 -0700428 BreadCrumbView crumbs = getBreadCrumbs(groupPosition);
429 if (crumbs != null) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700430 // update crumbs
John Reck71efc2b2011-05-09 16:54:28 -0700431 crumbs.pushView(title, uri);
Michael Kolb370a4f32010-10-06 10:45:32 -0700432 }
John Reck71efc2b2011-05-09 16:54:28 -0700433 loadFolder(groupPosition, uri);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400434 }
John Reck71efc2b2011-05-09 16:54:28 -0700435 return true;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800436 }
437
John Reck608baa72010-11-24 10:32:28 -0800438 /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500439 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Michael Kolbccaa8962010-10-20 17:03:10 -0700440 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500441 Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
442 Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
John Reck608baa72010-11-24 10:32:28 -0800443 return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800444 }
445
John Reck71efc2b2011-05-09 16:54:28 -0700446 private void loadUrl(BrowserBookmarksAdapter adapter, int position) {
447 if (mCallbacks != null && adapter != null) {
448 mCallbacks.onBookmarkSelected(adapter.getItem(position), false);
John Reck608baa72010-11-24 10:32:28 -0800449 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800450 }
451
John Reck71efc2b2011-05-09 16:54:28 -0700452 private void openInNewWindow(BrowserBookmarksAdapter adapter, int position) {
John Reck608baa72010-11-24 10:32:28 -0800453 if (mCallbacks != null) {
John Reck71efc2b2011-05-09 16:54:28 -0700454 Cursor c = adapter.getItem(position);
John Reck1b3c66e2011-01-11 13:20:32 -0800455 boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
456 if (isFolder) {
457 long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
458 new OpenAllInTabsTask(id).execute();
459 } else {
460 mCallbacks.onOpenInNewWindow(c);
461 }
John Reck608baa72010-11-24 10:32:28 -0800462 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800463 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700464
John Reck1b3c66e2011-01-11 13:20:32 -0800465 class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> {
466 long mFolderId;
467 public OpenAllInTabsTask(long id) {
468 mFolderId = id;
469 }
470
471 @Override
472 protected Cursor doInBackground(Void... params) {
473 Context c = getActivity();
474 if (c == null) return null;
475 return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c),
476 BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?",
477 new String[] { Long.toString(mFolderId) }, null);
478 }
479
480 @Override
481 protected void onPostExecute(Cursor result) {
482 if (mCallbacks != null) {
483 while (result.moveToNext()) {
484 mCallbacks.onOpenInNewWindow(result);
485 }
486 }
487 }
488
489 }
490
John Reck71efc2b2011-05-09 16:54:28 -0700491 private void editBookmark(BrowserBookmarksAdapter adapter, int position) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500492 Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
John Reck71efc2b2011-05-09 16:54:28 -0700493 Cursor cursor = adapter.getItem(position);
Jeff Hamilton84029622010-08-05 14:29:28 -0500494 Bundle item = new Bundle();
Michael Kolbbef7a752010-08-25 17:11:35 -0700495 item.putString(BrowserContract.Bookmarks.TITLE,
Jeff Hamilton84029622010-08-05 14:29:28 -0500496 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
Michael Kolbbef7a752010-08-25 17:11:35 -0700497 item.putString(BrowserContract.Bookmarks.URL,
Jeff Hamilton84029622010-08-05 14:29:28 -0500498 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
499 byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
500 if (data != null) {
Michael Kolbbef7a752010-08-25 17:11:35 -0700501 item.putParcelable(BrowserContract.Bookmarks.FAVICON,
Jeff Hamilton84029622010-08-05 14:29:28 -0500502 BitmapFactory.decodeByteArray(data, 0, data.length));
503 }
John Reckc8490812010-11-22 14:15:36 -0800504 item.putLong(BrowserContract.Bookmarks._ID,
505 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
Leon Scroggins III052ce662010-09-13 14:44:16 -0400506 item.putLong(BrowserContract.Bookmarks.PARENT,
507 cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
John Reckc8490812010-11-22 14:15:36 -0800508 intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item);
509 intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER,
510 cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1);
511 startActivity(intent);
Jeff Hamilton84029622010-08-05 14:29:28 -0500512 }
513
John Reck71efc2b2011-05-09 16:54:28 -0700514 private void displayRemoveBookmarkDialog(BrowserBookmarksAdapter adapter,
515 int position) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800516 // Put up a dialog asking if the user really wants to
517 // delete the bookmark
John Reck71efc2b2011-05-09 16:54:28 -0700518 Cursor cursor = adapter.getItem(position);
Leon Scroggins75630672011-01-13 17:56:15 -0500519 long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
520 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500521 Context context = getActivity();
Leon Scroggins75630672011-01-13 17:56:15 -0500522 BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800523 }
524
John Reck71efc2b2011-05-09 16:54:28 -0700525 private String getUrl(BrowserBookmarksAdapter adapter, int position) {
526 return getUrl(adapter.getItem(position));
John Reck608baa72010-11-24 10:32:28 -0800527 }
528
529 /* package */ static String getUrl(Cursor c) {
530 return c.getString(BookmarksLoader.COLUMN_INDEX_URL);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800531 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700532
The Android Open Source Project0c908882009-03-03 19:32:16 -0800533 private void copy(CharSequence text) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500534 ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
535 Context.CLIPBOARD_SERVICE);
Dianne Hackbornbf1d10a2011-01-17 12:29:51 -0800536 cm.setPrimaryClip(ClipData.newRawUri(null, Uri.parse(text.toString())));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800537 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700538
John Reckb3417f02011-01-14 11:01:05 -0800539 @Override
540 public boolean onOptionsItemSelected(MenuItem item) {
541 switch (item.getItemId()) {
542 case R.id.thumbnail_view:
543 selectView(VIEW_THUMBNAILS);
544 return true;
545 case R.id.list_view:
546 selectView(VIEW_LIST);
547 return true;
548 }
549 return super.onOptionsItemSelected(item);
550 }
551
552 @Override
553 public void onConfigurationChanged(Configuration newConfig) {
554 super.onConfigurationChanged(newConfig);
555 Resources res = getActivity().getResources();
556 int horizontalSpacing = (int) res.getDimension(R.dimen.combo_horizontalSpacing);
557 mGrid.setHorizontalSpacing(horizontalSpacing);
John Reck71efc2b2011-05-09 16:54:28 -0700558 mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
John Reck0ce8a942011-01-14 19:57:09 -0800559 int paddingLeftRight = (int) res.getDimension(R.dimen.combo_paddingLeftRight);
560 int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop);
561 mRoot.setPadding(paddingLeftRight, paddingTop,
562 paddingLeftRight, 0);
John Reck9fdd9812011-05-17 14:16:38 -0700563 getActivity().invalidateOptionsMenu();
John Reckb3417f02011-01-14 11:01:05 -0800564 }
565
566 @Override
567 public void onPrepareOptionsMenu(Menu menu) {
568 super.onPrepareOptionsMenu(menu);
569 menu.findItem(R.id.list_view).setVisible(mCurrentView != VIEW_LIST);
570 menu.findItem(R.id.thumbnail_view).setVisible(mCurrentView != VIEW_THUMBNAILS);
571 }
572
John Reck8af90642010-11-23 10:27:29 -0800573 void selectView(int view) {
John Reck71efc2b2011-05-09 16:54:28 -0700574 // TODO: Support list view
575 view = mCurrentView;
John Reck8af90642010-11-23 10:27:29 -0800576 if (view == mCurrentView) {
577 return;
578 }
John Reck8af90642010-11-23 10:27:29 -0800579 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
580 Editor edit = prefs.edit();
581 edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
582 edit.apply();
583 if (mEmptyView.getVisibility() == View.VISIBLE) {
584 return;
585 }
586 setupBookmarkView();
587 }
588
589 private void setupBookmarkView() {
John Reck71efc2b2011-05-09 16:54:28 -0700590 // TODO: Support list view
591// mAdapter.selectView(mCurrentView);
592// switch (mCurrentView) {
593// case VIEW_THUMBNAILS:
594// mList.setAdapter(null);
595// SharedPreferences prefs = PreferenceManager
596// .getDefaultSharedPreferences(getActivity());
597// String accountName = prefs.getString(PREF_ACCOUNT_NAME, null);
598// mGrid.addAccount(accountName, mAdapter);
599// mGrid.setVisibility(View.VISIBLE);
600// mList.setVisibility(View.GONE);
601// break;
602// case VIEW_LIST:
603// mGrid.clearAccounts();
604// if (mList.getAdapter() != mAdapter) {
605// mList.setAdapter(mAdapter);
606// }
607// mGrid.setVisibility(View.GONE);
608// mList.setVisibility(View.VISIBLE);
609// break;
610// }
John Reck8af90642010-11-23 10:27:29 -0800611 }
John Reck608baa72010-11-24 10:32:28 -0800612
John Reck608baa72010-11-24 10:32:28 -0800613 /**
614 * BreadCrumb controller callback
615 */
616 @Override
John Reck71efc2b2011-05-09 16:54:28 -0700617 public void onTop(BreadCrumbView view, int level, Object data) {
618 int groupPosition = (Integer) view.getTag(R.id.group_position);
John Reck89f73c12010-12-01 10:10:14 -0800619 Uri uri = (Uri) data;
620 if (uri == null) {
621 // top level
622 uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
623 }
John Reck71efc2b2011-05-09 16:54:28 -0700624 loadFolder(groupPosition, uri);
John Reck89f73c12010-12-01 10:10:14 -0800625 }
626
627 /**
628 * @param uri
629 */
John Reck71efc2b2011-05-09 16:54:28 -0700630 private void loadFolder(int groupPosition, Uri uri) {
John Reck89f73c12010-12-01 10:10:14 -0800631 LoaderManager manager = getLoaderManager();
John Reck71efc2b2011-05-09 16:54:28 -0700632 // This assumes groups are ordered the same as loaders
633 BookmarksLoader loader = (BookmarksLoader) ((Loader<?>)
634 manager.getLoader(LOADER_BOOKMARKS + groupPosition));
John Reck89f73c12010-12-01 10:10:14 -0800635 loader.setUri(uri);
636 loader.forceLoad();
John Reck608baa72010-11-24 10:32:28 -0800637 }
638
639 @Override
John Reck608baa72010-11-24 10:32:28 -0800640 public boolean onMenuItemClick(MenuItem item) {
641 switch (item.getItemId()) {
642 case R.id.list_view:
John Reck608baa72010-11-24 10:32:28 -0800643 selectView(BrowserBookmarksPage.VIEW_LIST);
644 return true;
645 case R.id.thumbnail_view:
John Reck608baa72010-11-24 10:32:28 -0800646 selectView(BrowserBookmarksPage.VIEW_THUMBNAILS);
647 return true;
648 }
649 return false;
650 }
651
652 public boolean onBackPressed() {
John Reck608baa72010-11-24 10:32:28 -0800653 return false;
654 }
655
656 public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
657 mCallbacks = callbackListener;
658 }
659
660 public void setEnableContextMenu(boolean enable) {
661 mEnableContextMenu = enable;
662 if (mGrid != null) {
663 if (mEnableContextMenu) {
664 registerForContextMenu(mGrid);
665 } else {
666 unregisterForContextMenu(mGrid);
667 mGrid.setLongClickable(false);
668 }
669 }
670 if (mList != null) {
671 if (mEnableContextMenu) {
672 registerForContextMenu(mList);
673 } else {
674 unregisterForContextMenu(mList);
675 mList.setLongClickable(false);
676 }
677 }
678 }
John Reckc8490812010-11-22 14:15:36 -0800679
680 private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
681 Context mContext;
682 BookmarkItem mHeader;
683
684 public LookupBookmarkCount(Context context, BookmarkItem header) {
685 mContext = context;
686 mHeader = header;
687 }
688
689 @Override
690 protected Integer doInBackground(Long... params) {
691 if (params.length != 1) {
692 throw new IllegalArgumentException("Missing folder id!");
693 }
694 Uri uri = BookmarkUtils.getBookmarksUri(mContext);
695 Cursor c = mContext.getContentResolver().query(uri,
696 null, BrowserContract.Bookmarks.PARENT + "=?",
697 new String[] {params[0].toString()}, null);
698 return c.getCount();
699 }
700
701 @Override
702 protected void onPostExecute(Integer result) {
703 if (result > 0) {
704 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount,
705 result));
706 } else if (result == 0) {
707 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty));
708 }
709 }
710 }
John Reck89f73c12010-12-01 10:10:14 -0800711
John Reck71efc2b2011-05-09 16:54:28 -0700712 static class AccountsLoader extends CursorLoader {
John Reck89f73c12010-12-01 10:10:14 -0800713
John Reck71efc2b2011-05-09 16:54:28 -0700714 static String[] ACCOUNTS_PROJECTION = new String[] {
715 Accounts.ACCOUNT_NAME,
716 Accounts.ACCOUNT_TYPE
717 };
John Reck89f73c12010-12-01 10:10:14 -0800718
John Reck71efc2b2011-05-09 16:54:28 -0700719 public AccountsLoader(Context context) {
720 super(context, Accounts.CONTENT_URI, ACCOUNTS_PROJECTION, null, null,
721 Accounts.ACCOUNT_NAME + " ASC");
John Reck89f73c12010-12-01 10:10:14 -0800722 }
John Reck522a4382011-01-26 13:23:47 -0800723
John Reck522a4382011-01-26 13:23:47 -0800724 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800725}