blob: caf8a83424f7d8fedef42b940ec3ad3757d7d7ce [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 Reck66302e52011-05-18 17:12:33 -070019import com.android.browser.BookmarkDragHandler.BookmarkDragController;
John Reck71efc2b2011-05-09 16:54:28 -070020import com.android.browser.view.BookmarkExpandableGridView;
21import com.android.browser.view.BookmarkExpandableGridView.BookmarkContextMenuInfo;
John Reckd4893b02010-12-07 17:38:34 -080022
The Android Open Source Project0c908882009-03-03 19:32:16 -080023import android.app.Activity;
Jeff Hamilton64144e42010-08-18 16:31:59 -050024import android.app.Fragment;
Jeff Hamilton84029622010-08-05 14:29:28 -050025import android.app.LoaderManager;
Dianne Hackborneb07b172010-08-26 22:18:14 -070026import android.content.ClipData;
Michael Kolbbef7a752010-08-25 17:11:35 -070027import android.content.ClipboardManager;
Jeff Hamilton84029622010-08-05 14:29:28 -050028import android.content.ContentUris;
Dianne Hackborn80f32622010-08-05 14:17:53 -070029import android.content.Context;
John Reck71efc2b2011-05-09 16:54:28 -070030import android.content.CursorLoader;
The Android Open Source Project0c908882009-03-03 19:32:16 -080031import android.content.Intent;
Jeff Hamilton84029622010-08-05 14:29:28 -050032import android.content.Loader;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050033import android.content.SharedPreferences;
John Reck8af90642010-11-23 10:27:29 -080034import android.content.SharedPreferences.Editor;
John Reckb3417f02011-01-14 11:01:05 -080035import android.content.res.Configuration;
36import android.content.res.Resources;
Jeff Hamilton84029622010-08-05 14:29:28 -050037import android.database.Cursor;
The Android Open Source Project0c908882009-03-03 19:32:16 -080038import android.graphics.Bitmap;
Jeff Hamilton84029622010-08-05 14:29:28 -050039import android.graphics.BitmapFactory;
40import android.net.Uri;
John Reckc8490812010-11-22 14:15:36 -080041import android.os.AsyncTask;
The Android Open Source Project0c908882009-03-03 19:32:16 -080042import android.os.Bundle;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050043import android.preference.PreferenceManager;
Jeff Hamilton69bd7072010-08-17 12:38:22 -050044import android.provider.BrowserContract;
John Reck71efc2b2011-05-09 16:54:28 -070045import android.provider.BrowserContract.Accounts;
John Reck1cebb442010-12-10 12:02:16 -080046import android.provider.BrowserContract.ChromeSyncColumns;
The Android Open Source Project0c908882009-03-03 19:32:16 -080047import android.view.ContextMenu;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050048import android.view.ContextMenu.ContextMenuInfo;
Jeff Hamilton64144e42010-08-18 16:31:59 -050049import android.view.LayoutInflater;
John Reckb3417f02011-01-14 11:01:05 -080050import android.view.Menu;
The Android Open Source Project0c908882009-03-03 19:32:16 -080051import android.view.MenuInflater;
52import android.view.MenuItem;
53import android.view.View;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050054import android.view.ViewGroup;
Patrick Scottc1cf63a2010-03-09 16:02:08 -050055import android.webkit.WebIconDatabase.IconListener;
John Reck71efc2b2011-05-09 16:54:28 -070056import android.widget.ExpandableListView;
57import android.widget.ExpandableListView.OnChildClickListener;
John Reck8af90642010-11-23 10:27:29 -080058import android.widget.ListView;
John Reck608baa72010-11-24 10:32:28 -080059import android.widget.PopupMenu.OnMenuItemClickListener;
Jeff Hamilton84029622010-08-05 14:29:28 -050060import android.widget.Toast;
The Android Open Source Project0c908882009-03-03 19:32:16 -080061
John Reck71efc2b2011-05-09 16:54:28 -070062import java.util.HashMap;
63
John Reck608baa72010-11-24 10:32:28 -080064interface BookmarksPageCallbacks {
65 // Return true if handled
66 boolean onBookmarkSelected(Cursor c, boolean isFolder);
67 // Return true if handled
68 boolean onOpenInNewWindow(Cursor c);
69}
70
The Android Open Source Project0c908882009-03-03 19:32:16 -080071/**
72 * View showing the user's bookmarks in the browser.
73 */
Jeff Hamilton64144e42010-08-18 16:31:59 -050074public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener,
John Reck71efc2b2011-05-09 16:54:28 -070075 LoaderManager.LoaderCallbacks<Cursor>, IconListener,
76 BreadCrumbView.Controller, OnMenuItemClickListener, OnChildClickListener {
The Android Open Source Project0c908882009-03-03 19:32:16 -080077
Jeff Hamilton84029622010-08-05 14:29:28 -050078 static final String LOGTAG = "browser";
Nicolas Catania095292f2010-03-15 09:00:14 -070079
John Reck71efc2b2011-05-09 16:54:28 -070080 static final int LOADER_ACCOUNTS = 1;
81 static final int LOADER_BOOKMARKS = 100;
Jeff Hamilton84029622010-08-05 14:29:28 -050082
Michael Kolb801ecb72010-08-25 12:57:38 -070083 static final String EXTRA_DISABLE_WINDOW = "disable_new_window";
84
John Reck71efc2b2011-05-09 16:54:28 -070085 static final String ACCOUNT_TYPE = "account_type";
86 static final String ACCOUNT_NAME = "account_name";
87
John Reck8af90642010-11-23 10:27:29 -080088 static final int VIEW_THUMBNAILS = 1;
89 static final int VIEW_LIST = 2;
90 static final String PREF_SELECTED_VIEW = "bookmarks_view";
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050091
John Reck608baa72010-11-24 10:32:28 -080092 BookmarksPageCallbacks mCallbacks;
John Reck0ce8a942011-01-14 19:57:09 -080093 View mRoot;
John Reck71efc2b2011-05-09 16:54:28 -070094 BookmarkExpandableGridView mGrid;
John Reck8af90642010-11-23 10:27:29 -080095 ListView mList;
Jeff Hamilton84029622010-08-05 14:29:28 -050096 boolean mDisableNewWindow;
John Reck608baa72010-11-24 10:32:28 -080097 boolean mEnableContextMenu = true;
Jeff Hamilton84029622010-08-05 14:29:28 -050098 View mEmptyView;
John Reck8af90642010-11-23 10:27:29 -080099 int mCurrentView;
John Reck608baa72010-11-24 10:32:28 -0800100 View mHeader;
John Reck71efc2b2011-05-09 16:54:28 -0700101 HashMap<Integer, BrowserBookmarksAdapter> mBookmarkAdapters = new HashMap<Integer, BrowserBookmarksAdapter>();
John Reck66302e52011-05-18 17:12:33 -0700102 BookmarkDragHandler mDragHandler;
Michael Kolb370a4f32010-10-06 10:45:32 -0700103
John Reck608baa72010-11-24 10:32:28 -0800104 static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb,
105 Bundle args, ViewGroup headerContainer) {
Michael Kolbe421c242010-10-04 19:29:01 -0700106 BrowserBookmarksPage bbp = new BrowserBookmarksPage();
107 bbp.mCallbacks = cb;
108 bbp.setArguments(args);
109 return bbp;
110 }
111
Jeff Hamilton84029622010-08-05 14:29:28 -0500112 @Override
113 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
John Reck71efc2b2011-05-09 16:54:28 -0700114 if (id == LOADER_ACCOUNTS) {
115 return new AccountsLoader(getActivity());
116 } else if (id >= LOADER_BOOKMARKS) {
117 String accountType = args.getString(ACCOUNT_TYPE);
118 String accountName = args.getString(ACCOUNT_NAME);
119 BookmarksLoader bl = new BookmarksLoader(getActivity(),
120 accountType, accountName);
121 return bl;
122 } else {
123 throw new UnsupportedOperationException("Unknown loader id " + id);
Jeff Hamilton84029622010-08-05 14:29:28 -0500124 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500125 }
126
127 @Override
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500128 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
John Reck71efc2b2011-05-09 16:54:28 -0700129 if (loader.getId() == LOADER_ACCOUNTS) {
130 LoaderManager lm = getLoaderManager();
131 int id = LOADER_BOOKMARKS;
132 while (cursor.moveToNext()) {
133 String accountName = cursor.getString(0);
134 String accountType = cursor.getString(1);
135 Bundle args = new Bundle();
136 args.putString(ACCOUNT_NAME, accountName);
137 args.putString(ACCOUNT_TYPE, accountType);
138 BrowserBookmarksAdapter adapter = new BrowserBookmarksAdapter(
139 getActivity(), mCurrentView);
140 mBookmarkAdapters.put(id, adapter);
141 mGrid.addAccount(accountName, adapter);
142 lm.restartLoader(id, args, this);
143 id++;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500144 }
John Reck71efc2b2011-05-09 16:54:28 -0700145 // TODO: Figure out what a reload of these means
146 // Currently, a reload is triggered whenever bookmarks change
147 // This is less than ideal
148 // It also causes UI flickering as a new adapter is created
149 // instead of re-using an existing one when the account_name is the
150 // same.
151 // For now, this is a one-shot load
152 getLoaderManager().destroyLoader(LOADER_ACCOUNTS);
153 } else if (loader.getId() >= LOADER_BOOKMARKS) {
154 BrowserBookmarksAdapter adapter = mBookmarkAdapters.get(loader.getId());
155 adapter.changeCursor(cursor);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500156 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500157 }
158
John Reck522a4382011-01-26 13:23:47 -0800159 @Override
Dianne Hackborn39772c82010-12-16 00:43:54 -0800160 public void onLoaderReset(Loader<Cursor> loader) {
John Reck71efc2b2011-05-09 16:54:28 -0700161 // TODO: Figure out what to do here (if anything?)
Dianne Hackborn39772c82010-12-16 00:43:54 -0800162 }
163
Michael Kolb370a4f32010-10-06 10:45:32 -0700164 long getFolderId() {
165 LoaderManager manager = getLoaderManager();
166 BookmarksLoader loader =
John Reck608baa72010-11-24 10:32:28 -0800167 (BookmarksLoader) ((Loader<?>)manager.getLoader(LOADER_BOOKMARKS));
Michael Kolb370a4f32010-10-06 10:45:32 -0700168
169 Uri uri = loader.getUri();
170 if (uri != null) {
171 try {
172 return ContentUris.parseId(uri);
173 } catch (NumberFormatException nfx) {
174 return -1;
175 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500176 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700177 return -1;
178 }
179
The Android Open Source Project0c908882009-03-03 19:32:16 -0800180 @Override
181 public boolean onContextItemSelected(MenuItem item) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500182 final Activity activity = getActivity();
John Reck71efc2b2011-05-09 16:54:28 -0700183 BookmarkContextMenuInfo i = (BookmarkContextMenuInfo)item.getMenuInfo();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800184 // If we have no menu info, we can't tell which item was selected.
185 if (i == null) {
Leon Scrogginsc8cae082010-11-03 18:51:46 -0400186 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800187 }
John Reck71efc2b2011-05-09 16:54:28 -0700188 BrowserBookmarksAdapter adapter = getChildAdapter(i.groupPosition);
Nicolas Catania095292f2010-03-15 09:00:14 -0700189
The Android Open Source Project0c908882009-03-03 19:32:16 -0800190 switch (item.getItemId()) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800191 case R.id.open_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700192 loadUrl(adapter, i.childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800193 break;
194 case R.id.edit_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700195 editBookmark(adapter, i.childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800196 break;
197 case R.id.shortcut_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700198 Cursor c = adapter.getItem(i.childPosition);
John Reck608baa72010-11-24 10:32:28 -0800199 activity.sendBroadcast(createShortcutIntent(getActivity(), c));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800200 break;
201 case R.id.delete_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700202 displayRemoveBookmarkDialog(adapter, i.childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800203 break;
204 case R.id.new_window_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700205 openInNewWindow(adapter, i.childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800206 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500207 case R.id.share_link_context_menu_id: {
John Reck71efc2b2011-05-09 16:54:28 -0700208 Cursor cursor = adapter.getItem(i.childPosition);
Michael Kolb8233fac2010-10-26 16:08:53 -0700209 Controller.sharePage(activity,
Jeff Hamilton84029622010-08-05 14:29:28 -0500210 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE),
211 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL),
212 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON),
213 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800214 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500215 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800216 case R.id.copy_url_context_menu_id:
John Reck71efc2b2011-05-09 16:54:28 -0700217 copy(getUrl(adapter, i.childPosition));
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400218 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500219 case R.id.homepage_context_menu_id: {
John Reck71efc2b2011-05-09 16:54:28 -0700220 BrowserSettings.getInstance().setHomePage(getUrl(adapter, i.childPosition));
Jeff Hamilton64144e42010-08-18 16:31:59 -0500221 Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400222 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500223 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400224 // Only for the Most visited page
Jeff Hamilton84029622010-08-05 14:29:28 -0500225 case R.id.save_to_bookmarks_menu_id: {
John Reck71efc2b2011-05-09 16:54:28 -0700226 Cursor cursor = adapter.getItem(i.childPosition);
Jeff Hamilton84029622010-08-05 14:29:28 -0500227 String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
228 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400229 // If the site is bookmarked, the item becomes remove from
230 // bookmarks.
Jeff Hamilton64144e42010-08-18 16:31:59 -0500231 Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400232 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500233 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800234 default:
235 return super.onContextItemSelected(item);
236 }
237 return true;
238 }
239
John Reck608baa72010-11-24 10:32:28 -0800240 static Bitmap getBitmap(Cursor cursor, int columnIndex) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500241 byte[] data = cursor.getBlob(columnIndex);
242 if (data == null) {
243 return null;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800244 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500245 return BitmapFactory.decodeByteArray(data, 0, data.length);
246 }
247
John Reckc8490812010-11-22 14:15:36 -0800248 private MenuItem.OnMenuItemClickListener mContextItemClickListener =
249 new MenuItem.OnMenuItemClickListener() {
250 @Override
251 public boolean onMenuItemClick(MenuItem item) {
252 return onContextItemSelected(item);
253 }
254 };
255
Jeff Hamilton84029622010-08-05 14:29:28 -0500256 @Override
John Reckb3417f02011-01-14 11:01:05 -0800257 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
258 inflater.inflate(R.menu.bookmark, menu);
John Recka5176f32011-05-17 12:35:37 -0700259 if (!BrowserActivity.isTablet(getActivity())) {
John Reck9d27ff52011-02-11 17:47:54 -0800260 MenuItem item = menu.findItem(R.id.add_bookmark);
261 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
262 }
John Reckb3417f02011-01-14 11:01:05 -0800263 }
264
265 @Override
Jeff Hamilton84029622010-08-05 14:29:28 -0500266 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
John Reck71efc2b2011-05-09 16:54:28 -0700267 BookmarkContextMenuInfo info = (BookmarkContextMenuInfo) menuInfo;
268 BrowserBookmarksAdapter adapter = getChildAdapter(info.groupPosition);
269 Cursor cursor = adapter.getItem(info.childPosition);
John Reck1cebb442010-12-10 12:02:16 -0800270 if (!canEdit(cursor)) {
271 return;
272 }
Leon Scroggins5e8a40f2010-09-27 17:13:35 -0400273 boolean isFolder
274 = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
Michael Kolb801ecb72010-08-25 12:57:38 -0700275
Jeff Hamilton64144e42010-08-18 16:31:59 -0500276 final Activity activity = getActivity();
277 MenuInflater inflater = activity.getMenuInflater();
Jeff Hamilton84029622010-08-05 14:29:28 -0500278 inflater.inflate(R.menu.bookmarkscontext, menu);
John Reckc8490812010-11-22 14:15:36 -0800279 if (isFolder) {
280 menu.setGroupVisible(R.id.FOLDER_CONTEXT_MENU, true);
281 } else {
282 menu.setGroupVisible(R.id.BOOKMARK_CONTEXT_MENU, true);
283 if (mDisableNewWindow) {
284 menu.findItem(R.id.new_window_context_menu_id).setVisible(false);
285 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500286 }
John Reckc8490812010-11-22 14:15:36 -0800287 BookmarkItem header = new BookmarkItem(activity);
288 populateBookmarkItem(cursor, header, isFolder);
John Reckc8490812010-11-22 14:15:36 -0800289 menu.setHeaderView(header);
Jeff Hamilton84029622010-08-05 14:29:28 -0500290
John Reckc8490812010-11-22 14:15:36 -0800291 int count = menu.size();
292 for (int i = 0; i < count; i++) {
293 menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener);
Jeff Hamilton84029622010-08-05 14:29:28 -0500294 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500295 }
296
John Reck1cebb442010-12-10 12:02:16 -0800297 boolean canEdit(Cursor c) {
298 String unique = c.getString(BookmarksLoader.COLUMN_INDEX_SERVER_UNIQUE);
299 return !ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS.equals(unique);
300 }
301
John Reckc8490812010-11-22 14:15:36 -0800302 private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500303 item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
John Reckc8490812010-11-22 14:15:36 -0800304 if (isFolder) {
305 item.setUrl(null);
306 Bitmap bitmap =
Michael Kolb5a72f182011-01-13 20:35:06 -0800307 BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder_holo_dark);
John Reckc8490812010-11-22 14:15:36 -0800308 item.setFavicon(bitmap);
John Reck60e33362010-12-02 17:52:38 -0800309 new LookupBookmarkCount(getActivity(), item)
310 .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
John Reckc8490812010-11-22 14:15:36 -0800311 } else {
312 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
313 item.setUrl(url);
314 Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
315 if (bitmap == null) {
316 bitmap = CombinedBookmarkHistoryView.getIconListenerSet().getFavicon(url);
317 }
318 item.setFavicon(bitmap);
Jeff Hamilton84029622010-08-05 14:29:28 -0500319 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500320 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800321
322 /**
323 * Create a new BrowserBookmarksPage.
Nicolas Catania095292f2010-03-15 09:00:14 -0700324 */
The Android Open Source Project0c908882009-03-03 19:32:16 -0800325 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500326 public void onCreate(Bundle icicle) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800327 super.onCreate(icicle);
John Reck8f295d12011-03-18 15:25:18 -0700328 SharedPreferences prefs = PreferenceManager
John Reck71efc2b2011-05-09 16:54:28 -0700329 .getDefaultSharedPreferences(getActivity());
John Reck8f295d12011-03-18 15:25:18 -0700330 mCurrentView = prefs.getInt(PREF_SELECTED_VIEW, getDefaultView());
John Reck71efc2b2011-05-09 16:54:28 -0700331 // TODO: Support list view
332 mCurrentView = VIEW_THUMBNAILS;
John Reckb3417f02011-01-14 11:01:05 -0800333
Jeff Hamilton64144e42010-08-18 16:31:59 -0500334 Bundle args = getArguments();
Leon Scrogginsbc922852010-10-22 12:15:27 -0400335 mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
John Reck8f295d12011-03-18 15:25:18 -0700336
337 setHasOptionsMenu(true);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500338 }
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400339
Jeff Hamilton64144e42010-08-18 16:31:59 -0500340 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500341 public View onCreateView(LayoutInflater inflater, ViewGroup container,
342 Bundle savedInstanceState) {
John Reck0ce8a942011-01-14 19:57:09 -0800343 mRoot = inflater.inflate(R.layout.bookmarks, container, false);
344 mEmptyView = mRoot.findViewById(android.R.id.empty);
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400345
John Reck71efc2b2011-05-09 16:54:28 -0700346 mGrid = (BookmarkExpandableGridView) mRoot.findViewById(R.id.grid);
347 mGrid.setOnChildClickListener(this);
348 mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
349 mGrid.setBreadcrumbController(this);
John Reck0ce8a942011-01-14 19:57:09 -0800350 mList = (ListView) mRoot.findViewById(R.id.list);
John Reck71efc2b2011-05-09 16:54:28 -0700351 // TODO: mList.setOnItemClickListener(this);
John Reck608baa72010-11-24 10:32:28 -0800352 setEnableContextMenu(mEnableContextMenu);
John Reck66302e52011-05-18 17:12:33 -0700353 mDragHandler = new BookmarkDragHandler(getActivity(), mDragController,
354 mGrid.getDragAdapter());
John Reck608baa72010-11-24 10:32:28 -0800355
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500356 // Start the loaders
357 LoaderManager lm = getLoaderManager();
John Reck71efc2b2011-05-09 16:54:28 -0700358 lm.restartLoader(LOADER_ACCOUNTS, null, this);
Jeff Hamilton84029622010-08-05 14:29:28 -0500359
360 // Add our own listener in case there are favicons that have yet to be loaded.
Michael Kolbe421c242010-10-04 19:29:01 -0700361 CombinedBookmarkHistoryView.getIconListenerSet().addListener(this);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800362
John Reck0ce8a942011-01-14 19:57:09 -0800363 return mRoot;
Jeff Hamilton64144e42010-08-18 16:31:59 -0500364 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700365
John Reck9d27ff52011-02-11 17:47:54 -0800366 private int getDefaultView() {
John Recka5176f32011-05-17 12:35:37 -0700367 if (BrowserActivity.isTablet(getActivity())) {
John Reck9d27ff52011-02-11 17:47:54 -0800368 return VIEW_THUMBNAILS;
369 }
370 return VIEW_LIST;
371 }
372
John Reck608baa72010-11-24 10:32:28 -0800373 @Override
374 public void onDestroyView() {
375 super.onDestroyView();
John Reck71efc2b2011-05-09 16:54:28 -0700376 mGrid.setBreadcrumbController(null);
377 LoaderManager lm = getLoaderManager();
378 lm.destroyLoader(LOADER_ACCOUNTS);
379 for (int id : mBookmarkAdapters.keySet()) {
380 lm.destroyLoader(id);
John Reck608baa72010-11-24 10:32:28 -0800381 }
John Reck71efc2b2011-05-09 16:54:28 -0700382 mBookmarkAdapters.clear();
383
John Recke3063ae2011-01-27 14:57:40 -0800384 CombinedBookmarkHistoryView.getIconListenerSet().removeListener(this);
John Reck608baa72010-11-24 10:32:28 -0800385 }
386
Nicolas Catania095292f2010-03-15 09:00:14 -0700387 @Override
Jeff Hamilton84029622010-08-05 14:29:28 -0500388 public void onReceivedIcon(String url, Bitmap icon) {
389 // A new favicon has been loaded, so let anything attached to the adapter know about it
390 // so new icons will be loaded.
John Reck71efc2b2011-05-09 16:54:28 -0700391 // TODO: Notify all of data set changed
392 // TODO: Wait, is this even needed? Won't this trigger a DB change anyway?
393 }
394
395 private BrowserBookmarksAdapter getChildAdapter(int groupPosition) {
396 if (mCurrentView == VIEW_THUMBNAILS) {
397 return mGrid.getChildAdapter(groupPosition);
398 } else {
399 // TODO: Support expandable list
400 return null;
401 }
402 }
403
404 private BreadCrumbView getBreadCrumbs(int groupPosition) {
405 if (mCurrentView == VIEW_THUMBNAILS) {
406 return mGrid.getBreadCrumbs(groupPosition);
407 } else {
408 // TODO: Support expandable list
409 return null;
410 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700411 }
412
Jeff Hamilton84029622010-08-05 14:29:28 -0500413 @Override
John Reck71efc2b2011-05-09 16:54:28 -0700414 public boolean onChildClick(ExpandableListView parent, View v,
415 int groupPosition, int childPosition, long id) {
416 BrowserBookmarksAdapter adapter = getChildAdapter(groupPosition);
417 Cursor cursor = adapter.getItem(childPosition);
John Reck608baa72010-11-24 10:32:28 -0800418 boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
419 if (mCallbacks != null &&
420 mCallbacks.onBookmarkSelected(cursor, isFolder)) {
John Reck71efc2b2011-05-09 16:54:28 -0700421 return true;
Ben Murdoch328ea872009-09-16 13:33:29 +0100422 }
423
John Reck71efc2b2011-05-09 16:54:28 -0700424 // TODO: Folder stuff
John Reck608baa72010-11-24 10:32:28 -0800425 if (isFolder) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700426 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500427 Uri uri = ContentUris.withAppendedId(
428 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
John Reck71efc2b2011-05-09 16:54:28 -0700429 BreadCrumbView crumbs = getBreadCrumbs(groupPosition);
430 if (crumbs != null) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700431 // update crumbs
John Reck71efc2b2011-05-09 16:54:28 -0700432 crumbs.pushView(title, uri);
Michael Kolb370a4f32010-10-06 10:45:32 -0700433 }
John Reck71efc2b2011-05-09 16:54:28 -0700434 loadFolder(groupPosition, uri);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400435 }
John Reck71efc2b2011-05-09 16:54:28 -0700436 return true;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800437 }
438
John Reck608baa72010-11-24 10:32:28 -0800439 /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500440 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Michael Kolbccaa8962010-10-20 17:03:10 -0700441 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500442 Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
443 Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
John Reck608baa72010-11-24 10:32:28 -0800444 return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800445 }
446
John Reck71efc2b2011-05-09 16:54:28 -0700447 private void loadUrl(BrowserBookmarksAdapter adapter, int position) {
448 if (mCallbacks != null && adapter != null) {
449 mCallbacks.onBookmarkSelected(adapter.getItem(position), false);
John Reck608baa72010-11-24 10:32:28 -0800450 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800451 }
452
John Reck71efc2b2011-05-09 16:54:28 -0700453 private void openInNewWindow(BrowserBookmarksAdapter adapter, int position) {
John Reck608baa72010-11-24 10:32:28 -0800454 if (mCallbacks != null) {
John Reck71efc2b2011-05-09 16:54:28 -0700455 Cursor c = adapter.getItem(position);
John Reck1b3c66e2011-01-11 13:20:32 -0800456 boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
457 if (isFolder) {
458 long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
459 new OpenAllInTabsTask(id).execute();
460 } else {
461 mCallbacks.onOpenInNewWindow(c);
462 }
John Reck608baa72010-11-24 10:32:28 -0800463 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800464 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700465
John Reck1b3c66e2011-01-11 13:20:32 -0800466 class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> {
467 long mFolderId;
468 public OpenAllInTabsTask(long id) {
469 mFolderId = id;
470 }
471
472 @Override
473 protected Cursor doInBackground(Void... params) {
474 Context c = getActivity();
475 if (c == null) return null;
476 return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c),
477 BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?",
478 new String[] { Long.toString(mFolderId) }, null);
479 }
480
481 @Override
482 protected void onPostExecute(Cursor result) {
483 if (mCallbacks != null) {
484 while (result.moveToNext()) {
485 mCallbacks.onOpenInNewWindow(result);
486 }
487 }
488 }
489
490 }
491
John Reck71efc2b2011-05-09 16:54:28 -0700492 private void editBookmark(BrowserBookmarksAdapter adapter, int position) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500493 Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
John Reck71efc2b2011-05-09 16:54:28 -0700494 Cursor cursor = adapter.getItem(position);
Jeff Hamilton84029622010-08-05 14:29:28 -0500495 Bundle item = new Bundle();
Michael Kolbbef7a752010-08-25 17:11:35 -0700496 item.putString(BrowserContract.Bookmarks.TITLE,
Jeff Hamilton84029622010-08-05 14:29:28 -0500497 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
Michael Kolbbef7a752010-08-25 17:11:35 -0700498 item.putString(BrowserContract.Bookmarks.URL,
Jeff Hamilton84029622010-08-05 14:29:28 -0500499 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
500 byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
501 if (data != null) {
Michael Kolbbef7a752010-08-25 17:11:35 -0700502 item.putParcelable(BrowserContract.Bookmarks.FAVICON,
Jeff Hamilton84029622010-08-05 14:29:28 -0500503 BitmapFactory.decodeByteArray(data, 0, data.length));
504 }
John Reckc8490812010-11-22 14:15:36 -0800505 item.putLong(BrowserContract.Bookmarks._ID,
506 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
Leon Scroggins III052ce662010-09-13 14:44:16 -0400507 item.putLong(BrowserContract.Bookmarks.PARENT,
508 cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
John Reckc8490812010-11-22 14:15:36 -0800509 intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item);
510 intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER,
511 cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1);
512 startActivity(intent);
Jeff Hamilton84029622010-08-05 14:29:28 -0500513 }
514
John Reck71efc2b2011-05-09 16:54:28 -0700515 private void displayRemoveBookmarkDialog(BrowserBookmarksAdapter adapter,
516 int position) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800517 // Put up a dialog asking if the user really wants to
518 // delete the bookmark
John Reck71efc2b2011-05-09 16:54:28 -0700519 Cursor cursor = adapter.getItem(position);
Leon Scroggins75630672011-01-13 17:56:15 -0500520 long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
521 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500522 Context context = getActivity();
Leon Scroggins75630672011-01-13 17:56:15 -0500523 BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800524 }
525
John Reck71efc2b2011-05-09 16:54:28 -0700526 private String getUrl(BrowserBookmarksAdapter adapter, int position) {
527 return getUrl(adapter.getItem(position));
John Reck608baa72010-11-24 10:32:28 -0800528 }
529
530 /* package */ static String getUrl(Cursor c) {
531 return c.getString(BookmarksLoader.COLUMN_INDEX_URL);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800532 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700533
The Android Open Source Project0c908882009-03-03 19:32:16 -0800534 private void copy(CharSequence text) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500535 ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
536 Context.CLIPBOARD_SERVICE);
Dianne Hackbornbf1d10a2011-01-17 12:29:51 -0800537 cm.setPrimaryClip(ClipData.newRawUri(null, Uri.parse(text.toString())));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800538 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700539
John Reckb3417f02011-01-14 11:01:05 -0800540 @Override
541 public boolean onOptionsItemSelected(MenuItem item) {
542 switch (item.getItemId()) {
543 case R.id.thumbnail_view:
544 selectView(VIEW_THUMBNAILS);
545 return true;
546 case R.id.list_view:
547 selectView(VIEW_LIST);
548 return true;
549 }
550 return super.onOptionsItemSelected(item);
551 }
552
553 @Override
554 public void onConfigurationChanged(Configuration newConfig) {
555 super.onConfigurationChanged(newConfig);
556 Resources res = getActivity().getResources();
557 int horizontalSpacing = (int) res.getDimension(R.dimen.combo_horizontalSpacing);
558 mGrid.setHorizontalSpacing(horizontalSpacing);
John Reck71efc2b2011-05-09 16:54:28 -0700559 mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
John Reck0ce8a942011-01-14 19:57:09 -0800560 int paddingLeftRight = (int) res.getDimension(R.dimen.combo_paddingLeftRight);
561 int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop);
562 mRoot.setPadding(paddingLeftRight, paddingTop,
563 paddingLeftRight, 0);
John Reck9fdd9812011-05-17 14:16:38 -0700564 getActivity().invalidateOptionsMenu();
John Reckb3417f02011-01-14 11:01:05 -0800565 }
566
567 @Override
568 public void onPrepareOptionsMenu(Menu menu) {
569 super.onPrepareOptionsMenu(menu);
570 menu.findItem(R.id.list_view).setVisible(mCurrentView != VIEW_LIST);
571 menu.findItem(R.id.thumbnail_view).setVisible(mCurrentView != VIEW_THUMBNAILS);
572 }
573
John Reck8af90642010-11-23 10:27:29 -0800574 void selectView(int view) {
John Reck71efc2b2011-05-09 16:54:28 -0700575 // TODO: Support list view
576 view = mCurrentView;
John Reck8af90642010-11-23 10:27:29 -0800577 if (view == mCurrentView) {
578 return;
579 }
John Reck8af90642010-11-23 10:27:29 -0800580 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
581 Editor edit = prefs.edit();
582 edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
583 edit.apply();
584 if (mEmptyView.getVisibility() == View.VISIBLE) {
585 return;
586 }
587 setupBookmarkView();
588 }
589
590 private void setupBookmarkView() {
John Reck71efc2b2011-05-09 16:54:28 -0700591 // TODO: Support list view
592// mAdapter.selectView(mCurrentView);
593// switch (mCurrentView) {
594// case VIEW_THUMBNAILS:
595// mList.setAdapter(null);
596// SharedPreferences prefs = PreferenceManager
597// .getDefaultSharedPreferences(getActivity());
598// String accountName = prefs.getString(PREF_ACCOUNT_NAME, null);
599// mGrid.addAccount(accountName, mAdapter);
600// mGrid.setVisibility(View.VISIBLE);
601// mList.setVisibility(View.GONE);
602// break;
603// case VIEW_LIST:
604// mGrid.clearAccounts();
605// if (mList.getAdapter() != mAdapter) {
606// mList.setAdapter(mAdapter);
607// }
608// mGrid.setVisibility(View.GONE);
609// mList.setVisibility(View.VISIBLE);
610// break;
611// }
John Reck8af90642010-11-23 10:27:29 -0800612 }
John Reck608baa72010-11-24 10:32:28 -0800613
John Reck608baa72010-11-24 10:32:28 -0800614 /**
615 * BreadCrumb controller callback
616 */
617 @Override
John Reck71efc2b2011-05-09 16:54:28 -0700618 public void onTop(BreadCrumbView view, int level, Object data) {
619 int groupPosition = (Integer) view.getTag(R.id.group_position);
John Reck89f73c12010-12-01 10:10:14 -0800620 Uri uri = (Uri) data;
621 if (uri == null) {
622 // top level
623 uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
624 }
John Reck71efc2b2011-05-09 16:54:28 -0700625 loadFolder(groupPosition, uri);
John Reck89f73c12010-12-01 10:10:14 -0800626 }
627
628 /**
629 * @param uri
630 */
John Reck71efc2b2011-05-09 16:54:28 -0700631 private void loadFolder(int groupPosition, Uri uri) {
John Reck89f73c12010-12-01 10:10:14 -0800632 LoaderManager manager = getLoaderManager();
John Reck71efc2b2011-05-09 16:54:28 -0700633 // This assumes groups are ordered the same as loaders
634 BookmarksLoader loader = (BookmarksLoader) ((Loader<?>)
635 manager.getLoader(LOADER_BOOKMARKS + groupPosition));
John Reck89f73c12010-12-01 10:10:14 -0800636 loader.setUri(uri);
637 loader.forceLoad();
John Reck608baa72010-11-24 10:32:28 -0800638 }
639
640 @Override
John Reck608baa72010-11-24 10:32:28 -0800641 public boolean onMenuItemClick(MenuItem item) {
642 switch (item.getItemId()) {
643 case R.id.list_view:
John Reck608baa72010-11-24 10:32:28 -0800644 selectView(BrowserBookmarksPage.VIEW_LIST);
645 return true;
646 case R.id.thumbnail_view:
John Reck608baa72010-11-24 10:32:28 -0800647 selectView(BrowserBookmarksPage.VIEW_THUMBNAILS);
648 return true;
649 }
650 return false;
651 }
652
653 public boolean onBackPressed() {
John Reck608baa72010-11-24 10:32:28 -0800654 return false;
655 }
656
657 public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
658 mCallbacks = callbackListener;
659 }
660
661 public void setEnableContextMenu(boolean enable) {
662 mEnableContextMenu = enable;
663 if (mGrid != null) {
664 if (mEnableContextMenu) {
665 registerForContextMenu(mGrid);
666 } else {
667 unregisterForContextMenu(mGrid);
668 mGrid.setLongClickable(false);
669 }
670 }
671 if (mList != null) {
672 if (mEnableContextMenu) {
673 registerForContextMenu(mList);
674 } else {
675 unregisterForContextMenu(mList);
676 mList.setLongClickable(false);
677 }
678 }
679 }
John Reckc8490812010-11-22 14:15:36 -0800680
John Reck66302e52011-05-18 17:12:33 -0700681 private BookmarkDragController mDragController = new BookmarkDragController() {
682
683 @Override
684 public boolean startDrag(Cursor item) {
685 return canEdit(item);
686 }
687 };
688
John Reckc8490812010-11-22 14:15:36 -0800689 private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
690 Context mContext;
691 BookmarkItem mHeader;
692
693 public LookupBookmarkCount(Context context, BookmarkItem header) {
694 mContext = context;
695 mHeader = header;
696 }
697
698 @Override
699 protected Integer doInBackground(Long... params) {
700 if (params.length != 1) {
701 throw new IllegalArgumentException("Missing folder id!");
702 }
703 Uri uri = BookmarkUtils.getBookmarksUri(mContext);
704 Cursor c = mContext.getContentResolver().query(uri,
705 null, BrowserContract.Bookmarks.PARENT + "=?",
706 new String[] {params[0].toString()}, null);
707 return c.getCount();
708 }
709
710 @Override
711 protected void onPostExecute(Integer result) {
712 if (result > 0) {
713 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount,
714 result));
715 } else if (result == 0) {
716 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty));
717 }
718 }
719 }
John Reck89f73c12010-12-01 10:10:14 -0800720
John Reck71efc2b2011-05-09 16:54:28 -0700721 static class AccountsLoader extends CursorLoader {
John Reck89f73c12010-12-01 10:10:14 -0800722
John Reck71efc2b2011-05-09 16:54:28 -0700723 static String[] ACCOUNTS_PROJECTION = new String[] {
724 Accounts.ACCOUNT_NAME,
725 Accounts.ACCOUNT_TYPE
726 };
John Reck89f73c12010-12-01 10:10:14 -0800727
John Reck71efc2b2011-05-09 16:54:28 -0700728 public AccountsLoader(Context context) {
729 super(context, Accounts.CONTENT_URI, ACCOUNTS_PROJECTION, null, null,
730 Accounts.ACCOUNT_NAME + " ASC");
John Reck89f73c12010-12-01 10:10:14 -0800731 }
John Reck522a4382011-01-26 13:23:47 -0800732
John Reck522a4382011-01-26 13:23:47 -0800733 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800734}