blob: b6a50daf1adf26a645c42ef6e5e7c9767cebf48e [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
19import android.app.Activity;
Jeff Hamilton64144e42010-08-18 16:31:59 -050020import android.app.Fragment;
Jeff Hamilton84029622010-08-05 14:29:28 -050021import android.app.LoaderManager;
Dianne Hackborneb07b172010-08-26 22:18:14 -070022import android.content.ClipData;
Michael Kolbbef7a752010-08-25 17:11:35 -070023import android.content.ClipboardManager;
Jeff Hamilton84029622010-08-05 14:29:28 -050024import android.content.ContentUris;
Dianne Hackborn80f32622010-08-05 14:17:53 -070025import android.content.Context;
John Reck71efc2b2011-05-09 16:54:28 -070026import android.content.CursorLoader;
The Android Open Source Project0c908882009-03-03 19:32:16 -080027import android.content.Intent;
Jeff Hamilton84029622010-08-05 14:29:28 -050028import android.content.Loader;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050029import android.content.SharedPreferences;
John Reck8af90642010-11-23 10:27:29 -080030import android.content.SharedPreferences.Editor;
John Reckb3417f02011-01-14 11:01:05 -080031import android.content.res.Configuration;
32import android.content.res.Resources;
Jeff Hamilton84029622010-08-05 14:29:28 -050033import android.database.Cursor;
The Android Open Source Project0c908882009-03-03 19:32:16 -080034import android.graphics.Bitmap;
Jeff Hamilton84029622010-08-05 14:29:28 -050035import android.graphics.BitmapFactory;
36import android.net.Uri;
John Reckc8490812010-11-22 14:15:36 -080037import android.os.AsyncTask;
The Android Open Source Project0c908882009-03-03 19:32:16 -080038import android.os.Bundle;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050039import android.preference.PreferenceManager;
Jeff Hamilton69bd7072010-08-17 12:38:22 -050040import android.provider.BrowserContract;
John Reck71efc2b2011-05-09 16:54:28 -070041import android.provider.BrowserContract.Accounts;
John Reck1cebb442010-12-10 12:02:16 -080042import android.provider.BrowserContract.ChromeSyncColumns;
John Recke7c97de2011-05-27 14:42:43 -070043import android.view.ActionMode;
The Android Open Source Project0c908882009-03-03 19:32:16 -080044import android.view.ContextMenu;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050045import android.view.ContextMenu.ContextMenuInfo;
Jeff Hamilton64144e42010-08-18 16:31:59 -050046import android.view.LayoutInflater;
John Reckb3417f02011-01-14 11:01:05 -080047import android.view.Menu;
The Android Open Source Project0c908882009-03-03 19:32:16 -080048import android.view.MenuInflater;
49import android.view.MenuItem;
50import android.view.View;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050051import android.view.ViewGroup;
John Reck71efc2b2011-05-09 16:54:28 -070052import android.widget.ExpandableListView;
53import android.widget.ExpandableListView.OnChildClickListener;
John Recke7c97de2011-05-27 14:42:43 -070054import android.widget.ImageView;
55import android.widget.LinearLayout;
John Reck608baa72010-11-24 10:32:28 -080056import android.widget.PopupMenu.OnMenuItemClickListener;
Jeff Hamilton84029622010-08-05 14:29:28 -050057import android.widget.Toast;
The Android Open Source Project0c908882009-03-03 19:32:16 -080058
John Recke7c97de2011-05-27 14:42:43 -070059import com.android.browser.BookmarkDragHandler.BookmarkDragController;
60import com.android.browser.BookmarkDragHandler.BookmarkDragState;
John Reck9db95292011-06-20 13:00:12 -070061import com.android.browser.view.BookmarkExpandableView;
62import com.android.browser.view.BookmarkExpandableView.BookmarkContextMenuInfo;
John Recke7c97de2011-05-27 14:42:43 -070063
John Reck71efc2b2011-05-09 16:54:28 -070064import java.util.HashMap;
65
John Reck608baa72010-11-24 10:32:28 -080066interface BookmarksPageCallbacks {
67 // Return true if handled
68 boolean onBookmarkSelected(Cursor c, boolean isFolder);
69 // Return true if handled
70 boolean onOpenInNewWindow(Cursor c);
71}
72
The Android Open Source Project0c908882009-03-03 19:32:16 -080073/**
74 * View showing the user's bookmarks in the browser.
75 */
Jeff Hamilton64144e42010-08-18 16:31:59 -050076public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener,
John Reck9db95292011-06-20 13:00:12 -070077 LoaderManager.LoaderCallbacks<Cursor>, BreadCrumbView.Controller,
78 OnMenuItemClickListener, OnChildClickListener {
The Android Open Source Project0c908882009-03-03 19:32:16 -080079
John Recke7c97de2011-05-27 14:42:43 -070080 public static class ExtraDragState {
81 public int childPosition;
82 public int groupPosition;
83 }
84
Jeff Hamilton84029622010-08-05 14:29:28 -050085 static final String LOGTAG = "browser";
Nicolas Catania095292f2010-03-15 09:00:14 -070086
John Reck71efc2b2011-05-09 16:54:28 -070087 static final int LOADER_ACCOUNTS = 1;
88 static final int LOADER_BOOKMARKS = 100;
Jeff Hamilton84029622010-08-05 14:29:28 -050089
Michael Kolb801ecb72010-08-25 12:57:38 -070090 static final String EXTRA_DISABLE_WINDOW = "disable_new_window";
91
John Reck71efc2b2011-05-09 16:54:28 -070092 static final String ACCOUNT_TYPE = "account_type";
93 static final String ACCOUNT_NAME = "account_name";
94
John Reck9db95292011-06-20 13:00:12 -070095 public static final int VIEW_THUMBNAILS = 1;
96 public static final int VIEW_LIST = 2;
John Reck8af90642010-11-23 10:27:29 -080097 static final String PREF_SELECTED_VIEW = "bookmarks_view";
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050098
John Reck608baa72010-11-24 10:32:28 -080099 BookmarksPageCallbacks mCallbacks;
John Reck0ce8a942011-01-14 19:57:09 -0800100 View mRoot;
John Reck9db95292011-06-20 13:00:12 -0700101 BookmarkExpandableView mGrid;
Jeff Hamilton84029622010-08-05 14:29:28 -0500102 boolean mDisableNewWindow;
John Reck608baa72010-11-24 10:32:28 -0800103 boolean mEnableContextMenu = true;
Jeff Hamilton84029622010-08-05 14:29:28 -0500104 View mEmptyView;
John Reck8af90642010-11-23 10:27:29 -0800105 int mCurrentView;
John Reck608baa72010-11-24 10:32:28 -0800106 View mHeader;
John Reck71efc2b2011-05-09 16:54:28 -0700107 HashMap<Integer, BrowserBookmarksAdapter> mBookmarkAdapters = new HashMap<Integer, BrowserBookmarksAdapter>();
John Reck66302e52011-05-18 17:12:33 -0700108 BookmarkDragHandler mDragHandler;
Michael Kolb370a4f32010-10-06 10:45:32 -0700109
John Reck608baa72010-11-24 10:32:28 -0800110 static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb,
111 Bundle args, ViewGroup headerContainer) {
Michael Kolbe421c242010-10-04 19:29:01 -0700112 BrowserBookmarksPage bbp = new BrowserBookmarksPage();
113 bbp.mCallbacks = cb;
114 bbp.setArguments(args);
115 return bbp;
116 }
117
Jeff Hamilton84029622010-08-05 14:29:28 -0500118 @Override
119 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
John Reck71efc2b2011-05-09 16:54:28 -0700120 if (id == LOADER_ACCOUNTS) {
121 return new AccountsLoader(getActivity());
122 } else if (id >= LOADER_BOOKMARKS) {
123 String accountType = args.getString(ACCOUNT_TYPE);
124 String accountName = args.getString(ACCOUNT_NAME);
125 BookmarksLoader bl = new BookmarksLoader(getActivity(),
126 accountType, accountName);
127 return bl;
128 } else {
129 throw new UnsupportedOperationException("Unknown loader id " + id);
Jeff Hamilton84029622010-08-05 14:29:28 -0500130 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500131 }
132
133 @Override
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500134 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
John Reck71efc2b2011-05-09 16:54:28 -0700135 if (loader.getId() == LOADER_ACCOUNTS) {
136 LoaderManager lm = getLoaderManager();
137 int id = LOADER_BOOKMARKS;
138 while (cursor.moveToNext()) {
139 String accountName = cursor.getString(0);
140 String accountType = cursor.getString(1);
141 Bundle args = new Bundle();
142 args.putString(ACCOUNT_NAME, accountName);
143 args.putString(ACCOUNT_TYPE, accountType);
144 BrowserBookmarksAdapter adapter = new BrowserBookmarksAdapter(
145 getActivity(), mCurrentView);
146 mBookmarkAdapters.put(id, adapter);
147 mGrid.addAccount(accountName, adapter);
148 lm.restartLoader(id, args, this);
149 id++;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500150 }
John Reck71efc2b2011-05-09 16:54:28 -0700151 // TODO: Figure out what a reload of these means
152 // Currently, a reload is triggered whenever bookmarks change
153 // This is less than ideal
154 // It also causes UI flickering as a new adapter is created
155 // instead of re-using an existing one when the account_name is the
156 // same.
157 // For now, this is a one-shot load
158 getLoaderManager().destroyLoader(LOADER_ACCOUNTS);
159 } else if (loader.getId() >= LOADER_BOOKMARKS) {
160 BrowserBookmarksAdapter adapter = mBookmarkAdapters.get(loader.getId());
161 adapter.changeCursor(cursor);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500162 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500163 }
164
John Reck522a4382011-01-26 13:23:47 -0800165 @Override
Dianne Hackborn39772c82010-12-16 00:43:54 -0800166 public void onLoaderReset(Loader<Cursor> loader) {
Dianne Hackborn39772c82010-12-16 00:43:54 -0800167 }
168
The Android Open Source Project0c908882009-03-03 19:32:16 -0800169 @Override
170 public boolean onContextItemSelected(MenuItem item) {
John Reck71efc2b2011-05-09 16:54:28 -0700171 BookmarkContextMenuInfo i = (BookmarkContextMenuInfo)item.getMenuInfo();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800172 // If we have no menu info, we can't tell which item was selected.
173 if (i == null) {
Leon Scrogginsc8cae082010-11-03 18:51:46 -0400174 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800175 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700176
John Recke7c97de2011-05-27 14:42:43 -0700177 if (handleContextItem(item.getItemId(), i.groupPosition, i.childPosition)) {
178 return true;
179 }
180 return super.onContextItemSelected(item);
181 }
182
183 public boolean handleContextItem(int itemId, int groupPosition,
184 int childPosition) {
185 final Activity activity = getActivity();
186 BrowserBookmarksAdapter adapter = getChildAdapter(groupPosition);
187
188 switch (itemId) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800189 case R.id.open_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700190 loadUrl(adapter, childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800191 break;
192 case R.id.edit_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700193 editBookmark(adapter, childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800194 break;
195 case R.id.shortcut_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700196 Cursor c = adapter.getItem(childPosition);
John Reck608baa72010-11-24 10:32:28 -0800197 activity.sendBroadcast(createShortcutIntent(getActivity(), c));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800198 break;
199 case R.id.delete_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700200 displayRemoveBookmarkDialog(adapter, childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800201 break;
202 case R.id.new_window_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700203 openInNewWindow(adapter, childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800204 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500205 case R.id.share_link_context_menu_id: {
John Recke7c97de2011-05-27 14:42:43 -0700206 Cursor cursor = adapter.getItem(childPosition);
Michael Kolb8233fac2010-10-26 16:08:53 -0700207 Controller.sharePage(activity,
Jeff Hamilton84029622010-08-05 14:29:28 -0500208 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE),
209 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL),
210 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON),
211 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800212 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500213 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800214 case R.id.copy_url_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700215 copy(getUrl(adapter, childPosition));
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400216 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500217 case R.id.homepage_context_menu_id: {
John Recke7c97de2011-05-27 14:42:43 -0700218 BrowserSettings.getInstance().setHomePage(getUrl(adapter, childPosition));
Jeff Hamilton64144e42010-08-18 16:31:59 -0500219 Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400220 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500221 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400222 // Only for the Most visited page
Jeff Hamilton84029622010-08-05 14:29:28 -0500223 case R.id.save_to_bookmarks_menu_id: {
John Recke7c97de2011-05-27 14:42:43 -0700224 Cursor cursor = adapter.getItem(childPosition);
Jeff Hamilton84029622010-08-05 14:29:28 -0500225 String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
226 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400227 // If the site is bookmarked, the item becomes remove from
228 // bookmarks.
Jeff Hamilton64144e42010-08-18 16:31:59 -0500229 Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400230 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500231 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800232 default:
John Recke7c97de2011-05-27 14:42:43 -0700233 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800234 }
235 return true;
236 }
237
John Reck608baa72010-11-24 10:32:28 -0800238 static Bitmap getBitmap(Cursor cursor, int columnIndex) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500239 byte[] data = cursor.getBlob(columnIndex);
240 if (data == null) {
241 return null;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800242 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500243 return BitmapFactory.decodeByteArray(data, 0, data.length);
244 }
245
John Reckc8490812010-11-22 14:15:36 -0800246 private MenuItem.OnMenuItemClickListener mContextItemClickListener =
247 new MenuItem.OnMenuItemClickListener() {
248 @Override
249 public boolean onMenuItemClick(MenuItem item) {
250 return onContextItemSelected(item);
251 }
252 };
253
Jeff Hamilton84029622010-08-05 14:29:28 -0500254 @Override
John Reckb3417f02011-01-14 11:01:05 -0800255 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
256 inflater.inflate(R.menu.bookmark, menu);
257 }
258
259 @Override
Jeff Hamilton84029622010-08-05 14:29:28 -0500260 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
John Reck71efc2b2011-05-09 16:54:28 -0700261 BookmarkContextMenuInfo info = (BookmarkContextMenuInfo) menuInfo;
262 BrowserBookmarksAdapter adapter = getChildAdapter(info.groupPosition);
263 Cursor cursor = adapter.getItem(info.childPosition);
John Reck1cebb442010-12-10 12:02:16 -0800264 if (!canEdit(cursor)) {
265 return;
266 }
Leon Scroggins5e8a40f2010-09-27 17:13:35 -0400267 boolean isFolder
268 = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
Michael Kolb801ecb72010-08-25 12:57:38 -0700269
Jeff Hamilton64144e42010-08-18 16:31:59 -0500270 final Activity activity = getActivity();
271 MenuInflater inflater = activity.getMenuInflater();
Jeff Hamilton84029622010-08-05 14:29:28 -0500272 inflater.inflate(R.menu.bookmarkscontext, menu);
John Reckc8490812010-11-22 14:15:36 -0800273 if (isFolder) {
274 menu.setGroupVisible(R.id.FOLDER_CONTEXT_MENU, true);
275 } else {
276 menu.setGroupVisible(R.id.BOOKMARK_CONTEXT_MENU, true);
277 if (mDisableNewWindow) {
278 menu.findItem(R.id.new_window_context_menu_id).setVisible(false);
279 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500280 }
John Reckc8490812010-11-22 14:15:36 -0800281 BookmarkItem header = new BookmarkItem(activity);
282 populateBookmarkItem(cursor, header, isFolder);
John Reckc8490812010-11-22 14:15:36 -0800283 menu.setHeaderView(header);
Jeff Hamilton84029622010-08-05 14:29:28 -0500284
John Reckc8490812010-11-22 14:15:36 -0800285 int count = menu.size();
286 for (int i = 0; i < count; i++) {
287 menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener);
Jeff Hamilton84029622010-08-05 14:29:28 -0500288 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500289 }
290
John Reck1cebb442010-12-10 12:02:16 -0800291 boolean canEdit(Cursor c) {
292 String unique = c.getString(BookmarksLoader.COLUMN_INDEX_SERVER_UNIQUE);
293 return !ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS.equals(unique);
294 }
295
John Reckc8490812010-11-22 14:15:36 -0800296 private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500297 item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
John Reckc8490812010-11-22 14:15:36 -0800298 if (isFolder) {
299 item.setUrl(null);
300 Bitmap bitmap =
Michael Kolb5a72f182011-01-13 20:35:06 -0800301 BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder_holo_dark);
John Reckc8490812010-11-22 14:15:36 -0800302 item.setFavicon(bitmap);
John Reck60e33362010-12-02 17:52:38 -0800303 new LookupBookmarkCount(getActivity(), item)
304 .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
John Reckc8490812010-11-22 14:15:36 -0800305 } else {
306 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
307 item.setUrl(url);
308 Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
309 if (bitmap == null) {
310 bitmap = CombinedBookmarkHistoryView.getIconListenerSet().getFavicon(url);
311 }
312 item.setFavicon(bitmap);
Jeff Hamilton84029622010-08-05 14:29:28 -0500313 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500314 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800315
316 /**
317 * Create a new BrowserBookmarksPage.
Nicolas Catania095292f2010-03-15 09:00:14 -0700318 */
The Android Open Source Project0c908882009-03-03 19:32:16 -0800319 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500320 public void onCreate(Bundle icicle) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800321 super.onCreate(icicle);
John Reck8f295d12011-03-18 15:25:18 -0700322 SharedPreferences prefs = PreferenceManager
John Reck71efc2b2011-05-09 16:54:28 -0700323 .getDefaultSharedPreferences(getActivity());
John Reck8f295d12011-03-18 15:25:18 -0700324 mCurrentView = prefs.getInt(PREF_SELECTED_VIEW, getDefaultView());
John Reckb3417f02011-01-14 11:01:05 -0800325
Jeff Hamilton64144e42010-08-18 16:31:59 -0500326 Bundle args = getArguments();
Leon Scrogginsbc922852010-10-22 12:15:27 -0400327 mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
John Reck8f295d12011-03-18 15:25:18 -0700328
329 setHasOptionsMenu(true);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500330 }
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400331
Jeff Hamilton64144e42010-08-18 16:31:59 -0500332 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500333 public View onCreateView(LayoutInflater inflater, ViewGroup container,
334 Bundle savedInstanceState) {
John Reck0ce8a942011-01-14 19:57:09 -0800335 mRoot = inflater.inflate(R.layout.bookmarks, container, false);
336 mEmptyView = mRoot.findViewById(android.R.id.empty);
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400337
John Reck9db95292011-06-20 13:00:12 -0700338 mGrid = (BookmarkExpandableView) mRoot.findViewById(R.id.grid);
John Reck71efc2b2011-05-09 16:54:28 -0700339 mGrid.setOnChildClickListener(this);
340 mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
341 mGrid.setBreadcrumbController(this);
John Reck608baa72010-11-24 10:32:28 -0800342 setEnableContextMenu(mEnableContextMenu);
John Reck66302e52011-05-18 17:12:33 -0700343 mDragHandler = new BookmarkDragHandler(getActivity(), mDragController,
344 mGrid.getDragAdapter());
John Reck608baa72010-11-24 10:32:28 -0800345
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500346 // Start the loaders
347 LoaderManager lm = getLoaderManager();
John Reck71efc2b2011-05-09 16:54:28 -0700348 lm.restartLoader(LOADER_ACCOUNTS, null, this);
Jeff Hamilton84029622010-08-05 14:29:28 -0500349
John Reck0ce8a942011-01-14 19:57:09 -0800350 return mRoot;
Jeff Hamilton64144e42010-08-18 16:31:59 -0500351 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700352
John Reck9d27ff52011-02-11 17:47:54 -0800353 private int getDefaultView() {
John Recka5176f32011-05-17 12:35:37 -0700354 if (BrowserActivity.isTablet(getActivity())) {
John Reck9d27ff52011-02-11 17:47:54 -0800355 return VIEW_THUMBNAILS;
356 }
357 return VIEW_LIST;
358 }
359
John Reck608baa72010-11-24 10:32:28 -0800360 @Override
361 public void onDestroyView() {
362 super.onDestroyView();
John Reck71efc2b2011-05-09 16:54:28 -0700363 mGrid.setBreadcrumbController(null);
364 LoaderManager lm = getLoaderManager();
365 lm.destroyLoader(LOADER_ACCOUNTS);
366 for (int id : mBookmarkAdapters.keySet()) {
367 lm.destroyLoader(id);
John Reck608baa72010-11-24 10:32:28 -0800368 }
John Reck71efc2b2011-05-09 16:54:28 -0700369 mBookmarkAdapters.clear();
John Reck71efc2b2011-05-09 16:54:28 -0700370 }
371
372 private BrowserBookmarksAdapter getChildAdapter(int groupPosition) {
John Reck9db95292011-06-20 13:00:12 -0700373 return mGrid.getChildAdapter(groupPosition);
John Reck71efc2b2011-05-09 16:54:28 -0700374 }
375
376 private BreadCrumbView getBreadCrumbs(int groupPosition) {
John Reck9db95292011-06-20 13:00:12 -0700377 return mGrid.getBreadCrumbs(groupPosition);
Nicolas Catania095292f2010-03-15 09:00:14 -0700378 }
379
Jeff Hamilton84029622010-08-05 14:29:28 -0500380 @Override
John Reck71efc2b2011-05-09 16:54:28 -0700381 public boolean onChildClick(ExpandableListView parent, View v,
382 int groupPosition, int childPosition, long id) {
383 BrowserBookmarksAdapter adapter = getChildAdapter(groupPosition);
384 Cursor cursor = adapter.getItem(childPosition);
John Reck608baa72010-11-24 10:32:28 -0800385 boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
386 if (mCallbacks != null &&
387 mCallbacks.onBookmarkSelected(cursor, isFolder)) {
John Reck71efc2b2011-05-09 16:54:28 -0700388 return true;
Ben Murdoch328ea872009-09-16 13:33:29 +0100389 }
390
John Reck71efc2b2011-05-09 16:54:28 -0700391 // TODO: Folder stuff
John Reck608baa72010-11-24 10:32:28 -0800392 if (isFolder) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700393 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500394 Uri uri = ContentUris.withAppendedId(
395 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
John Reck71efc2b2011-05-09 16:54:28 -0700396 BreadCrumbView crumbs = getBreadCrumbs(groupPosition);
397 if (crumbs != null) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700398 // update crumbs
John Reck71efc2b2011-05-09 16:54:28 -0700399 crumbs.pushView(title, uri);
Michael Kolb370a4f32010-10-06 10:45:32 -0700400 }
John Reck71efc2b2011-05-09 16:54:28 -0700401 loadFolder(groupPosition, uri);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400402 }
John Reck71efc2b2011-05-09 16:54:28 -0700403 return true;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800404 }
405
John Reck608baa72010-11-24 10:32:28 -0800406 /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500407 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Michael Kolbccaa8962010-10-20 17:03:10 -0700408 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500409 Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
410 Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
John Reck608baa72010-11-24 10:32:28 -0800411 return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800412 }
413
John Reck71efc2b2011-05-09 16:54:28 -0700414 private void loadUrl(BrowserBookmarksAdapter adapter, int position) {
415 if (mCallbacks != null && adapter != null) {
416 mCallbacks.onBookmarkSelected(adapter.getItem(position), false);
John Reck608baa72010-11-24 10:32:28 -0800417 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800418 }
419
John Reck71efc2b2011-05-09 16:54:28 -0700420 private void openInNewWindow(BrowserBookmarksAdapter adapter, int position) {
John Reck608baa72010-11-24 10:32:28 -0800421 if (mCallbacks != null) {
John Reck71efc2b2011-05-09 16:54:28 -0700422 Cursor c = adapter.getItem(position);
John Reck1b3c66e2011-01-11 13:20:32 -0800423 boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
424 if (isFolder) {
425 long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
426 new OpenAllInTabsTask(id).execute();
427 } else {
428 mCallbacks.onOpenInNewWindow(c);
429 }
John Reck608baa72010-11-24 10:32:28 -0800430 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800431 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700432
John Reck1b3c66e2011-01-11 13:20:32 -0800433 class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> {
434 long mFolderId;
435 public OpenAllInTabsTask(long id) {
436 mFolderId = id;
437 }
438
439 @Override
440 protected Cursor doInBackground(Void... params) {
441 Context c = getActivity();
442 if (c == null) return null;
443 return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c),
444 BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?",
445 new String[] { Long.toString(mFolderId) }, null);
446 }
447
448 @Override
449 protected void onPostExecute(Cursor result) {
450 if (mCallbacks != null) {
451 while (result.moveToNext()) {
452 mCallbacks.onOpenInNewWindow(result);
453 }
454 }
455 }
456
457 }
458
John Reck71efc2b2011-05-09 16:54:28 -0700459 private void editBookmark(BrowserBookmarksAdapter adapter, int position) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500460 Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
John Reck71efc2b2011-05-09 16:54:28 -0700461 Cursor cursor = adapter.getItem(position);
Jeff Hamilton84029622010-08-05 14:29:28 -0500462 Bundle item = new Bundle();
Michael Kolbbef7a752010-08-25 17:11:35 -0700463 item.putString(BrowserContract.Bookmarks.TITLE,
Jeff Hamilton84029622010-08-05 14:29:28 -0500464 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
Michael Kolbbef7a752010-08-25 17:11:35 -0700465 item.putString(BrowserContract.Bookmarks.URL,
Jeff Hamilton84029622010-08-05 14:29:28 -0500466 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
467 byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
468 if (data != null) {
Michael Kolbbef7a752010-08-25 17:11:35 -0700469 item.putParcelable(BrowserContract.Bookmarks.FAVICON,
Jeff Hamilton84029622010-08-05 14:29:28 -0500470 BitmapFactory.decodeByteArray(data, 0, data.length));
471 }
John Reckc8490812010-11-22 14:15:36 -0800472 item.putLong(BrowserContract.Bookmarks._ID,
473 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
Leon Scroggins III052ce662010-09-13 14:44:16 -0400474 item.putLong(BrowserContract.Bookmarks.PARENT,
475 cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
John Reckc8490812010-11-22 14:15:36 -0800476 intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item);
477 intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER,
478 cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1);
479 startActivity(intent);
Jeff Hamilton84029622010-08-05 14:29:28 -0500480 }
481
John Reck71efc2b2011-05-09 16:54:28 -0700482 private void displayRemoveBookmarkDialog(BrowserBookmarksAdapter adapter,
483 int position) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800484 // Put up a dialog asking if the user really wants to
485 // delete the bookmark
John Reck71efc2b2011-05-09 16:54:28 -0700486 Cursor cursor = adapter.getItem(position);
Leon Scroggins75630672011-01-13 17:56:15 -0500487 long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
488 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500489 Context context = getActivity();
Leon Scroggins75630672011-01-13 17:56:15 -0500490 BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800491 }
492
John Reck71efc2b2011-05-09 16:54:28 -0700493 private String getUrl(BrowserBookmarksAdapter adapter, int position) {
494 return getUrl(adapter.getItem(position));
John Reck608baa72010-11-24 10:32:28 -0800495 }
496
497 /* package */ static String getUrl(Cursor c) {
498 return c.getString(BookmarksLoader.COLUMN_INDEX_URL);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800499 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700500
The Android Open Source Project0c908882009-03-03 19:32:16 -0800501 private void copy(CharSequence text) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500502 ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
503 Context.CLIPBOARD_SERVICE);
Dianne Hackbornbf1d10a2011-01-17 12:29:51 -0800504 cm.setPrimaryClip(ClipData.newRawUri(null, Uri.parse(text.toString())));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800505 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700506
John Reckb3417f02011-01-14 11:01:05 -0800507 @Override
508 public boolean onOptionsItemSelected(MenuItem item) {
509 switch (item.getItemId()) {
510 case R.id.thumbnail_view:
511 selectView(VIEW_THUMBNAILS);
512 return true;
513 case R.id.list_view:
514 selectView(VIEW_LIST);
515 return true;
516 }
517 return super.onOptionsItemSelected(item);
518 }
519
520 @Override
521 public void onConfigurationChanged(Configuration newConfig) {
522 super.onConfigurationChanged(newConfig);
523 Resources res = getActivity().getResources();
John Reck71efc2b2011-05-09 16:54:28 -0700524 mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
John Reck0ce8a942011-01-14 19:57:09 -0800525 int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop);
John Reckf3828cd2011-06-14 17:21:55 -0700526 mRoot.setPadding(0, paddingTop, 0, 0);
John Reck9fdd9812011-05-17 14:16:38 -0700527 getActivity().invalidateOptionsMenu();
John Reckb3417f02011-01-14 11:01:05 -0800528 }
529
530 @Override
531 public void onPrepareOptionsMenu(Menu menu) {
532 super.onPrepareOptionsMenu(menu);
533 menu.findItem(R.id.list_view).setVisible(mCurrentView != VIEW_LIST);
534 menu.findItem(R.id.thumbnail_view).setVisible(mCurrentView != VIEW_THUMBNAILS);
535 }
536
John Reck8af90642010-11-23 10:27:29 -0800537 void selectView(int view) {
538 if (view == mCurrentView) {
539 return;
540 }
John Reck9db95292011-06-20 13:00:12 -0700541 mCurrentView = view;
John Reck8af90642010-11-23 10:27:29 -0800542 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
543 Editor edit = prefs.edit();
544 edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
545 edit.apply();
546 if (mEmptyView.getVisibility() == View.VISIBLE) {
547 return;
548 }
John Reck9db95292011-06-20 13:00:12 -0700549 mGrid.selectView(mCurrentView);
John Reck8af90642010-11-23 10:27:29 -0800550 }
John Reck608baa72010-11-24 10:32:28 -0800551
John Reck608baa72010-11-24 10:32:28 -0800552 /**
553 * BreadCrumb controller callback
554 */
555 @Override
John Reck71efc2b2011-05-09 16:54:28 -0700556 public void onTop(BreadCrumbView view, int level, Object data) {
557 int groupPosition = (Integer) view.getTag(R.id.group_position);
John Reck89f73c12010-12-01 10:10:14 -0800558 Uri uri = (Uri) data;
559 if (uri == null) {
560 // top level
561 uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
562 }
John Reck71efc2b2011-05-09 16:54:28 -0700563 loadFolder(groupPosition, uri);
John Reck89f73c12010-12-01 10:10:14 -0800564 }
565
566 /**
567 * @param uri
568 */
John Reck71efc2b2011-05-09 16:54:28 -0700569 private void loadFolder(int groupPosition, Uri uri) {
John Reck89f73c12010-12-01 10:10:14 -0800570 LoaderManager manager = getLoaderManager();
John Reck71efc2b2011-05-09 16:54:28 -0700571 // This assumes groups are ordered the same as loaders
572 BookmarksLoader loader = (BookmarksLoader) ((Loader<?>)
573 manager.getLoader(LOADER_BOOKMARKS + groupPosition));
John Reck89f73c12010-12-01 10:10:14 -0800574 loader.setUri(uri);
575 loader.forceLoad();
John Reck608baa72010-11-24 10:32:28 -0800576 }
577
578 @Override
John Reck608baa72010-11-24 10:32:28 -0800579 public boolean onMenuItemClick(MenuItem item) {
580 switch (item.getItemId()) {
581 case R.id.list_view:
John Reck608baa72010-11-24 10:32:28 -0800582 selectView(BrowserBookmarksPage.VIEW_LIST);
583 return true;
584 case R.id.thumbnail_view:
John Reck608baa72010-11-24 10:32:28 -0800585 selectView(BrowserBookmarksPage.VIEW_THUMBNAILS);
586 return true;
587 }
588 return false;
589 }
590
591 public boolean onBackPressed() {
John Reck608baa72010-11-24 10:32:28 -0800592 return false;
593 }
594
595 public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
596 mCallbacks = callbackListener;
597 }
598
599 public void setEnableContextMenu(boolean enable) {
600 mEnableContextMenu = enable;
601 if (mGrid != null) {
602 if (mEnableContextMenu) {
603 registerForContextMenu(mGrid);
604 } else {
605 unregisterForContextMenu(mGrid);
606 mGrid.setLongClickable(false);
607 }
608 }
John Reck608baa72010-11-24 10:32:28 -0800609 }
John Reckc8490812010-11-22 14:15:36 -0800610
John Reck66302e52011-05-18 17:12:33 -0700611 private BookmarkDragController mDragController = new BookmarkDragController() {
612
613 @Override
614 public boolean startDrag(Cursor item) {
615 return canEdit(item);
616 }
John Recke7c97de2011-05-27 14:42:43 -0700617
618 @Override
619 public ViewGroup getActionModeView(ActionMode mode,
620 BookmarkDragState state) {
621 LayoutInflater inflater = LayoutInflater.from(getActivity());
622 LinearLayout view = (LinearLayout) inflater.inflate(
623 R.layout.bookmarks_drag_actionmode, null);
624 view.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
625 ExtraDragState extraState = (ExtraDragState) state.extraState;
626 BrowserBookmarksAdapter adapter = getChildAdapter(extraState.groupPosition);
627 Cursor c = adapter.getItem(extraState.childPosition);
628 boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
629 if (isFolder) {
630 view.findViewById(R.id.open_context_menu_id).setVisibility(View.GONE);
631 ImageView iv = (ImageView) view.findViewById(
632 R.id.new_window_context_menu_id);
633 iv.setImageResource(R.drawable.ic_windows_holo_dark);
634 }
635 return view;
636 }
637
638 @Override
639 public void actionItemClicked(View v, BookmarkDragState state) {
640 if (v.getId() == R.id.info) {
John Reck9db95292011-06-20 13:00:12 -0700641 mGrid.showContextMenuForState(state);
John Recke7c97de2011-05-27 14:42:43 -0700642 } else {
643 ExtraDragState extraState = (ExtraDragState) state.extraState;
644 handleContextItem(v.getId(), extraState.groupPosition,
645 extraState.childPosition);
646 }
647 }
John Reck66302e52011-05-18 17:12:33 -0700648 };
649
John Reckc8490812010-11-22 14:15:36 -0800650 private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
651 Context mContext;
652 BookmarkItem mHeader;
653
654 public LookupBookmarkCount(Context context, BookmarkItem header) {
655 mContext = context;
656 mHeader = header;
657 }
658
659 @Override
660 protected Integer doInBackground(Long... params) {
661 if (params.length != 1) {
662 throw new IllegalArgumentException("Missing folder id!");
663 }
664 Uri uri = BookmarkUtils.getBookmarksUri(mContext);
665 Cursor c = mContext.getContentResolver().query(uri,
666 null, BrowserContract.Bookmarks.PARENT + "=?",
667 new String[] {params[0].toString()}, null);
668 return c.getCount();
669 }
670
671 @Override
672 protected void onPostExecute(Integer result) {
673 if (result > 0) {
674 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount,
675 result));
676 } else if (result == 0) {
677 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty));
678 }
679 }
680 }
John Reck89f73c12010-12-01 10:10:14 -0800681
John Reck71efc2b2011-05-09 16:54:28 -0700682 static class AccountsLoader extends CursorLoader {
John Reck89f73c12010-12-01 10:10:14 -0800683
John Reck71efc2b2011-05-09 16:54:28 -0700684 static String[] ACCOUNTS_PROJECTION = new String[] {
685 Accounts.ACCOUNT_NAME,
686 Accounts.ACCOUNT_TYPE
687 };
John Reck89f73c12010-12-01 10:10:14 -0800688
John Reck71efc2b2011-05-09 16:54:28 -0700689 public AccountsLoader(Context context) {
690 super(context, Accounts.CONTENT_URI, ACCOUNTS_PROJECTION, null, null,
691 Accounts.ACCOUNT_NAME + " ASC");
John Reck89f73c12010-12-01 10:10:14 -0800692 }
John Reck522a4382011-01-26 13:23:47 -0800693
John Reck522a4382011-01-26 13:23:47 -0800694 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800695}