blob: 2c38334a8c362d4ba226e5203b2e7f47f2b4ce58 [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;
John Reckb3417f02011-01-14 11:01:05 -080029import android.content.res.Configuration;
30import android.content.res.Resources;
Jeff Hamilton84029622010-08-05 14:29:28 -050031import android.database.Cursor;
The Android Open Source Project0c908882009-03-03 19:32:16 -080032import android.graphics.Bitmap;
Jeff Hamilton84029622010-08-05 14:29:28 -050033import android.graphics.BitmapFactory;
34import android.net.Uri;
John Reckc8490812010-11-22 14:15:36 -080035import android.os.AsyncTask;
The Android Open Source Project0c908882009-03-03 19:32:16 -080036import android.os.Bundle;
Jeff Hamilton69bd7072010-08-17 12:38:22 -050037import android.provider.BrowserContract;
John Reck71efc2b2011-05-09 16:54:28 -070038import android.provider.BrowserContract.Accounts;
John Reck1cebb442010-12-10 12:02:16 -080039import android.provider.BrowserContract.ChromeSyncColumns;
John Recke7c97de2011-05-27 14:42:43 -070040import android.view.ActionMode;
The Android Open Source Project0c908882009-03-03 19:32:16 -080041import android.view.ContextMenu;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050042import android.view.ContextMenu.ContextMenuInfo;
Jeff Hamilton64144e42010-08-18 16:31:59 -050043import android.view.LayoutInflater;
The Android Open Source Project0c908882009-03-03 19:32:16 -080044import android.view.MenuInflater;
45import android.view.MenuItem;
46import android.view.View;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050047import android.view.ViewGroup;
John Reck71efc2b2011-05-09 16:54:28 -070048import android.widget.ExpandableListView;
49import android.widget.ExpandableListView.OnChildClickListener;
John Recke7c97de2011-05-27 14:42:43 -070050import android.widget.ImageView;
51import android.widget.LinearLayout;
Jeff Hamilton84029622010-08-05 14:29:28 -050052import android.widget.Toast;
The Android Open Source Project0c908882009-03-03 19:32:16 -080053
John Recke7c97de2011-05-27 14:42:43 -070054import com.android.browser.BookmarkDragHandler.BookmarkDragController;
55import com.android.browser.BookmarkDragHandler.BookmarkDragState;
John Reck1e9815d2011-08-08 17:45:05 -070056import com.android.browser.provider.BrowserProvider2;
John Reck9db95292011-06-20 13:00:12 -070057import com.android.browser.view.BookmarkExpandableView;
58import com.android.browser.view.BookmarkExpandableView.BookmarkContextMenuInfo;
John Recke7c97de2011-05-27 14:42:43 -070059
John Reck71efc2b2011-05-09 16:54:28 -070060import java.util.HashMap;
61
John Reck608baa72010-11-24 10:32:28 -080062interface BookmarksPageCallbacks {
63 // Return true if handled
64 boolean onBookmarkSelected(Cursor c, boolean isFolder);
65 // Return true if handled
John Reckd3e4d5b2011-07-13 15:48:43 -070066 boolean onOpenInNewWindow(String... urls);
John Reck608baa72010-11-24 10:32:28 -080067}
68
The Android Open Source Project0c908882009-03-03 19:32:16 -080069/**
70 * View showing the user's bookmarks in the browser.
71 */
Jeff Hamilton64144e42010-08-18 16:31:59 -050072public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener,
John Reck9db95292011-06-20 13:00:12 -070073 LoaderManager.LoaderCallbacks<Cursor>, BreadCrumbView.Controller,
John Reckd3e4d5b2011-07-13 15:48:43 -070074 OnChildClickListener {
The Android Open Source Project0c908882009-03-03 19:32:16 -080075
John Recke7c97de2011-05-27 14:42:43 -070076 public static class ExtraDragState {
77 public int childPosition;
78 public int groupPosition;
79 }
80
Jeff Hamilton84029622010-08-05 14:29:28 -050081 static final String LOGTAG = "browser";
Nicolas Catania095292f2010-03-15 09:00:14 -070082
John Reck71efc2b2011-05-09 16:54:28 -070083 static final int LOADER_ACCOUNTS = 1;
84 static final int LOADER_BOOKMARKS = 100;
Jeff Hamilton84029622010-08-05 14:29:28 -050085
Michael Kolb801ecb72010-08-25 12:57:38 -070086 static final String EXTRA_DISABLE_WINDOW = "disable_new_window";
87
John Reck71efc2b2011-05-09 16:54:28 -070088 static final String ACCOUNT_TYPE = "account_type";
89 static final String ACCOUNT_NAME = "account_name";
90
John Reck9db95292011-06-20 13:00:12 -070091 public static final int VIEW_THUMBNAILS = 1;
92 public static final int VIEW_LIST = 2;
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 Reck9db95292011-06-20 13:00:12 -070096 BookmarkExpandableView mGrid;
Jeff Hamilton84029622010-08-05 14:29:28 -050097 boolean mDisableNewWindow;
John Reck608baa72010-11-24 10:32:28 -080098 boolean mEnableContextMenu = true;
Jeff Hamilton84029622010-08-05 14:29:28 -050099 View mEmptyView;
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
Jeff Hamilton84029622010-08-05 14:29:28 -0500104 @Override
105 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
John Reck71efc2b2011-05-09 16:54:28 -0700106 if (id == LOADER_ACCOUNTS) {
107 return new AccountsLoader(getActivity());
108 } else if (id >= LOADER_BOOKMARKS) {
109 String accountType = args.getString(ACCOUNT_TYPE);
110 String accountName = args.getString(ACCOUNT_NAME);
111 BookmarksLoader bl = new BookmarksLoader(getActivity(),
112 accountType, accountName);
113 return bl;
114 } else {
115 throw new UnsupportedOperationException("Unknown loader id " + id);
Jeff Hamilton84029622010-08-05 14:29:28 -0500116 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500117 }
118
119 @Override
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500120 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
John Reck71efc2b2011-05-09 16:54:28 -0700121 if (loader.getId() == LOADER_ACCOUNTS) {
122 LoaderManager lm = getLoaderManager();
123 int id = LOADER_BOOKMARKS;
124 while (cursor.moveToNext()) {
125 String accountName = cursor.getString(0);
126 String accountType = cursor.getString(1);
127 Bundle args = new Bundle();
128 args.putString(ACCOUNT_NAME, accountName);
129 args.putString(ACCOUNT_TYPE, accountType);
130 BrowserBookmarksAdapter adapter = new BrowserBookmarksAdapter(
John Reckd3e4d5b2011-07-13 15:48:43 -0700131 getActivity(), VIEW_THUMBNAILS);
John Reck71efc2b2011-05-09 16:54:28 -0700132 mBookmarkAdapters.put(id, adapter);
133 mGrid.addAccount(accountName, adapter);
134 lm.restartLoader(id, args, this);
135 id++;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500136 }
John Reck71efc2b2011-05-09 16:54:28 -0700137 // TODO: Figure out what a reload of these means
138 // Currently, a reload is triggered whenever bookmarks change
139 // This is less than ideal
140 // It also causes UI flickering as a new adapter is created
141 // instead of re-using an existing one when the account_name is the
142 // same.
143 // For now, this is a one-shot load
144 getLoaderManager().destroyLoader(LOADER_ACCOUNTS);
145 } else if (loader.getId() >= LOADER_BOOKMARKS) {
146 BrowserBookmarksAdapter adapter = mBookmarkAdapters.get(loader.getId());
147 adapter.changeCursor(cursor);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500148 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500149 }
150
John Reck522a4382011-01-26 13:23:47 -0800151 @Override
Dianne Hackborn39772c82010-12-16 00:43:54 -0800152 public void onLoaderReset(Loader<Cursor> loader) {
Dianne Hackborn39772c82010-12-16 00:43:54 -0800153 }
154
The Android Open Source Project0c908882009-03-03 19:32:16 -0800155 @Override
156 public boolean onContextItemSelected(MenuItem item) {
John Reck54ed3aa2011-08-19 15:16:05 -0700157 if (!(item.getMenuInfo() instanceof BookmarkContextMenuInfo)) {
158 return false;
159 }
160 BookmarkContextMenuInfo i = (BookmarkContextMenuInfo) item.getMenuInfo();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800161 // If we have no menu info, we can't tell which item was selected.
162 if (i == null) {
Leon Scrogginsc8cae082010-11-03 18:51:46 -0400163 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800164 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700165
John Recke7c97de2011-05-27 14:42:43 -0700166 if (handleContextItem(item.getItemId(), i.groupPosition, i.childPosition)) {
167 return true;
168 }
169 return super.onContextItemSelected(item);
170 }
171
172 public boolean handleContextItem(int itemId, int groupPosition,
173 int childPosition) {
174 final Activity activity = getActivity();
175 BrowserBookmarksAdapter adapter = getChildAdapter(groupPosition);
176
177 switch (itemId) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800178 case R.id.open_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700179 loadUrl(adapter, childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800180 break;
181 case R.id.edit_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700182 editBookmark(adapter, childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800183 break;
184 case R.id.shortcut_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700185 Cursor c = adapter.getItem(childPosition);
John Reck608baa72010-11-24 10:32:28 -0800186 activity.sendBroadcast(createShortcutIntent(getActivity(), c));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800187 break;
188 case R.id.delete_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700189 displayRemoveBookmarkDialog(adapter, childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800190 break;
191 case R.id.new_window_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700192 openInNewWindow(adapter, childPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800193 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500194 case R.id.share_link_context_menu_id: {
John Recke7c97de2011-05-27 14:42:43 -0700195 Cursor cursor = adapter.getItem(childPosition);
Michael Kolb8233fac2010-10-26 16:08:53 -0700196 Controller.sharePage(activity,
Jeff Hamilton84029622010-08-05 14:29:28 -0500197 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE),
198 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL),
199 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON),
200 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800201 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500202 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800203 case R.id.copy_url_context_menu_id:
John Recke7c97de2011-05-27 14:42:43 -0700204 copy(getUrl(adapter, childPosition));
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400205 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500206 case R.id.homepage_context_menu_id: {
John Recke7c97de2011-05-27 14:42:43 -0700207 BrowserSettings.getInstance().setHomePage(getUrl(adapter, childPosition));
Jeff Hamilton64144e42010-08-18 16:31:59 -0500208 Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400209 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500210 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400211 // Only for the Most visited page
Jeff Hamilton84029622010-08-05 14:29:28 -0500212 case R.id.save_to_bookmarks_menu_id: {
John Recke7c97de2011-05-27 14:42:43 -0700213 Cursor cursor = adapter.getItem(childPosition);
Jeff Hamilton84029622010-08-05 14:29:28 -0500214 String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
215 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400216 // If the site is bookmarked, the item becomes remove from
217 // bookmarks.
Jeff Hamilton64144e42010-08-18 16:31:59 -0500218 Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400219 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500220 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800221 default:
John Recke7c97de2011-05-27 14:42:43 -0700222 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800223 }
224 return true;
225 }
226
John Reck608baa72010-11-24 10:32:28 -0800227 static Bitmap getBitmap(Cursor cursor, int columnIndex) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500228 byte[] data = cursor.getBlob(columnIndex);
229 if (data == null) {
230 return null;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800231 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500232 return BitmapFactory.decodeByteArray(data, 0, data.length);
233 }
234
John Reckc8490812010-11-22 14:15:36 -0800235 private MenuItem.OnMenuItemClickListener mContextItemClickListener =
236 new MenuItem.OnMenuItemClickListener() {
237 @Override
238 public boolean onMenuItemClick(MenuItem item) {
239 return onContextItemSelected(item);
240 }
241 };
242
Jeff Hamilton84029622010-08-05 14:29:28 -0500243 @Override
244 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
John Reck71efc2b2011-05-09 16:54:28 -0700245 BookmarkContextMenuInfo info = (BookmarkContextMenuInfo) menuInfo;
246 BrowserBookmarksAdapter adapter = getChildAdapter(info.groupPosition);
247 Cursor cursor = adapter.getItem(info.childPosition);
John Reck1cebb442010-12-10 12:02:16 -0800248 if (!canEdit(cursor)) {
249 return;
250 }
Leon Scroggins5e8a40f2010-09-27 17:13:35 -0400251 boolean isFolder
252 = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
Michael Kolb801ecb72010-08-25 12:57:38 -0700253
Jeff Hamilton64144e42010-08-18 16:31:59 -0500254 final Activity activity = getActivity();
255 MenuInflater inflater = activity.getMenuInflater();
Jeff Hamilton84029622010-08-05 14:29:28 -0500256 inflater.inflate(R.menu.bookmarkscontext, menu);
John Reckc8490812010-11-22 14:15:36 -0800257 if (isFolder) {
258 menu.setGroupVisible(R.id.FOLDER_CONTEXT_MENU, true);
259 } else {
260 menu.setGroupVisible(R.id.BOOKMARK_CONTEXT_MENU, true);
261 if (mDisableNewWindow) {
262 menu.findItem(R.id.new_window_context_menu_id).setVisible(false);
263 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500264 }
John Reckc8490812010-11-22 14:15:36 -0800265 BookmarkItem header = new BookmarkItem(activity);
266 populateBookmarkItem(cursor, header, isFolder);
John Reckc8490812010-11-22 14:15:36 -0800267 menu.setHeaderView(header);
Jeff Hamilton84029622010-08-05 14:29:28 -0500268
John Reckc8490812010-11-22 14:15:36 -0800269 int count = menu.size();
270 for (int i = 0; i < count; i++) {
271 menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener);
Jeff Hamilton84029622010-08-05 14:29:28 -0500272 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500273 }
274
John Reck1cebb442010-12-10 12:02:16 -0800275 boolean canEdit(Cursor c) {
276 String unique = c.getString(BookmarksLoader.COLUMN_INDEX_SERVER_UNIQUE);
277 return !ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS.equals(unique);
278 }
279
John Reckc8490812010-11-22 14:15:36 -0800280 private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500281 item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
John Reckc8490812010-11-22 14:15:36 -0800282 if (isFolder) {
283 item.setUrl(null);
284 Bitmap bitmap =
Michael Kolb5a72f182011-01-13 20:35:06 -0800285 BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder_holo_dark);
John Reckc8490812010-11-22 14:15:36 -0800286 item.setFavicon(bitmap);
John Reck60e33362010-12-02 17:52:38 -0800287 new LookupBookmarkCount(getActivity(), item)
288 .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
John Reckc8490812010-11-22 14:15:36 -0800289 } else {
290 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
291 item.setUrl(url);
292 Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
John Reckc8490812010-11-22 14:15:36 -0800293 item.setFavicon(bitmap);
Jeff Hamilton84029622010-08-05 14:29:28 -0500294 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500295 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800296
297 /**
298 * Create a new BrowserBookmarksPage.
Nicolas Catania095292f2010-03-15 09:00:14 -0700299 */
The Android Open Source Project0c908882009-03-03 19:32:16 -0800300 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500301 public void onCreate(Bundle icicle) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800302 super.onCreate(icicle);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500303 Bundle args = getArguments();
Leon Scrogginsbc922852010-10-22 12:15:27 -0400304 mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
John Reck8f295d12011-03-18 15:25:18 -0700305 setHasOptionsMenu(true);
John Reck2d963a22011-08-10 15:53:07 -0700306 if (mCallbacks == null && getActivity() instanceof CombinedBookmarksCallbacks) {
307 mCallbacks = new CombinedBookmarksCallbackWrapper(
308 (CombinedBookmarksCallbacks) getActivity());
309 }
Jeff Hamilton64144e42010-08-18 16:31:59 -0500310 }
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400311
John Reck2d963a22011-08-10 15:53:07 -0700312 private static class CombinedBookmarksCallbackWrapper
313 implements BookmarksPageCallbacks {
314
315 private CombinedBookmarksCallbacks mCombinedCallback;
316
317 private CombinedBookmarksCallbackWrapper(CombinedBookmarksCallbacks cb) {
318 mCombinedCallback = cb;
319 }
320
321 @Override
322 public boolean onOpenInNewWindow(String... urls) {
323 mCombinedCallback.openInNewTab(urls);
324 return true;
325 }
326
327 @Override
328 public boolean onBookmarkSelected(Cursor c, boolean isFolder) {
329 if (isFolder) {
330 return false;
331 }
332 mCombinedCallback.openUrl(BrowserBookmarksPage.getUrl(c));
333 return true;
334 }
335 };
336
Jeff Hamilton64144e42010-08-18 16:31:59 -0500337 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500338 public View onCreateView(LayoutInflater inflater, ViewGroup container,
339 Bundle savedInstanceState) {
John Reck0ce8a942011-01-14 19:57:09 -0800340 mRoot = inflater.inflate(R.layout.bookmarks, container, false);
341 mEmptyView = mRoot.findViewById(android.R.id.empty);
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400342
John Reck9db95292011-06-20 13:00:12 -0700343 mGrid = (BookmarkExpandableView) mRoot.findViewById(R.id.grid);
John Reck71efc2b2011-05-09 16:54:28 -0700344 mGrid.setOnChildClickListener(this);
345 mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
346 mGrid.setBreadcrumbController(this);
John Reck608baa72010-11-24 10:32:28 -0800347 setEnableContextMenu(mEnableContextMenu);
John Reck66302e52011-05-18 17:12:33 -0700348 mDragHandler = new BookmarkDragHandler(getActivity(), mDragController,
349 mGrid.getDragAdapter());
John Reck608baa72010-11-24 10:32:28 -0800350
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500351 // Start the loaders
352 LoaderManager lm = getLoaderManager();
John Reck71efc2b2011-05-09 16:54:28 -0700353 lm.restartLoader(LOADER_ACCOUNTS, null, this);
Jeff Hamilton84029622010-08-05 14:29:28 -0500354
John Reck0ce8a942011-01-14 19:57:09 -0800355 return mRoot;
Jeff Hamilton64144e42010-08-18 16:31:59 -0500356 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700357
John Reck608baa72010-11-24 10:32:28 -0800358 @Override
359 public void onDestroyView() {
360 super.onDestroyView();
John Reck71efc2b2011-05-09 16:54:28 -0700361 mGrid.setBreadcrumbController(null);
362 LoaderManager lm = getLoaderManager();
363 lm.destroyLoader(LOADER_ACCOUNTS);
364 for (int id : mBookmarkAdapters.keySet()) {
365 lm.destroyLoader(id);
John Reck608baa72010-11-24 10:32:28 -0800366 }
John Reck71efc2b2011-05-09 16:54:28 -0700367 mBookmarkAdapters.clear();
John Reck71efc2b2011-05-09 16:54:28 -0700368 }
369
370 private BrowserBookmarksAdapter getChildAdapter(int groupPosition) {
John Reck9db95292011-06-20 13:00:12 -0700371 return mGrid.getChildAdapter(groupPosition);
John Reck71efc2b2011-05-09 16:54:28 -0700372 }
373
374 private BreadCrumbView getBreadCrumbs(int groupPosition) {
John Reck9db95292011-06-20 13:00:12 -0700375 return mGrid.getBreadCrumbs(groupPosition);
Nicolas Catania095292f2010-03-15 09:00:14 -0700376 }
377
Jeff Hamilton84029622010-08-05 14:29:28 -0500378 @Override
John Reck71efc2b2011-05-09 16:54:28 -0700379 public boolean onChildClick(ExpandableListView parent, View v,
380 int groupPosition, int childPosition, long id) {
381 BrowserBookmarksAdapter adapter = getChildAdapter(groupPosition);
382 Cursor cursor = adapter.getItem(childPosition);
John Reck608baa72010-11-24 10:32:28 -0800383 boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
384 if (mCallbacks != null &&
385 mCallbacks.onBookmarkSelected(cursor, isFolder)) {
John Reck71efc2b2011-05-09 16:54:28 -0700386 return true;
Ben Murdoch328ea872009-09-16 13:33:29 +0100387 }
388
John Reck71efc2b2011-05-09 16:54:28 -0700389 // TODO: Folder stuff
John Reck608baa72010-11-24 10:32:28 -0800390 if (isFolder) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700391 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500392 Uri uri = ContentUris.withAppendedId(
393 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
John Reck71efc2b2011-05-09 16:54:28 -0700394 BreadCrumbView crumbs = getBreadCrumbs(groupPosition);
395 if (crumbs != null) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700396 // update crumbs
John Reck71efc2b2011-05-09 16:54:28 -0700397 crumbs.pushView(title, uri);
Michael Kolb370a4f32010-10-06 10:45:32 -0700398 }
John Reck71efc2b2011-05-09 16:54:28 -0700399 loadFolder(groupPosition, uri);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400400 }
John Reck71efc2b2011-05-09 16:54:28 -0700401 return true;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800402 }
403
John Reck608baa72010-11-24 10:32:28 -0800404 /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500405 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Michael Kolbccaa8962010-10-20 17:03:10 -0700406 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500407 Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
408 Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
John Reck608baa72010-11-24 10:32:28 -0800409 return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800410 }
411
John Reck71efc2b2011-05-09 16:54:28 -0700412 private void loadUrl(BrowserBookmarksAdapter adapter, int position) {
413 if (mCallbacks != null && adapter != null) {
414 mCallbacks.onBookmarkSelected(adapter.getItem(position), false);
John Reck608baa72010-11-24 10:32:28 -0800415 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800416 }
417
John Reck71efc2b2011-05-09 16:54:28 -0700418 private void openInNewWindow(BrowserBookmarksAdapter adapter, int position) {
John Reck608baa72010-11-24 10:32:28 -0800419 if (mCallbacks != null) {
John Reck71efc2b2011-05-09 16:54:28 -0700420 Cursor c = adapter.getItem(position);
John Reck1b3c66e2011-01-11 13:20:32 -0800421 boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
422 if (isFolder) {
423 long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
424 new OpenAllInTabsTask(id).execute();
425 } else {
John Reckd3e4d5b2011-07-13 15:48:43 -0700426 mCallbacks.onOpenInNewWindow(BrowserBookmarksPage.getUrl(c));
John Reck1b3c66e2011-01-11 13:20:32 -0800427 }
John Reck608baa72010-11-24 10:32:28 -0800428 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800429 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700430
John Reck1b3c66e2011-01-11 13:20:32 -0800431 class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> {
432 long mFolderId;
433 public OpenAllInTabsTask(long id) {
434 mFolderId = id;
435 }
436
437 @Override
438 protected Cursor doInBackground(Void... params) {
439 Context c = getActivity();
440 if (c == null) return null;
441 return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c),
442 BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?",
443 new String[] { Long.toString(mFolderId) }, null);
444 }
445
446 @Override
447 protected void onPostExecute(Cursor result) {
John Reckd3e4d5b2011-07-13 15:48:43 -0700448 if (mCallbacks != null && result.getCount() > 0) {
449 String[] urls = new String[result.getCount()];
450 int i = 0;
John Reck1b3c66e2011-01-11 13:20:32 -0800451 while (result.moveToNext()) {
John Reckd3e4d5b2011-07-13 15:48:43 -0700452 urls[i++] = BrowserBookmarksPage.getUrl(result);
John Reck1b3c66e2011-01-11 13:20:32 -0800453 }
John Reckd3e4d5b2011-07-13 15:48:43 -0700454 mCallbacks.onOpenInNewWindow(urls);
John Reck1b3c66e2011-01-11 13:20:32 -0800455 }
456 }
457
458 }
459
John Reck71efc2b2011-05-09 16:54:28 -0700460 private void editBookmark(BrowserBookmarksAdapter adapter, int position) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500461 Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
John Reck71efc2b2011-05-09 16:54:28 -0700462 Cursor cursor = adapter.getItem(position);
Jeff Hamilton84029622010-08-05 14:29:28 -0500463 Bundle item = new Bundle();
Michael Kolbbef7a752010-08-25 17:11:35 -0700464 item.putString(BrowserContract.Bookmarks.TITLE,
Jeff Hamilton84029622010-08-05 14:29:28 -0500465 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
Michael Kolbbef7a752010-08-25 17:11:35 -0700466 item.putString(BrowserContract.Bookmarks.URL,
Jeff Hamilton84029622010-08-05 14:29:28 -0500467 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
468 byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
469 if (data != null) {
Michael Kolbbef7a752010-08-25 17:11:35 -0700470 item.putParcelable(BrowserContract.Bookmarks.FAVICON,
Jeff Hamilton84029622010-08-05 14:29:28 -0500471 BitmapFactory.decodeByteArray(data, 0, data.length));
472 }
John Reckc8490812010-11-22 14:15:36 -0800473 item.putLong(BrowserContract.Bookmarks._ID,
474 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
Leon Scroggins III052ce662010-09-13 14:44:16 -0400475 item.putLong(BrowserContract.Bookmarks.PARENT,
476 cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
John Reckc8490812010-11-22 14:15:36 -0800477 intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item);
478 intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER,
479 cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1);
480 startActivity(intent);
Jeff Hamilton84029622010-08-05 14:29:28 -0500481 }
482
John Reck71efc2b2011-05-09 16:54:28 -0700483 private void displayRemoveBookmarkDialog(BrowserBookmarksAdapter adapter,
484 int position) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800485 // Put up a dialog asking if the user really wants to
486 // delete the bookmark
John Reck71efc2b2011-05-09 16:54:28 -0700487 Cursor cursor = adapter.getItem(position);
Leon Scroggins75630672011-01-13 17:56:15 -0500488 long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
489 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500490 Context context = getActivity();
Leon Scroggins75630672011-01-13 17:56:15 -0500491 BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800492 }
493
John Reck71efc2b2011-05-09 16:54:28 -0700494 private String getUrl(BrowserBookmarksAdapter adapter, int position) {
495 return getUrl(adapter.getItem(position));
John Reck608baa72010-11-24 10:32:28 -0800496 }
497
498 /* package */ static String getUrl(Cursor c) {
499 return c.getString(BookmarksLoader.COLUMN_INDEX_URL);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800500 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700501
The Android Open Source Project0c908882009-03-03 19:32:16 -0800502 private void copy(CharSequence text) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500503 ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
504 Context.CLIPBOARD_SERVICE);
Dianne Hackbornbf1d10a2011-01-17 12:29:51 -0800505 cm.setPrimaryClip(ClipData.newRawUri(null, Uri.parse(text.toString())));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800506 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700507
John Reckb3417f02011-01-14 11:01:05 -0800508 @Override
John Reckb3417f02011-01-14 11:01:05 -0800509 public void onConfigurationChanged(Configuration newConfig) {
510 super.onConfigurationChanged(newConfig);
511 Resources res = getActivity().getResources();
John Reck71efc2b2011-05-09 16:54:28 -0700512 mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
John Reck0ce8a942011-01-14 19:57:09 -0800513 int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop);
John Reckf3828cd2011-06-14 17:21:55 -0700514 mRoot.setPadding(0, paddingTop, 0, 0);
John Reck9fdd9812011-05-17 14:16:38 -0700515 getActivity().invalidateOptionsMenu();
John Reckb3417f02011-01-14 11:01:05 -0800516 }
517
John Reck608baa72010-11-24 10:32:28 -0800518 /**
519 * BreadCrumb controller callback
520 */
521 @Override
John Reck71efc2b2011-05-09 16:54:28 -0700522 public void onTop(BreadCrumbView view, int level, Object data) {
523 int groupPosition = (Integer) view.getTag(R.id.group_position);
John Reck89f73c12010-12-01 10:10:14 -0800524 Uri uri = (Uri) data;
525 if (uri == null) {
526 // top level
527 uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
528 }
John Reck71efc2b2011-05-09 16:54:28 -0700529 loadFolder(groupPosition, uri);
John Reck89f73c12010-12-01 10:10:14 -0800530 }
531
532 /**
533 * @param uri
534 */
John Reck71efc2b2011-05-09 16:54:28 -0700535 private void loadFolder(int groupPosition, Uri uri) {
John Reck89f73c12010-12-01 10:10:14 -0800536 LoaderManager manager = getLoaderManager();
John Reck71efc2b2011-05-09 16:54:28 -0700537 // This assumes groups are ordered the same as loaders
538 BookmarksLoader loader = (BookmarksLoader) ((Loader<?>)
539 manager.getLoader(LOADER_BOOKMARKS + groupPosition));
John Reck89f73c12010-12-01 10:10:14 -0800540 loader.setUri(uri);
541 loader.forceLoad();
John Reck608baa72010-11-24 10:32:28 -0800542 }
543
John Reck608baa72010-11-24 10:32:28 -0800544 public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
545 mCallbacks = callbackListener;
546 }
547
548 public void setEnableContextMenu(boolean enable) {
549 mEnableContextMenu = enable;
550 if (mGrid != null) {
551 if (mEnableContextMenu) {
552 registerForContextMenu(mGrid);
553 } else {
554 unregisterForContextMenu(mGrid);
555 mGrid.setLongClickable(false);
556 }
557 }
John Reck608baa72010-11-24 10:32:28 -0800558 }
John Reckc8490812010-11-22 14:15:36 -0800559
John Reck66302e52011-05-18 17:12:33 -0700560 private BookmarkDragController mDragController = new BookmarkDragController() {
561
562 @Override
563 public boolean startDrag(Cursor item) {
564 return canEdit(item);
565 }
John Recke7c97de2011-05-27 14:42:43 -0700566
567 @Override
568 public ViewGroup getActionModeView(ActionMode mode,
569 BookmarkDragState state) {
570 LayoutInflater inflater = LayoutInflater.from(getActivity());
571 LinearLayout view = (LinearLayout) inflater.inflate(
572 R.layout.bookmarks_drag_actionmode, null);
573 view.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
574 ExtraDragState extraState = (ExtraDragState) state.extraState;
575 BrowserBookmarksAdapter adapter = getChildAdapter(extraState.groupPosition);
576 Cursor c = adapter.getItem(extraState.childPosition);
577 boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
578 if (isFolder) {
579 view.findViewById(R.id.open_context_menu_id).setVisibility(View.GONE);
580 ImageView iv = (ImageView) view.findViewById(
581 R.id.new_window_context_menu_id);
582 iv.setImageResource(R.drawable.ic_windows_holo_dark);
583 }
584 return view;
585 }
586
587 @Override
588 public void actionItemClicked(View v, BookmarkDragState state) {
589 if (v.getId() == R.id.info) {
John Reck9db95292011-06-20 13:00:12 -0700590 mGrid.showContextMenuForState(state);
John Recke7c97de2011-05-27 14:42:43 -0700591 } else {
592 ExtraDragState extraState = (ExtraDragState) state.extraState;
593 handleContextItem(v.getId(), extraState.groupPosition,
594 extraState.childPosition);
595 }
596 }
John Reck66302e52011-05-18 17:12:33 -0700597 };
598
John Reckc8490812010-11-22 14:15:36 -0800599 private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
600 Context mContext;
601 BookmarkItem mHeader;
602
603 public LookupBookmarkCount(Context context, BookmarkItem header) {
Ben Murdoch914c5592011-08-01 13:58:47 +0100604 mContext = context.getApplicationContext();
John Reckc8490812010-11-22 14:15:36 -0800605 mHeader = header;
606 }
607
608 @Override
609 protected Integer doInBackground(Long... params) {
610 if (params.length != 1) {
611 throw new IllegalArgumentException("Missing folder id!");
612 }
613 Uri uri = BookmarkUtils.getBookmarksUri(mContext);
614 Cursor c = mContext.getContentResolver().query(uri,
615 null, BrowserContract.Bookmarks.PARENT + "=?",
616 new String[] {params[0].toString()}, null);
617 return c.getCount();
618 }
619
620 @Override
621 protected void onPostExecute(Integer result) {
622 if (result > 0) {
623 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount,
624 result));
625 } else if (result == 0) {
626 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty));
627 }
628 }
629 }
John Reck89f73c12010-12-01 10:10:14 -0800630
John Reck71efc2b2011-05-09 16:54:28 -0700631 static class AccountsLoader extends CursorLoader {
John Reck89f73c12010-12-01 10:10:14 -0800632
John Reck71efc2b2011-05-09 16:54:28 -0700633 static String[] ACCOUNTS_PROJECTION = new String[] {
634 Accounts.ACCOUNT_NAME,
635 Accounts.ACCOUNT_TYPE
636 };
John Reck89f73c12010-12-01 10:10:14 -0800637
John Reck71efc2b2011-05-09 16:54:28 -0700638 public AccountsLoader(Context context) {
John Reck1e9815d2011-08-08 17:45:05 -0700639 super(context, Accounts.CONTENT_URI
640 .buildUpon()
641 .appendQueryParameter(BrowserProvider2.PARAM_ALLOW_EMPTY_ACCOUNTS, "false")
642 .build(),
643 ACCOUNTS_PROJECTION, null, null, null);
John Reck89f73c12010-12-01 10:10:14 -0800644 }
John Reck522a4382011-01-26 13:23:47 -0800645
John Reck522a4382011-01-26 13:23:47 -0800646 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800647}