blob: 1dc26121652b37d611e6272bbe73424ae74c7a4b [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 Reckd4893b02010-12-07 17:38:34 -080019import com.android.browser.BreadCrumbView.Crumb;
20
The Android Open Source Project0c908882009-03-03 19:32:16 -080021import android.app.Activity;
Jeff Hamilton64144e42010-08-18 16:31:59 -050022import android.app.Fragment;
Jeff Hamilton84029622010-08-05 14:29:28 -050023import android.app.LoaderManager;
Dianne Hackborneb07b172010-08-26 22:18:14 -070024import android.content.ClipData;
Michael Kolbbef7a752010-08-25 17:11:35 -070025import android.content.ClipboardManager;
Jeff Hamilton84029622010-08-05 14:29:28 -050026import android.content.ContentUris;
Dianne Hackborn80f32622010-08-05 14:17:53 -070027import android.content.Context;
The Android Open Source Project0c908882009-03-03 19:32:16 -080028import android.content.Intent;
Jeff Hamilton84029622010-08-05 14:29:28 -050029import android.content.Loader;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050030import android.content.SharedPreferences;
John Reck8af90642010-11-23 10:27:29 -080031import android.content.SharedPreferences.Editor;
John Reck522a4382011-01-26 13:23:47 -080032import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
John Reckb3417f02011-01-14 11:01:05 -080033import android.content.res.Configuration;
34import android.content.res.Resources;
Jeff Hamilton84029622010-08-05 14:29:28 -050035import android.database.Cursor;
The Android Open Source Project0c908882009-03-03 19:32:16 -080036import android.graphics.Bitmap;
Jeff Hamilton84029622010-08-05 14:29:28 -050037import android.graphics.BitmapFactory;
38import android.net.Uri;
John Reckc8490812010-11-22 14:15:36 -080039import android.os.AsyncTask;
The Android Open Source Project0c908882009-03-03 19:32:16 -080040import android.os.Bundle;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050041import android.preference.PreferenceManager;
Jeff Hamilton69bd7072010-08-17 12:38:22 -050042import android.provider.BrowserContract;
John Reck1cebb442010-12-10 12:02:16 -080043import android.provider.BrowserContract.ChromeSyncColumns;
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;
Patrick Scottc1cf63a2010-03-09 16:02:08 -050052import android.webkit.WebIconDatabase.IconListener;
The Android Open Source Project0c908882009-03-03 19:32:16 -080053import android.widget.AdapterView;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050054import android.widget.AdapterView.OnItemClickListener;
Jeff Hamilton84029622010-08-05 14:29:28 -050055import android.widget.GridView;
John Reck8af90642010-11-23 10:27:29 -080056import android.widget.ListView;
John Reck608baa72010-11-24 10:32:28 -080057import android.widget.PopupMenu.OnMenuItemClickListener;
Jeff Hamilton84029622010-08-05 14:29:28 -050058import android.widget.Toast;
The Android Open Source Project0c908882009-03-03 19:32:16 -080059
John Reck608baa72010-11-24 10:32:28 -080060interface BookmarksPageCallbacks {
61 // Return true if handled
62 boolean onBookmarkSelected(Cursor c, boolean isFolder);
63 // Return true if handled
64 boolean onOpenInNewWindow(Cursor c);
John Reck89f73c12010-12-01 10:10:14 -080065 void onFolderChanged(int level, Uri uri);
John Reck608baa72010-11-24 10:32:28 -080066}
67
The Android Open Source Project0c908882009-03-03 19:32:16 -080068/**
69 * View showing the user's bookmarks in the browser.
70 */
Jeff Hamilton64144e42010-08-18 16:31:59 -050071public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener,
Michael Kolb370a4f32010-10-06 10:45:32 -070072 LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, IconListener,
John Reck522a4382011-01-26 13:23:47 -080073 BreadCrumbView.Controller, OnMenuItemClickListener, OnSharedPreferenceChangeListener {
The Android Open Source Project0c908882009-03-03 19:32:16 -080074
Jeff Hamilton84029622010-08-05 14:29:28 -050075 static final String LOGTAG = "browser";
Nicolas Catania095292f2010-03-15 09:00:14 -070076
Jeff Hamilton84029622010-08-05 14:29:28 -050077 static final int LOADER_BOOKMARKS = 1;
78
Michael Kolb801ecb72010-08-25 12:57:38 -070079 static final String EXTRA_DISABLE_WINDOW = "disable_new_window";
80
Jeff Hamilton70c77692010-09-21 19:11:24 -050081 static final String ACCOUNT_NAME_UNSYNCED = "Unsynced";
Michael Kolbe421c242010-10-04 19:29:01 -070082
Jeff Hamilton7f6cf3e2010-09-17 17:22:21 -050083 public static final String PREF_ACCOUNT_TYPE = "acct_type";
84 public static final String PREF_ACCOUNT_NAME = "acct_name";
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050085
John Reck8af90642010-11-23 10:27:29 -080086 static final int VIEW_THUMBNAILS = 1;
87 static final int VIEW_LIST = 2;
88 static final String PREF_SELECTED_VIEW = "bookmarks_view";
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050089
John Reck608baa72010-11-24 10:32:28 -080090 BookmarksPageCallbacks mCallbacks;
John Reck0ce8a942011-01-14 19:57:09 -080091 View mRoot;
Jeff Hamilton84029622010-08-05 14:29:28 -050092 GridView mGrid;
John Reck8af90642010-11-23 10:27:29 -080093 ListView mList;
Jeff Hamilton84029622010-08-05 14:29:28 -050094 BrowserBookmarksAdapter mAdapter;
95 boolean mDisableNewWindow;
Jeff Hamilton84029622010-08-05 14:29:28 -050096 boolean mCanceled = false;
John Reck608baa72010-11-24 10:32:28 -080097 boolean mEnableContextMenu = true;
98 boolean mShowRootFolder = false;
Jeff Hamilton84029622010-08-05 14:29:28 -050099 View mEmptyView;
John Reck8af90642010-11-23 10:27:29 -0800100 int mCurrentView;
John Reck608baa72010-11-24 10:32:28 -0800101 View mHeader;
John Reck608baa72010-11-24 10:32:28 -0800102 ViewGroup mHeaderContainer;
Michael Kolb370a4f32010-10-06 10:45:32 -0700103 BreadCrumbView mCrumbs;
John Reck89f73c12010-12-01 10:10:14 -0800104 int mCrumbVisibility = View.VISIBLE;
105 int mCrumbMaxVisible = -1;
106 boolean mCrumbBackButton = false;
Michael Kolb370a4f32010-10-06 10:45:32 -0700107
John Reck608baa72010-11-24 10:32:28 -0800108 static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb,
109 Bundle args, ViewGroup headerContainer) {
Michael Kolbe421c242010-10-04 19:29:01 -0700110 BrowserBookmarksPage bbp = new BrowserBookmarksPage();
111 bbp.mCallbacks = cb;
John Reck608baa72010-11-24 10:32:28 -0800112 bbp.mHeaderContainer = headerContainer;
Michael Kolbe421c242010-10-04 19:29:01 -0700113 bbp.setArguments(args);
114 return bbp;
115 }
116
Jeff Hamilton84029622010-08-05 14:29:28 -0500117 @Override
118 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
119 switch (id) {
120 case LOADER_BOOKMARKS: {
John Reck522a4382011-01-26 13:23:47 -0800121 SharedPreferences prefs = PreferenceManager
122 .getDefaultSharedPreferences(getActivity());
123 String accountType = prefs.getString(PREF_ACCOUNT_TYPE, null);
124 String accountName = prefs.getString(PREF_ACCOUNT_NAME, null);
125 BookmarksLoader bl = new BookmarksLoader(getActivity(),
126 accountType, accountName);
Michael Kolb370a4f32010-10-06 10:45:32 -0700127 if (mCrumbs != null) {
128 Uri uri = (Uri) mCrumbs.getTopData();
129 if (uri != null) {
130 bl.setUri(uri);
131 }
132 }
133 return bl;
Jeff Hamilton84029622010-08-05 14:29:28 -0500134 }
135 }
136 throw new UnsupportedOperationException("Unknown loader id " + id);
137 }
138
139 @Override
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500140 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
141 switch (loader.getId()) {
142 case LOADER_BOOKMARKS: {
143 // Set the visibility of the empty vs. content views
144 if (cursor == null || cursor.getCount() == 0) {
145 mEmptyView.setVisibility(View.VISIBLE);
146 mGrid.setVisibility(View.GONE);
John Reck8af90642010-11-23 10:27:29 -0800147 mList.setVisibility(View.GONE);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500148 } else {
149 mEmptyView.setVisibility(View.GONE);
John Reck8af90642010-11-23 10:27:29 -0800150 setupBookmarkView();
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500151 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500152
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500153 // Give the new data to the adapter
154 mAdapter.changeCursor(cursor);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500155 break;
156 }
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500157 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500158 }
159
John Reck522a4382011-01-26 13:23:47 -0800160 @Override
Dianne Hackborn39772c82010-12-16 00:43:54 -0800161 public void onLoaderReset(Loader<Cursor> loader) {
162 onLoadFinished(loader, null);
Dianne Hackborn39772c82010-12-16 00:43:54 -0800163 }
164
Michael Kolb370a4f32010-10-06 10:45:32 -0700165 long getFolderId() {
166 LoaderManager manager = getLoaderManager();
167 BookmarksLoader loader =
John Reck608baa72010-11-24 10:32:28 -0800168 (BookmarksLoader) ((Loader<?>)manager.getLoader(LOADER_BOOKMARKS));
Michael Kolb370a4f32010-10-06 10:45:32 -0700169
170 Uri uri = loader.getUri();
171 if (uri != null) {
172 try {
173 return ContentUris.parseId(uri);
174 } catch (NumberFormatException nfx) {
175 return -1;
176 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500177 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700178 return -1;
179 }
180
The Android Open Source Project0c908882009-03-03 19:32:16 -0800181 @Override
182 public boolean onContextItemSelected(MenuItem item) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500183 final Activity activity = getActivity();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800184 // It is possible that the view has been canceled when we get to
Nicolas Catania095292f2010-03-15 09:00:14 -0700185 // this point as back has a higher priority
The Android Open Source Project0c908882009-03-03 19:32:16 -0800186 if (mCanceled) {
Leon Scrogginsc8cae082010-11-03 18:51:46 -0400187 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800188 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700189 AdapterView.AdapterContextMenuInfo i =
The Android Open Source Project0c908882009-03-03 19:32:16 -0800190 (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
191 // If we have no menu info, we can't tell which item was selected.
192 if (i == null) {
Leon Scrogginsc8cae082010-11-03 18:51:46 -0400193 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800194 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700195
The Android Open Source Project0c908882009-03-03 19:32:16 -0800196 switch (item.getItemId()) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800197 case R.id.open_context_menu_id:
198 loadUrl(i.position);
199 break;
200 case R.id.edit_context_menu_id:
201 editBookmark(i.position);
202 break;
203 case R.id.shortcut_context_menu_id:
John Reck608baa72010-11-24 10:32:28 -0800204 Cursor c = mAdapter.getItem(i.position);
205 activity.sendBroadcast(createShortcutIntent(getActivity(), c));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800206 break;
207 case R.id.delete_context_menu_id:
Jeff Hamilton84029622010-08-05 14:29:28 -0500208 displayRemoveBookmarkDialog(i.position);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800209 break;
210 case R.id.new_window_context_menu_id:
211 openInNewWindow(i.position);
212 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500213 case R.id.share_link_context_menu_id: {
John Reck608baa72010-11-24 10:32:28 -0800214 Cursor cursor = mAdapter.getItem(i.position);
Michael Kolb8233fac2010-10-26 16:08:53 -0700215 Controller.sharePage(activity,
Jeff Hamilton84029622010-08-05 14:29:28 -0500216 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE),
217 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL),
218 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON),
219 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800220 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500221 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800222 case R.id.copy_url_context_menu_id:
223 copy(getUrl(i.position));
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400224 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500225 case R.id.homepage_context_menu_id: {
John Reck35e9dd62011-04-25 09:01:54 -0700226 BrowserSettings.getInstance().setHomePage(getUrl(i.position));
Jeff Hamilton64144e42010-08-18 16:31:59 -0500227 Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400228 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500229 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400230 // Only for the Most visited page
Jeff Hamilton84029622010-08-05 14:29:28 -0500231 case R.id.save_to_bookmarks_menu_id: {
John Reck608baa72010-11-24 10:32:28 -0800232 Cursor cursor = mAdapter.getItem(i.position);
Jeff Hamilton84029622010-08-05 14:29:28 -0500233 String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
234 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400235 // If the site is bookmarked, the item becomes remove from
236 // bookmarks.
Jeff Hamilton64144e42010-08-18 16:31:59 -0500237 Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400238 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500239 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800240 default:
241 return super.onContextItemSelected(item);
242 }
243 return true;
244 }
245
John Reck608baa72010-11-24 10:32:28 -0800246 static Bitmap getBitmap(Cursor cursor, int columnIndex) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500247 byte[] data = cursor.getBlob(columnIndex);
248 if (data == null) {
249 return null;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800250 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500251 return BitmapFactory.decodeByteArray(data, 0, data.length);
252 }
253
John Reckc8490812010-11-22 14:15:36 -0800254 private MenuItem.OnMenuItemClickListener mContextItemClickListener =
255 new MenuItem.OnMenuItemClickListener() {
256 @Override
257 public boolean onMenuItemClick(MenuItem item) {
258 return onContextItemSelected(item);
259 }
260 };
261
Jeff Hamilton84029622010-08-05 14:29:28 -0500262 @Override
John Reckb3417f02011-01-14 11:01:05 -0800263 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
264 inflater.inflate(R.menu.bookmark, menu);
John Reck9d27ff52011-02-11 17:47:54 -0800265 if (!BrowserActivity.isXlarge(getActivity())) {
266 MenuItem item = menu.findItem(R.id.add_bookmark);
267 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
268 }
John Reckb3417f02011-01-14 11:01:05 -0800269 }
270
271 @Override
Jeff Hamilton84029622010-08-05 14:29:28 -0500272 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
273 AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
John Reck608baa72010-11-24 10:32:28 -0800274 Cursor cursor = mAdapter.getItem(info.position);
John Reck1cebb442010-12-10 12:02:16 -0800275 if (!canEdit(cursor)) {
276 return;
277 }
Leon Scroggins5e8a40f2010-09-27 17:13:35 -0400278 boolean isFolder
279 = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
Michael Kolb801ecb72010-08-25 12:57:38 -0700280
Jeff Hamilton64144e42010-08-18 16:31:59 -0500281 final Activity activity = getActivity();
282 MenuInflater inflater = activity.getMenuInflater();
Jeff Hamilton84029622010-08-05 14:29:28 -0500283 inflater.inflate(R.menu.bookmarkscontext, menu);
John Reckc8490812010-11-22 14:15:36 -0800284 if (isFolder) {
285 menu.setGroupVisible(R.id.FOLDER_CONTEXT_MENU, true);
286 } else {
287 menu.setGroupVisible(R.id.BOOKMARK_CONTEXT_MENU, true);
288 if (mDisableNewWindow) {
289 menu.findItem(R.id.new_window_context_menu_id).setVisible(false);
290 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500291 }
John Reckc8490812010-11-22 14:15:36 -0800292 BookmarkItem header = new BookmarkItem(activity);
293 populateBookmarkItem(cursor, header, isFolder);
John Reckc8490812010-11-22 14:15:36 -0800294 menu.setHeaderView(header);
Jeff Hamilton84029622010-08-05 14:29:28 -0500295
John Reckc8490812010-11-22 14:15:36 -0800296 int count = menu.size();
297 for (int i = 0; i < count; i++) {
298 menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener);
Jeff Hamilton84029622010-08-05 14:29:28 -0500299 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500300 }
301
John Reck1cebb442010-12-10 12:02:16 -0800302 boolean canEdit(Cursor c) {
303 String unique = c.getString(BookmarksLoader.COLUMN_INDEX_SERVER_UNIQUE);
304 return !ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS.equals(unique);
305 }
306
John Reckc8490812010-11-22 14:15:36 -0800307 private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500308 item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
John Reckc8490812010-11-22 14:15:36 -0800309 if (isFolder) {
310 item.setUrl(null);
311 Bitmap bitmap =
Michael Kolb5a72f182011-01-13 20:35:06 -0800312 BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder_holo_dark);
John Reckc8490812010-11-22 14:15:36 -0800313 item.setFavicon(bitmap);
John Reck60e33362010-12-02 17:52:38 -0800314 new LookupBookmarkCount(getActivity(), item)
315 .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
John Reckc8490812010-11-22 14:15:36 -0800316 } else {
317 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
318 item.setUrl(url);
319 Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
320 if (bitmap == null) {
321 bitmap = CombinedBookmarkHistoryView.getIconListenerSet().getFavicon(url);
322 }
323 item.setFavicon(bitmap);
Jeff Hamilton84029622010-08-05 14:29:28 -0500324 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500325 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800326
327 /**
328 * Create a new BrowserBookmarksPage.
Nicolas Catania095292f2010-03-15 09:00:14 -0700329 */
The Android Open Source Project0c908882009-03-03 19:32:16 -0800330 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500331 public void onCreate(Bundle icicle) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800332 super.onCreate(icicle);
333
John Reck8f295d12011-03-18 15:25:18 -0700334 SharedPreferences prefs = PreferenceManager
335 .getDefaultSharedPreferences(getActivity());
336 prefs.registerOnSharedPreferenceChangeListener(this);
337 mCurrentView = prefs.getInt(PREF_SELECTED_VIEW, getDefaultView());
John Reckb3417f02011-01-14 11:01:05 -0800338
Jeff Hamilton64144e42010-08-18 16:31:59 -0500339 Bundle args = getArguments();
Leon Scrogginsbc922852010-10-22 12:15:27 -0400340 mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
John Reck8f295d12011-03-18 15:25:18 -0700341
342 setHasOptionsMenu(true);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500343 }
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400344
Jeff Hamilton64144e42010-08-18 16:31:59 -0500345 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500346 public View onCreateView(LayoutInflater inflater, ViewGroup container,
347 Bundle savedInstanceState) {
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500348 Context context = getActivity();
349
John Reck0ce8a942011-01-14 19:57:09 -0800350 mRoot = inflater.inflate(R.layout.bookmarks, container, false);
351 mEmptyView = mRoot.findViewById(android.R.id.empty);
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400352
John Reck0ce8a942011-01-14 19:57:09 -0800353 mGrid = (GridView) mRoot.findViewById(R.id.grid);
Jeff Hamilton84029622010-08-05 14:29:28 -0500354 mGrid.setOnItemClickListener(this);
Michael Kolb8233fac2010-10-26 16:08:53 -0700355 mGrid.setColumnWidth(Controller.getDesiredThumbnailWidth(getActivity()));
John Reck0ce8a942011-01-14 19:57:09 -0800356 mList = (ListView) mRoot.findViewById(R.id.list);
John Reck8af90642010-11-23 10:27:29 -0800357 mList.setOnItemClickListener(this);
John Reck608baa72010-11-24 10:32:28 -0800358 setEnableContextMenu(mEnableContextMenu);
359
360 // Prep the header
361 ViewGroup hc = mHeaderContainer;
362 if (hc == null) {
John Reck0ce8a942011-01-14 19:57:09 -0800363 hc = (ViewGroup) mRoot.findViewById(R.id.header_container);
John Reck608baa72010-11-24 10:32:28 -0800364 hc.setVisibility(View.VISIBLE);
John Reck8af90642010-11-23 10:27:29 -0800365 }
John Reckf2057c22010-12-03 18:11:50 -0800366 mHeader = inflater.inflate(R.layout.bookmarks_header, hc, false);
367 hc.addView(mHeader);
John Reck608baa72010-11-24 10:32:28 -0800368 mCrumbs = (BreadCrumbView) mHeader.findViewById(R.id.crumbs);
369 mCrumbs.setController(this);
John Reck89f73c12010-12-01 10:10:14 -0800370 mCrumbs.setUseBackButton(mCrumbBackButton);
371 mCrumbs.setMaxVisible(mCrumbMaxVisible);
372 mCrumbs.setVisibility(mCrumbVisibility);
373 String name = getString(R.string.bookmarks);
374 mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
375 if (mCallbacks != null) {
376 mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
377 }
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500378 // Start the loaders
379 LoaderManager lm = getLoaderManager();
John Reck8af90642010-11-23 10:27:29 -0800380 mAdapter = new BrowserBookmarksAdapter(getActivity(), mCurrentView);
John Reck522a4382011-01-26 13:23:47 -0800381 lm.restartLoader(LOADER_BOOKMARKS, null, this);
Jeff Hamilton84029622010-08-05 14:29:28 -0500382
383 // Add our own listener in case there are favicons that have yet to be loaded.
Michael Kolbe421c242010-10-04 19:29:01 -0700384 CombinedBookmarkHistoryView.getIconListenerSet().addListener(this);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800385
John Reck0ce8a942011-01-14 19:57:09 -0800386 return mRoot;
Jeff Hamilton64144e42010-08-18 16:31:59 -0500387 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700388
John Reck9d27ff52011-02-11 17:47:54 -0800389 private int getDefaultView() {
390 if (BrowserActivity.isXlarge(getActivity())) {
391 return VIEW_THUMBNAILS;
392 }
393 return VIEW_LIST;
394 }
395
John Reck608baa72010-11-24 10:32:28 -0800396 @Override
397 public void onDestroyView() {
398 super.onDestroyView();
John Reck522a4382011-01-26 13:23:47 -0800399 SharedPreferences prefs = PreferenceManager
400 .getDefaultSharedPreferences(getActivity());
401 prefs.unregisterOnSharedPreferenceChangeListener(this);
John Reck608baa72010-11-24 10:32:28 -0800402 if (mHeaderContainer != null) {
403 mHeaderContainer.removeView(mHeader);
404 }
405 mCrumbs.setController(null);
406 mCrumbs = null;
Dianne Hackborn71e76c72010-12-20 11:44:09 -0800407 getLoaderManager().destroyLoader(LOADER_BOOKMARKS);
John Recke3063ae2011-01-27 14:57:40 -0800408 mAdapter = null;
409 CombinedBookmarkHistoryView.getIconListenerSet().removeListener(this);
John Reck608baa72010-11-24 10:32:28 -0800410 }
411
Nicolas Catania095292f2010-03-15 09:00:14 -0700412 @Override
Jeff Hamilton84029622010-08-05 14:29:28 -0500413 public void onReceivedIcon(String url, Bitmap icon) {
414 // A new favicon has been loaded, so let anything attached to the adapter know about it
415 // so new icons will be loaded.
416 mAdapter.notifyDataSetChanged();
Nicolas Catania095292f2010-03-15 09:00:14 -0700417 }
418
Jeff Hamilton84029622010-08-05 14:29:28 -0500419 @Override
John Reck608baa72010-11-24 10:32:28 -0800420 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500421 // It is possible that the view has been canceled when we get to
422 // this point as back has a higher priority
423 if (mCanceled) {
424 android.util.Log.e(LOGTAG, "item clicked when dismissing");
425 return;
426 }
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500427
John Reck608baa72010-11-24 10:32:28 -0800428 Cursor cursor = mAdapter.getItem(position);
429 boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
430 if (mCallbacks != null &&
431 mCallbacks.onBookmarkSelected(cursor, isFolder)) {
Ben Murdoch328ea872009-09-16 13:33:29 +0100432 return;
433 }
434
John Reck608baa72010-11-24 10:32:28 -0800435 if (isFolder) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700436 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500437 Uri uri = ContentUris.withAppendedId(
438 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
Michael Kolb370a4f32010-10-06 10:45:32 -0700439 if (mCrumbs != null) {
440 // update crumbs
441 mCrumbs.pushView(title, uri);
442 }
John Reck89f73c12010-12-01 10:10:14 -0800443 loadFolder(uri);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400444 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800445 }
446
John Reck608baa72010-11-24 10:32:28 -0800447 /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500448 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Michael Kolbccaa8962010-10-20 17:03:10 -0700449 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500450 Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
451 Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
John Reck608baa72010-11-24 10:32:28 -0800452 return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800453 }
454
The Android Open Source Project0c908882009-03-03 19:32:16 -0800455 private void loadUrl(int position) {
John Reckde631892011-03-14 18:03:53 -0700456 if (mCallbacks != null && mAdapter != null) {
John Reck608baa72010-11-24 10:32:28 -0800457 mCallbacks.onBookmarkSelected(mAdapter.getItem(position), false);
458 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800459 }
460
The Android Open Source Project0c908882009-03-03 19:32:16 -0800461 private void openInNewWindow(int position) {
John Reck608baa72010-11-24 10:32:28 -0800462 if (mCallbacks != null) {
John Reck1b3c66e2011-01-11 13:20:32 -0800463 Cursor c = mAdapter.getItem(position);
464 boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
465 if (isFolder) {
466 long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
467 new OpenAllInTabsTask(id).execute();
468 } else {
469 mCallbacks.onOpenInNewWindow(c);
470 }
John Reck608baa72010-11-24 10:32:28 -0800471 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800472 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700473
John Reck1b3c66e2011-01-11 13:20:32 -0800474 class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> {
475 long mFolderId;
476 public OpenAllInTabsTask(long id) {
477 mFolderId = id;
478 }
479
480 @Override
481 protected Cursor doInBackground(Void... params) {
482 Context c = getActivity();
483 if (c == null) return null;
484 return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c),
485 BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?",
486 new String[] { Long.toString(mFolderId) }, null);
487 }
488
489 @Override
490 protected void onPostExecute(Cursor result) {
491 if (mCallbacks != null) {
492 while (result.moveToNext()) {
493 mCallbacks.onOpenInNewWindow(result);
494 }
495 }
496 }
497
498 }
499
The Android Open Source Project0c908882009-03-03 19:32:16 -0800500 private void editBookmark(int position) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500501 Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
John Reck608baa72010-11-24 10:32:28 -0800502 Cursor cursor = mAdapter.getItem(position);
Jeff Hamilton84029622010-08-05 14:29:28 -0500503 Bundle item = new Bundle();
Michael Kolbbef7a752010-08-25 17:11:35 -0700504 item.putString(BrowserContract.Bookmarks.TITLE,
Jeff Hamilton84029622010-08-05 14:29:28 -0500505 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
Michael Kolbbef7a752010-08-25 17:11:35 -0700506 item.putString(BrowserContract.Bookmarks.URL,
Jeff Hamilton84029622010-08-05 14:29:28 -0500507 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
508 byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
509 if (data != null) {
Michael Kolbbef7a752010-08-25 17:11:35 -0700510 item.putParcelable(BrowserContract.Bookmarks.FAVICON,
Jeff Hamilton84029622010-08-05 14:29:28 -0500511 BitmapFactory.decodeByteArray(data, 0, data.length));
512 }
John Reckc8490812010-11-22 14:15:36 -0800513 item.putLong(BrowserContract.Bookmarks._ID,
514 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
Leon Scroggins III052ce662010-09-13 14:44:16 -0400515 item.putLong(BrowserContract.Bookmarks.PARENT,
516 cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
John Reckc8490812010-11-22 14:15:36 -0800517 intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item);
518 intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER,
519 cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1);
520 startActivity(intent);
Jeff Hamilton84029622010-08-05 14:29:28 -0500521 }
522
523 private void displayRemoveBookmarkDialog(final int position) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800524 // Put up a dialog asking if the user really wants to
525 // delete the bookmark
John Reck608baa72010-11-24 10:32:28 -0800526 Cursor cursor = mAdapter.getItem(position);
Leon Scroggins75630672011-01-13 17:56:15 -0500527 long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
528 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500529 Context context = getActivity();
Leon Scroggins75630672011-01-13 17:56:15 -0500530 BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800531 }
532
Jeff Hamilton84029622010-08-05 14:29:28 -0500533 private String getUrl(int position) {
John Reck608baa72010-11-24 10:32:28 -0800534 return getUrl(mAdapter.getItem(position));
535 }
536
537 /* package */ static String getUrl(Cursor c) {
538 return c.getString(BookmarksLoader.COLUMN_INDEX_URL);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800539 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700540
The Android Open Source Project0c908882009-03-03 19:32:16 -0800541 private void copy(CharSequence text) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500542 ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
543 Context.CLIPBOARD_SERVICE);
Dianne Hackbornbf1d10a2011-01-17 12:29:51 -0800544 cm.setPrimaryClip(ClipData.newRawUri(null, Uri.parse(text.toString())));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800545 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700546
John Reckb3417f02011-01-14 11:01:05 -0800547 @Override
548 public boolean onOptionsItemSelected(MenuItem item) {
549 switch (item.getItemId()) {
550 case R.id.thumbnail_view:
551 selectView(VIEW_THUMBNAILS);
552 return true;
553 case R.id.list_view:
554 selectView(VIEW_LIST);
555 return true;
556 }
557 return super.onOptionsItemSelected(item);
558 }
559
560 @Override
561 public void onConfigurationChanged(Configuration newConfig) {
562 super.onConfigurationChanged(newConfig);
563 Resources res = getActivity().getResources();
564 int horizontalSpacing = (int) res.getDimension(R.dimen.combo_horizontalSpacing);
565 mGrid.setHorizontalSpacing(horizontalSpacing);
John Reck0ce8a942011-01-14 19:57:09 -0800566 int paddingLeftRight = (int) res.getDimension(R.dimen.combo_paddingLeftRight);
567 int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop);
568 mRoot.setPadding(paddingLeftRight, paddingTop,
569 paddingLeftRight, 0);
John Reckb3417f02011-01-14 11:01:05 -0800570 }
571
572 @Override
573 public void onPrepareOptionsMenu(Menu menu) {
574 super.onPrepareOptionsMenu(menu);
575 menu.findItem(R.id.list_view).setVisible(mCurrentView != VIEW_LIST);
576 menu.findItem(R.id.thumbnail_view).setVisible(mCurrentView != VIEW_THUMBNAILS);
577 }
578
John Reck8af90642010-11-23 10:27:29 -0800579 void selectView(int view) {
580 if (view == mCurrentView) {
581 return;
582 }
583 mCurrentView = view;
584 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
585 Editor edit = prefs.edit();
586 edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
587 edit.apply();
588 if (mEmptyView.getVisibility() == View.VISIBLE) {
589 return;
590 }
591 setupBookmarkView();
592 }
593
594 private void setupBookmarkView() {
595 mAdapter.selectView(mCurrentView);
596 switch (mCurrentView) {
597 case VIEW_THUMBNAILS:
598 mList.setAdapter(null);
John Reckf9e6a8e2011-02-22 13:16:13 -0800599 if (mGrid.getAdapter() != mAdapter) {
600 mGrid.setAdapter(mAdapter);
601 }
John Reck8af90642010-11-23 10:27:29 -0800602 mGrid.setVisibility(View.VISIBLE);
603 mList.setVisibility(View.GONE);
604 break;
605 case VIEW_LIST:
606 mGrid.setAdapter(null);
John Reckf9e6a8e2011-02-22 13:16:13 -0800607 if (mList.getAdapter() != mAdapter) {
608 mList.setAdapter(mAdapter);
609 }
John Reck8af90642010-11-23 10:27:29 -0800610 mGrid.setVisibility(View.GONE);
611 mList.setVisibility(View.VISIBLE);
612 break;
613 }
614 }
John Reck608baa72010-11-24 10:32:28 -0800615
John Reck608baa72010-11-24 10:32:28 -0800616 /**
617 * BreadCrumb controller callback
618 */
619 @Override
620 public void onTop(int level, Object data) {
John Reck89f73c12010-12-01 10:10:14 -0800621 Uri uri = (Uri) data;
622 if (uri == null) {
623 // top level
624 uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
625 }
626 loadFolder(uri);
627 }
628
629 /**
630 * @param uri
631 */
632 private void loadFolder(Uri uri) {
633 LoaderManager manager = getLoaderManager();
634 BookmarksLoader loader =
635 (BookmarksLoader) ((Loader<?>) manager.getLoader(LOADER_BOOKMARKS));
636 loader.setUri(uri);
637 loader.forceLoad();
638 if (mCallbacks != null) {
639 mCallbacks.onFolderChanged(mCrumbs.getTopLevel(), uri);
640 }
John Reck608baa72010-11-24 10:32:28 -0800641 }
642
643 @Override
John Reck608baa72010-11-24 10:32:28 -0800644 public boolean onMenuItemClick(MenuItem item) {
645 switch (item.getItemId()) {
646 case R.id.list_view:
John Reck608baa72010-11-24 10:32:28 -0800647 selectView(BrowserBookmarksPage.VIEW_LIST);
648 return true;
649 case R.id.thumbnail_view:
John Reck608baa72010-11-24 10:32:28 -0800650 selectView(BrowserBookmarksPage.VIEW_THUMBNAILS);
651 return true;
652 }
653 return false;
654 }
655
656 public boolean onBackPressed() {
John Reckd4893b02010-12-07 17:38:34 -0800657 if (canGoBack()) {
John Reck608baa72010-11-24 10:32:28 -0800658 mCrumbs.popView();
659 return true;
660 }
661 return false;
662 }
663
John Reckd4893b02010-12-07 17:38:34 -0800664 private boolean canGoBack() {
665 Crumb c = mCrumbs.getTopCrumb();
666 return c != null && c.canGoBack;
667 }
668
John Reck608baa72010-11-24 10:32:28 -0800669 public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
670 mCallbacks = callbackListener;
671 }
672
673 public void setEnableContextMenu(boolean enable) {
674 mEnableContextMenu = enable;
675 if (mGrid != null) {
676 if (mEnableContextMenu) {
677 registerForContextMenu(mGrid);
678 } else {
679 unregisterForContextMenu(mGrid);
680 mGrid.setLongClickable(false);
681 }
682 }
683 if (mList != null) {
684 if (mEnableContextMenu) {
685 registerForContextMenu(mList);
686 } else {
687 unregisterForContextMenu(mList);
688 mList.setLongClickable(false);
689 }
690 }
691 }
John Reckc8490812010-11-22 14:15:36 -0800692
693 private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
694 Context mContext;
695 BookmarkItem mHeader;
696
697 public LookupBookmarkCount(Context context, BookmarkItem header) {
698 mContext = context;
699 mHeader = header;
700 }
701
702 @Override
703 protected Integer doInBackground(Long... params) {
704 if (params.length != 1) {
705 throw new IllegalArgumentException("Missing folder id!");
706 }
707 Uri uri = BookmarkUtils.getBookmarksUri(mContext);
708 Cursor c = mContext.getContentResolver().query(uri,
709 null, BrowserContract.Bookmarks.PARENT + "=?",
710 new String[] {params[0].toString()}, null);
711 return c.getCount();
712 }
713
714 @Override
715 protected void onPostExecute(Integer result) {
716 if (result > 0) {
717 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount,
718 result));
719 } else if (result == 0) {
720 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty));
721 }
722 }
723 }
John Reck89f73c12010-12-01 10:10:14 -0800724
725 public void setBreadCrumbVisibility(int visibility) {
726 mCrumbVisibility = visibility;
727 if (mCrumbs != null) {
728 mCrumbs.setVisibility(mCrumbVisibility);
729 }
730 }
731
732 public void setBreadCrumbUseBackButton(boolean use) {
733 mCrumbBackButton = use;
734 if (mCrumbs != null) {
735 mCrumbs.setUseBackButton(mCrumbBackButton);
736 }
737 }
738
739 public void setBreadCrumbMaxVisible(int max) {
740 mCrumbMaxVisible = max;
741 if (mCrumbs != null) {
742 mCrumbs.setMaxVisible(mCrumbMaxVisible);
743 }
744 }
John Reck522a4382011-01-26 13:23:47 -0800745
746 @Override
747 public void onSharedPreferenceChanged(
748 SharedPreferences sharedPreferences, String key) {
749 if (PREF_ACCOUNT_NAME.equals(key) || PREF_ACCOUNT_TYPE.equals(key)) {
750 mCrumbs.setController(null);
751 mCrumbs.clear();
752 LoaderManager lm = getLoaderManager();
753 lm.restartLoader(LOADER_BOOKMARKS, null, this);
754 mCrumbs.setController(this);
755 String name = getString(R.string.bookmarks);
756 mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
757 if (mCallbacks != null) {
758 mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
759 }
760 }
761 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800762}