blob: 4887f3f49a332394a86c580fa12c56dbfebf622c [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;
20import android.app.AlertDialog;
Jeff Hamilton64144e42010-08-18 16:31:59 -050021import android.app.Fragment;
Jeff Hamilton84029622010-08-05 14:29:28 -050022import android.app.LoaderManager;
Dianne Hackborneb07b172010-08-26 22:18:14 -070023import android.content.ClipData;
Michael Kolbbef7a752010-08-25 17:11:35 -070024import android.content.ClipboardManager;
Jeff Hamilton1a805652010-09-07 12:36:30 -070025import android.content.ContentResolver;
Jeff Hamilton84029622010-08-05 14:29:28 -050026import android.content.ContentUris;
Dianne Hackborn80f32622010-08-05 14:17:53 -070027import android.content.Context;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050028import android.content.CursorLoader;
The Android Open Source Project0c908882009-03-03 19:32:16 -080029import android.content.DialogInterface;
30import android.content.Intent;
Jeff Hamilton84029622010-08-05 14:29:28 -050031import android.content.Loader;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050032import android.content.SharedPreferences;
John Reck8af90642010-11-23 10:27:29 -080033import android.content.SharedPreferences.Editor;
Jeff Hamilton84029622010-08-05 14:29:28 -050034import android.database.Cursor;
The Android Open Source Project0c908882009-03-03 19:32:16 -080035import android.graphics.Bitmap;
Jeff Hamilton84029622010-08-05 14:29:28 -050036import android.graphics.BitmapFactory;
37import android.net.Uri;
John Reckc8490812010-11-22 14:15:36 -080038import android.os.AsyncTask;
The Android Open Source Project0c908882009-03-03 19:32:16 -080039import android.os.Bundle;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050040import android.preference.PreferenceManager;
Jeff Hamilton69bd7072010-08-17 12:38:22 -050041import android.provider.BrowserContract;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050042import android.provider.BrowserContract.Accounts;
43import android.text.TextUtils;
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;
The Android Open Source Project0c908882009-03-03 19:32:16 -080047import android.view.MenuInflater;
48import android.view.MenuItem;
49import android.view.View;
John Reck608baa72010-11-24 10:32:28 -080050import android.view.View.OnClickListener;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050051import android.view.ViewGroup;
Patrick Scottc1cf63a2010-03-09 16:02:08 -050052import android.webkit.WebIconDatabase.IconListener;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050053import android.widget.Adapter;
The Android Open Source Project0c908882009-03-03 19:32:16 -080054import android.widget.AdapterView;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050055import android.widget.AdapterView.OnItemClickListener;
56import android.widget.AdapterView.OnItemSelectedListener;
Jeff Hamilton84029622010-08-05 14:29:28 -050057import android.widget.GridView;
John Reck8af90642010-11-23 10:27:29 -080058import android.widget.ListView;
John Reck608baa72010-11-24 10:32:28 -080059import android.widget.PopupMenu;
60import android.widget.PopupMenu.OnMenuItemClickListener;
61import android.widget.TextView;
Jeff Hamilton84029622010-08-05 14:29:28 -050062import android.widget.Toast;
The Android Open Source Project0c908882009-03-03 19:32:16 -080063
John Reck608baa72010-11-24 10:32:28 -080064interface BookmarksPageCallbacks {
65 // Return true if handled
66 boolean onBookmarkSelected(Cursor c, boolean isFolder);
67 // Return true if handled
68 boolean onOpenInNewWindow(Cursor c);
69}
70
The Android Open Source Project0c908882009-03-03 19:32:16 -080071/**
72 * View showing the user's bookmarks in the browser.
73 */
Jeff Hamilton64144e42010-08-18 16:31:59 -050074public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener,
Michael Kolb370a4f32010-10-06 10:45:32 -070075 LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, IconListener,
John Reck608baa72010-11-24 10:32:28 -080076 OnItemSelectedListener, BreadCrumbView.Controller, OnClickListener, OnMenuItemClickListener {
The Android Open Source Project0c908882009-03-03 19:32:16 -080077
Jeff Hamilton84029622010-08-05 14:29:28 -050078 static final String LOGTAG = "browser";
Nicolas Catania095292f2010-03-15 09:00:14 -070079
Jeff Hamilton84029622010-08-05 14:29:28 -050080 static final int LOADER_BOOKMARKS = 1;
Jeff Hamiltona9bad832010-09-24 11:05:30 -050081 static final int LOADER_ACCOUNTS_THEN_BOOKMARKS = 2;
Jeff Hamilton84029622010-08-05 14:29:28 -050082
Michael Kolb801ecb72010-08-25 12:57:38 -070083 static final String EXTRA_DISABLE_WINDOW = "disable_new_window";
84
Jeff Hamilton70c77692010-09-21 19:11:24 -050085 static final String ACCOUNT_NAME_UNSYNCED = "Unsynced";
Michael Kolbe421c242010-10-04 19:29:01 -070086
Jeff Hamilton7f6cf3e2010-09-17 17:22:21 -050087 public static final String PREF_ACCOUNT_TYPE = "acct_type";
88 public static final String PREF_ACCOUNT_NAME = "acct_name";
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050089
90 static final String DEFAULT_ACCOUNT = "local";
John Reck8af90642010-11-23 10:27:29 -080091 static final int VIEW_THUMBNAILS = 1;
92 static final int VIEW_LIST = 2;
93 static final String PREF_SELECTED_VIEW = "bookmarks_view";
Jeff Hamiltondb90aa82010-09-16 03:38:04 -050094
John Reck608baa72010-11-24 10:32:28 -080095 BookmarksPageCallbacks mCallbacks;
Jeff Hamilton84029622010-08-05 14:29:28 -050096 GridView mGrid;
John Reck8af90642010-11-23 10:27:29 -080097 ListView mList;
Jeff Hamilton84029622010-08-05 14:29:28 -050098 BrowserBookmarksAdapter mAdapter;
99 boolean mDisableNewWindow;
Jeff Hamilton84029622010-08-05 14:29:28 -0500100 boolean mCanceled = false;
John Reck608baa72010-11-24 10:32:28 -0800101 boolean mEnableContextMenu = true;
102 boolean mShowRootFolder = false;
Jeff Hamilton84029622010-08-05 14:29:28 -0500103 View mEmptyView;
John Reck8af90642010-11-23 10:27:29 -0800104 int mCurrentView;
John Reck608baa72010-11-24 10:32:28 -0800105 View mHeader;
106 View mRootFolderView;
107 ViewGroup mHeaderContainer;
Michael Kolb370a4f32010-10-06 10:45:32 -0700108 BreadCrumbView mCrumbs;
John Reck608baa72010-11-24 10:32:28 -0800109 TextView mSelectBookmarkView;
Michael Kolb370a4f32010-10-06 10:45:32 -0700110
John Reck608baa72010-11-24 10:32:28 -0800111 static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb,
112 Bundle args, ViewGroup headerContainer) {
Michael Kolbe421c242010-10-04 19:29:01 -0700113 BrowserBookmarksPage bbp = new BrowserBookmarksPage();
114 bbp.mCallbacks = cb;
John Reck608baa72010-11-24 10:32:28 -0800115 bbp.mHeaderContainer = headerContainer;
Michael Kolbe421c242010-10-04 19:29:01 -0700116 bbp.setArguments(args);
117 return bbp;
118 }
119
Jeff Hamilton84029622010-08-05 14:29:28 -0500120 @Override
121 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
122 switch (id) {
123 case LOADER_BOOKMARKS: {
Jeff Hamilton1a805652010-09-07 12:36:30 -0700124 String accountType = null;
125 String accountName = null;
Jeff Hamilton84029622010-08-05 14:29:28 -0500126 if (args != null) {
Jeff Hamilton1a805652010-09-07 12:36:30 -0700127 accountType = args.getString(BookmarksLoader.ARG_ACCOUNT_TYPE);
128 accountName = args.getString(BookmarksLoader.ARG_ACCOUNT_NAME);
Jeff Hamilton84029622010-08-05 14:29:28 -0500129 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700130 BookmarksLoader bl = new BookmarksLoader(getActivity(), accountType, accountName);
131 if (mCrumbs != null) {
132 Uri uri = (Uri) mCrumbs.getTopData();
133 if (uri != null) {
134 bl.setUri(uri);
135 }
136 }
137 return bl;
Jeff Hamilton84029622010-08-05 14:29:28 -0500138 }
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500139 case LOADER_ACCOUNTS_THEN_BOOKMARKS: {
140 return new CursorLoader(getActivity(), Accounts.CONTENT_URI,
141 new String[] { Accounts.ACCOUNT_TYPE, Accounts.ACCOUNT_NAME }, null, null,
142 null);
143 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500144 }
145 throw new UnsupportedOperationException("Unknown loader id " + id);
146 }
147
148 @Override
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500149 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
150 switch (loader.getId()) {
151 case LOADER_BOOKMARKS: {
152 // Set the visibility of the empty vs. content views
153 if (cursor == null || cursor.getCount() == 0) {
154 mEmptyView.setVisibility(View.VISIBLE);
155 mGrid.setVisibility(View.GONE);
John Reck8af90642010-11-23 10:27:29 -0800156 mList.setVisibility(View.GONE);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500157 } else {
158 mEmptyView.setVisibility(View.GONE);
John Reck8af90642010-11-23 10:27:29 -0800159 setupBookmarkView();
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500160 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500161
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500162 // Give the new data to the adapter
163 mAdapter.changeCursor(cursor);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500164 break;
165 }
166
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500167 case LOADER_ACCOUNTS_THEN_BOOKMARKS: {
168 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
169 getActivity());
170 String storedAccountType = prefs.getString(PREF_ACCOUNT_TYPE, null);
171 String storedAccountName = prefs.getString(PREF_ACCOUNT_NAME, null);
172 String accountType =
173 TextUtils.isEmpty(storedAccountType) ? DEFAULT_ACCOUNT : storedAccountType;
174 String accountName =
175 TextUtils.isEmpty(storedAccountName) ? DEFAULT_ACCOUNT : storedAccountName;
176
177 Bundle args = null;
178 if (cursor == null || !cursor.moveToFirst()) {
179 // No accounts, set the prefs to the default
180 accountType = DEFAULT_ACCOUNT;
181 accountName = DEFAULT_ACCOUNT;
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500182 } else {
183 int accountPosition = -1;
184
185 if (!DEFAULT_ACCOUNT.equals(accountType) &&
186 !DEFAULT_ACCOUNT.equals(accountName)) {
187 // Check to see if the account in prefs still exists
188 cursor.moveToFirst();
189 do {
190 if (accountType.equals(cursor.getString(0))
191 && accountName.equals(cursor.getString(1))) {
192 accountPosition = cursor.getPosition();
193 break;
194 }
195 } while (cursor.moveToNext());
196 }
197
198 if (accountPosition == -1) {
Jeff Hamiltona9bad832010-09-24 11:05:30 -0500199 if (!(DEFAULT_ACCOUNT.equals(accountType)
Jeff Hamilton70c77692010-09-21 19:11:24 -0500200 && DEFAULT_ACCOUNT.equals(accountName))) {
Jeff Hamilton70c77692010-09-21 19:11:24 -0500201 // No account is set in prefs and there is at least one,
202 // so pick the first one as the default
203 cursor.moveToFirst();
204 accountType = cursor.getString(0);
205 accountName = cursor.getString(1);
Jeff Hamilton70c77692010-09-21 19:11:24 -0500206 }
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500207 }
208
209 args = new Bundle();
210 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType);
211 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500212 }
Jeff Hamiltona9bad832010-09-24 11:05:30 -0500213
214 // The stored account name wasn't found, update the stored account with a valid one
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500215 if (!accountType.equals(storedAccountType)
216 || !accountName.equals(storedAccountName)) {
217 prefs.edit()
218 .putString(PREF_ACCOUNT_TYPE, accountType)
219 .putString(PREF_ACCOUNT_NAME, accountName)
220 .apply();
221 }
Jeff Hamiltona9bad832010-09-24 11:05:30 -0500222 getLoaderManager().initLoader(LOADER_BOOKMARKS, args, this);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500223
224 break;
225 }
226 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500227 }
228
Michael Kolb370a4f32010-10-06 10:45:32 -0700229 long getFolderId() {
230 LoaderManager manager = getLoaderManager();
231 BookmarksLoader loader =
John Reck608baa72010-11-24 10:32:28 -0800232 (BookmarksLoader) ((Loader<?>)manager.getLoader(LOADER_BOOKMARKS));
Michael Kolb370a4f32010-10-06 10:45:32 -0700233
234 Uri uri = loader.getUri();
235 if (uri != null) {
236 try {
237 return ContentUris.parseId(uri);
238 } catch (NumberFormatException nfx) {
239 return -1;
240 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500241 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700242 return -1;
243 }
244
245 public void onFolderChange(int level, Object data) {
246 Uri uri = (Uri) data;
247 if (uri == null) {
248 // top level
249 uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
250 }
251 LoaderManager manager = getLoaderManager();
252 BookmarksLoader loader =
John Reck608baa72010-11-24 10:32:28 -0800253 (BookmarksLoader) ((Loader<?>) manager.getLoader(LOADER_BOOKMARKS));
Michael Kolb370a4f32010-10-06 10:45:32 -0700254 loader.setUri(uri);
255 loader.forceLoad();
256
Jeff Hamilton84029622010-08-05 14:29:28 -0500257 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800258
259 @Override
260 public boolean onContextItemSelected(MenuItem item) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500261 final Activity activity = getActivity();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800262 // It is possible that the view has been canceled when we get to
Nicolas Catania095292f2010-03-15 09:00:14 -0700263 // this point as back has a higher priority
The Android Open Source Project0c908882009-03-03 19:32:16 -0800264 if (mCanceled) {
Leon Scrogginsc8cae082010-11-03 18:51:46 -0400265 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800266 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700267 AdapterView.AdapterContextMenuInfo i =
The Android Open Source Project0c908882009-03-03 19:32:16 -0800268 (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
269 // If we have no menu info, we can't tell which item was selected.
270 if (i == null) {
Leon Scrogginsc8cae082010-11-03 18:51:46 -0400271 return false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800272 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700273
The Android Open Source Project0c908882009-03-03 19:32:16 -0800274 switch (item.getItemId()) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800275 case R.id.open_context_menu_id:
276 loadUrl(i.position);
277 break;
278 case R.id.edit_context_menu_id:
279 editBookmark(i.position);
280 break;
281 case R.id.shortcut_context_menu_id:
John Reck608baa72010-11-24 10:32:28 -0800282 Cursor c = mAdapter.getItem(i.position);
283 activity.sendBroadcast(createShortcutIntent(getActivity(), c));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800284 break;
285 case R.id.delete_context_menu_id:
Jeff Hamilton84029622010-08-05 14:29:28 -0500286 displayRemoveBookmarkDialog(i.position);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800287 break;
288 case R.id.new_window_context_menu_id:
289 openInNewWindow(i.position);
290 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500291 case R.id.share_link_context_menu_id: {
John Reck608baa72010-11-24 10:32:28 -0800292 Cursor cursor = mAdapter.getItem(i.position);
Michael Kolb8233fac2010-10-26 16:08:53 -0700293 Controller.sharePage(activity,
Jeff Hamilton84029622010-08-05 14:29:28 -0500294 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE),
295 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL),
296 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON),
297 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800298 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500299 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800300 case R.id.copy_url_context_menu_id:
301 copy(getUrl(i.position));
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400302 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500303 case R.id.homepage_context_menu_id: {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500304 BrowserSettings.getInstance().setHomePage(activity, getUrl(i.position));
305 Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
Leon Scrogginsfeb941d2009-05-28 17:27:38 -0400306 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500307 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400308 // Only for the Most visited page
Jeff Hamilton84029622010-08-05 14:29:28 -0500309 case R.id.save_to_bookmarks_menu_id: {
John Reck608baa72010-11-24 10:32:28 -0800310 Cursor cursor = mAdapter.getItem(i.position);
Jeff Hamilton84029622010-08-05 14:29:28 -0500311 String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
312 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400313 // If the site is bookmarked, the item becomes remove from
314 // bookmarks.
Jeff Hamilton64144e42010-08-18 16:31:59 -0500315 Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name);
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400316 break;
Jeff Hamilton84029622010-08-05 14:29:28 -0500317 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800318 default:
319 return super.onContextItemSelected(item);
320 }
321 return true;
322 }
323
John Reck608baa72010-11-24 10:32:28 -0800324 static Bitmap getBitmap(Cursor cursor, int columnIndex) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500325 byte[] data = cursor.getBlob(columnIndex);
326 if (data == null) {
327 return null;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800328 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500329 return BitmapFactory.decodeByteArray(data, 0, data.length);
330 }
331
John Reckc8490812010-11-22 14:15:36 -0800332 private MenuItem.OnMenuItemClickListener mContextItemClickListener =
333 new MenuItem.OnMenuItemClickListener() {
334 @Override
335 public boolean onMenuItemClick(MenuItem item) {
336 return onContextItemSelected(item);
337 }
338 };
339
Jeff Hamilton84029622010-08-05 14:29:28 -0500340 @Override
341 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
342 AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
John Reck608baa72010-11-24 10:32:28 -0800343 Cursor cursor = mAdapter.getItem(info.position);
Leon Scroggins5e8a40f2010-09-27 17:13:35 -0400344 boolean isFolder
345 = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
Michael Kolb801ecb72010-08-25 12:57:38 -0700346
Jeff Hamilton64144e42010-08-18 16:31:59 -0500347 final Activity activity = getActivity();
348 MenuInflater inflater = activity.getMenuInflater();
Jeff Hamilton84029622010-08-05 14:29:28 -0500349 inflater.inflate(R.menu.bookmarkscontext, menu);
John Reckc8490812010-11-22 14:15:36 -0800350 if (isFolder) {
351 menu.setGroupVisible(R.id.FOLDER_CONTEXT_MENU, true);
352 } else {
353 menu.setGroupVisible(R.id.BOOKMARK_CONTEXT_MENU, true);
354 if (mDisableNewWindow) {
355 menu.findItem(R.id.new_window_context_menu_id).setVisible(false);
356 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500357 }
John Reckc8490812010-11-22 14:15:36 -0800358 BookmarkItem header = new BookmarkItem(activity);
359 populateBookmarkItem(cursor, header, isFolder);
360 new LookupBookmarkCount(getActivity(), header)
361 .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
362 menu.setHeaderView(header);
Jeff Hamilton84029622010-08-05 14:29:28 -0500363
John Reckc8490812010-11-22 14:15:36 -0800364 int count = menu.size();
365 for (int i = 0; i < count; i++) {
366 menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener);
Jeff Hamilton84029622010-08-05 14:29:28 -0500367 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500368 }
369
John Reckc8490812010-11-22 14:15:36 -0800370 private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500371 item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
John Reckc8490812010-11-22 14:15:36 -0800372 if (isFolder) {
373 item.setUrl(null);
374 Bitmap bitmap =
375 BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder);
376 item.setFavicon(bitmap);
377 } else {
378 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
379 item.setUrl(url);
380 Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
381 if (bitmap == null) {
382 bitmap = CombinedBookmarkHistoryView.getIconListenerSet().getFavicon(url);
383 }
384 item.setFavicon(bitmap);
Jeff Hamilton84029622010-08-05 14:29:28 -0500385 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500386 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800387
388 /**
389 * Create a new BrowserBookmarksPage.
Nicolas Catania095292f2010-03-15 09:00:14 -0700390 */
The Android Open Source Project0c908882009-03-03 19:32:16 -0800391 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500392 public void onCreate(Bundle icicle) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800393 super.onCreate(icicle);
394
Jeff Hamilton64144e42010-08-18 16:31:59 -0500395 Bundle args = getArguments();
Leon Scrogginsbc922852010-10-22 12:15:27 -0400396 mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500397 }
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400398
Jeff Hamilton64144e42010-08-18 16:31:59 -0500399 @Override
Jeff Hamilton64144e42010-08-18 16:31:59 -0500400 public View onCreateView(LayoutInflater inflater, ViewGroup container,
401 Bundle savedInstanceState) {
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500402 Context context = getActivity();
403
Jeff Hamilton64144e42010-08-18 16:31:59 -0500404 View root = inflater.inflate(R.layout.bookmarks, container, false);
405 mEmptyView = root.findViewById(android.R.id.empty);
Leon Scrogginsd87f85e2009-08-18 14:13:31 -0400406
Jeff Hamilton64144e42010-08-18 16:31:59 -0500407 mGrid = (GridView) root.findViewById(R.id.grid);
Jeff Hamilton84029622010-08-05 14:29:28 -0500408 mGrid.setOnItemClickListener(this);
Michael Kolb8233fac2010-10-26 16:08:53 -0700409 mGrid.setColumnWidth(Controller.getDesiredThumbnailWidth(getActivity()));
John Reck8af90642010-11-23 10:27:29 -0800410 mList = (ListView) root.findViewById(R.id.list);
411 mList.setOnItemClickListener(this);
John Reck608baa72010-11-24 10:32:28 -0800412 setEnableContextMenu(mEnableContextMenu);
413
414 // Prep the header
415 ViewGroup hc = mHeaderContainer;
416 if (hc == null) {
417 hc = (ViewGroup) root.findViewById(R.id.header_container);
418 hc.setVisibility(View.VISIBLE);
John Reck8af90642010-11-23 10:27:29 -0800419 }
John Reck608baa72010-11-24 10:32:28 -0800420 mHeader = inflater.inflate(R.layout.bookmarks_header, hc, true);
421 mCrumbs = (BreadCrumbView) mHeader.findViewById(R.id.crumbs);
422 mCrumbs.setController(this);
423 mSelectBookmarkView = (TextView) mHeader.findViewById(R.id.select_bookmark_view);
424 mSelectBookmarkView.setOnClickListener(this);
425 mRootFolderView = mHeader.findViewById(R.id.root_folder);
426 mRootFolderView.setOnClickListener(this);
427 setShowRootFolder(mShowRootFolder);
Jeff Hamilton84029622010-08-05 14:29:28 -0500428
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500429 // Start the loaders
430 LoaderManager lm = getLoaderManager();
431 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
John Reck8af90642010-11-23 10:27:29 -0800432 mCurrentView =
433 prefs.getInt(PREF_SELECTED_VIEW, BrowserBookmarksPage.VIEW_THUMBNAILS);
John Reck608baa72010-11-24 10:32:28 -0800434 if (mCurrentView == BrowserBookmarksPage.VIEW_THUMBNAILS) {
435 mSelectBookmarkView.setText(R.string.bookmark_thumbnail_view);
436 } else {
437 mSelectBookmarkView.setText(R.string.bookmark_list_view);
438 }
John Reck8af90642010-11-23 10:27:29 -0800439 mAdapter = new BrowserBookmarksAdapter(getActivity(), mCurrentView);
Jeff Hamiltona9bad832010-09-24 11:05:30 -0500440 String accountType = prefs.getString(PREF_ACCOUNT_TYPE, DEFAULT_ACCOUNT);
441 String accountName = prefs.getString(PREF_ACCOUNT_NAME, DEFAULT_ACCOUNT);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500442 if (!TextUtils.isEmpty(accountType) && !TextUtils.isEmpty(accountName)) {
443 // There is an account set, load up that one
444 Bundle args = null;
445 if (!DEFAULT_ACCOUNT.equals(accountType) && !DEFAULT_ACCOUNT.equals(accountName)) {
446 args = new Bundle();
447 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType);
448 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName);
449 }
Jeff Hamilton70c77692010-09-21 19:11:24 -0500450 lm.restartLoader(LOADER_BOOKMARKS, args, this);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500451 } else {
Jeff Hamiltona9bad832010-09-24 11:05:30 -0500452 // No account set, load the account list first
Jeff Hamilton70c77692010-09-21 19:11:24 -0500453 lm.restartLoader(LOADER_ACCOUNTS_THEN_BOOKMARKS, null, this);
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500454 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500455
456 // Add our own listener in case there are favicons that have yet to be loaded.
Michael Kolbe421c242010-10-04 19:29:01 -0700457 CombinedBookmarkHistoryView.getIconListenerSet().addListener(this);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800458
Jeff Hamilton64144e42010-08-18 16:31:59 -0500459 return root;
460 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700461
John Reck608baa72010-11-24 10:32:28 -0800462 public void setShowRootFolder(boolean show) {
463 mShowRootFolder = show;
464 if (mRootFolderView != null) {
465 if (mShowRootFolder) {
466 mRootFolderView.setVisibility(View.VISIBLE);
467 } else {
468 mRootFolderView.setVisibility(View.GONE);
469 }
470 }
471 }
472
473 @Override
474 public void onDestroyView() {
475 super.onDestroyView();
476 if (mHeaderContainer != null) {
477 mHeaderContainer.removeView(mHeader);
478 }
479 mCrumbs.setController(null);
480 mCrumbs = null;
481 }
482
Nicolas Catania095292f2010-03-15 09:00:14 -0700483 @Override
Jeff Hamilton84029622010-08-05 14:29:28 -0500484 public void onReceivedIcon(String url, Bitmap icon) {
485 // A new favicon has been loaded, so let anything attached to the adapter know about it
486 // so new icons will be loaded.
487 mAdapter.notifyDataSetChanged();
Nicolas Catania095292f2010-03-15 09:00:14 -0700488 }
489
Jeff Hamilton84029622010-08-05 14:29:28 -0500490 @Override
John Reck608baa72010-11-24 10:32:28 -0800491 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500492 // It is possible that the view has been canceled when we get to
493 // this point as back has a higher priority
494 if (mCanceled) {
495 android.util.Log.e(LOGTAG, "item clicked when dismissing");
496 return;
497 }
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500498
John Reck608baa72010-11-24 10:32:28 -0800499 Cursor cursor = mAdapter.getItem(position);
500 boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
501 if (mCallbacks != null &&
502 mCallbacks.onBookmarkSelected(cursor, isFolder)) {
Ben Murdoch328ea872009-09-16 13:33:29 +0100503 return;
504 }
505
John Reck608baa72010-11-24 10:32:28 -0800506 if (isFolder) {
Michael Kolb370a4f32010-10-06 10:45:32 -0700507 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500508 LoaderManager manager = getLoaderManager();
Michael Kolb801ecb72010-08-25 12:57:38 -0700509 BookmarksLoader loader =
John Reck608baa72010-11-24 10:32:28 -0800510 (BookmarksLoader) ((Loader<?>) manager.getLoader(LOADER_BOOKMARKS));
Jeff Hamilton84029622010-08-05 14:29:28 -0500511 Uri uri = ContentUris.withAppendedId(
512 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
Michael Kolb370a4f32010-10-06 10:45:32 -0700513 if (mCrumbs != null) {
514 // update crumbs
515 mCrumbs.pushView(title, uri);
516 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500517 loader.setUri(uri);
518 loader.forceLoad();
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400519 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800520 }
521
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500522 @Override
523 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
524 Adapter adapter = parent.getAdapter();
525 String accountType = "com.google";
526 String accountName = adapter.getItem(position).toString();
527
Jeff Hamilton70c77692010-09-21 19:11:24 -0500528 Bundle args = null;
529 if (ACCOUNT_NAME_UNSYNCED.equals(accountName)) {
530 accountType = DEFAULT_ACCOUNT;
531 accountName = DEFAULT_ACCOUNT;
532 } else {
533 args = new Bundle();
534 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType);
535 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName);
536 }
537
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500538 // Remember the selection for later
539 PreferenceManager.getDefaultSharedPreferences(getActivity()).edit()
540 .putString(PREF_ACCOUNT_TYPE, accountType)
541 .putString(PREF_ACCOUNT_NAME, accountName)
542 .apply();
543
Jeff Hamiltondb90aa82010-09-16 03:38:04 -0500544 getLoaderManager().restartLoader(LOADER_BOOKMARKS, args, this);
545 }
546
547 @Override
548 public void onNothingSelected(AdapterView<?> parent) {
549 // Do nothing
550 }
551
John Reck608baa72010-11-24 10:32:28 -0800552 /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500553 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
Michael Kolbccaa8962010-10-20 17:03:10 -0700554 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Jeff Hamilton84029622010-08-05 14:29:28 -0500555 Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON);
556 Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON);
John Reck608baa72010-11-24 10:32:28 -0800557 return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800558 }
559
The Android Open Source Project0c908882009-03-03 19:32:16 -0800560 private void loadUrl(int position) {
John Reck608baa72010-11-24 10:32:28 -0800561 if (mCallbacks != null) {
562 mCallbacks.onBookmarkSelected(mAdapter.getItem(position), false);
563 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800564 }
565
The Android Open Source Project0c908882009-03-03 19:32:16 -0800566 private void openInNewWindow(int position) {
John Reck608baa72010-11-24 10:32:28 -0800567 if (mCallbacks != null) {
568 mCallbacks.onOpenInNewWindow(mAdapter.getItem(position));
569 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800570 }
Nicolas Catania095292f2010-03-15 09:00:14 -0700571
The Android Open Source Project0c908882009-03-03 19:32:16 -0800572 private void editBookmark(int position) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500573 Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
John Reck608baa72010-11-24 10:32:28 -0800574 Cursor cursor = mAdapter.getItem(position);
Jeff Hamilton84029622010-08-05 14:29:28 -0500575 Bundle item = new Bundle();
Michael Kolbbef7a752010-08-25 17:11:35 -0700576 item.putString(BrowserContract.Bookmarks.TITLE,
Jeff Hamilton84029622010-08-05 14:29:28 -0500577 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
Michael Kolbbef7a752010-08-25 17:11:35 -0700578 item.putString(BrowserContract.Bookmarks.URL,
Jeff Hamilton84029622010-08-05 14:29:28 -0500579 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL));
580 byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON);
581 if (data != null) {
Michael Kolbbef7a752010-08-25 17:11:35 -0700582 item.putParcelable(BrowserContract.Bookmarks.FAVICON,
Jeff Hamilton84029622010-08-05 14:29:28 -0500583 BitmapFactory.decodeByteArray(data, 0, data.length));
584 }
John Reckc8490812010-11-22 14:15:36 -0800585 item.putLong(BrowserContract.Bookmarks._ID,
586 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
Leon Scroggins III052ce662010-09-13 14:44:16 -0400587 item.putLong(BrowserContract.Bookmarks.PARENT,
588 cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT));
John Reckc8490812010-11-22 14:15:36 -0800589 intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item);
590 intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER,
591 cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1);
592 startActivity(intent);
Jeff Hamilton84029622010-08-05 14:29:28 -0500593 }
594
595 private void displayRemoveBookmarkDialog(final int position) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800596 // Put up a dialog asking if the user really wants to
597 // delete the bookmark
John Reck608baa72010-11-24 10:32:28 -0800598 Cursor cursor = mAdapter.getItem(position);
Jeff Hamilton64144e42010-08-18 16:31:59 -0500599 Context context = getActivity();
Jeff Hamilton1a805652010-09-07 12:36:30 -0700600 final ContentResolver resolver = context.getContentResolver();
601 final Uri uri = ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI,
602 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID));
603
Jeff Hamilton64144e42010-08-18 16:31:59 -0500604 new AlertDialog.Builder(context)
The Android Open Source Project0c908882009-03-03 19:32:16 -0800605 .setTitle(R.string.delete_bookmark)
606 .setIcon(android.R.drawable.ic_dialog_alert)
Jeff Hamilton1a805652010-09-07 12:36:30 -0700607 .setMessage(context.getString(R.string.delete_bookmark_warning,
608 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE)))
Nicolas Catania095292f2010-03-15 09:00:14 -0700609 .setPositiveButton(R.string.ok,
The Android Open Source Project0c908882009-03-03 19:32:16 -0800610 new DialogInterface.OnClickListener() {
Jeff Hamiltona9bad832010-09-24 11:05:30 -0500611 @Override
The Android Open Source Project0c908882009-03-03 19:32:16 -0800612 public void onClick(DialogInterface dialog, int whichButton) {
Jeff Hamilton1a805652010-09-07 12:36:30 -0700613 resolver.delete(uri, null, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800614 }
615 })
616 .setNegativeButton(R.string.cancel, null)
617 .show();
618 }
619
Jeff Hamilton84029622010-08-05 14:29:28 -0500620 private String getUrl(int position) {
John Reck608baa72010-11-24 10:32:28 -0800621 return getUrl(mAdapter.getItem(position));
622 }
623
624 /* package */ static String getUrl(Cursor c) {
625 return c.getString(BookmarksLoader.COLUMN_INDEX_URL);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800626 }
Michael Kolb801ecb72010-08-25 12:57:38 -0700627
The Android Open Source Project0c908882009-03-03 19:32:16 -0800628 private void copy(CharSequence text) {
Jeff Hamilton64144e42010-08-18 16:31:59 -0500629 ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
630 Context.CLIPBOARD_SERVICE);
Dianne Hackborneb07b172010-08-26 22:18:14 -0700631 cm.setPrimaryClip(ClipData.newRawUri(null, null, Uri.parse(text.toString())));
The Android Open Source Project0c908882009-03-03 19:32:16 -0800632 }
Michael Kolb370a4f32010-10-06 10:45:32 -0700633
John Reck8af90642010-11-23 10:27:29 -0800634 void selectView(int view) {
635 if (view == mCurrentView) {
636 return;
637 }
638 mCurrentView = view;
639 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
640 Editor edit = prefs.edit();
641 edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
642 edit.apply();
643 if (mEmptyView.getVisibility() == View.VISIBLE) {
644 return;
645 }
646 setupBookmarkView();
647 }
648
649 private void setupBookmarkView() {
650 mAdapter.selectView(mCurrentView);
651 switch (mCurrentView) {
652 case VIEW_THUMBNAILS:
653 mList.setAdapter(null);
654 mGrid.setAdapter(mAdapter);
655 mGrid.setVisibility(View.VISIBLE);
656 mList.setVisibility(View.GONE);
657 break;
658 case VIEW_LIST:
659 mGrid.setAdapter(null);
660 mList.setAdapter(mAdapter);
661 mGrid.setVisibility(View.GONE);
662 mList.setVisibility(View.VISIBLE);
663 break;
664 }
665 }
John Reck608baa72010-11-24 10:32:28 -0800666
667 public BreadCrumbView getBreadCrumb() {
668 return mCrumbs;
669 }
670
671 /**
672 * BreadCrumb controller callback
673 */
674 @Override
675 public void onTop(int level, Object data) {
676 onFolderChange(level, data);
677 }
678
679 @Override
680 public void onClick(View view) {
681 if (mSelectBookmarkView == view) {
682 PopupMenu popup = new PopupMenu(getActivity(), mSelectBookmarkView);
683 popup.getMenuInflater().inflate(R.menu.bookmark_view,
684 popup.getMenu());
685 popup.setOnMenuItemClickListener(this);
686 popup.show();
687 } else if (mRootFolderView == view) {
688 mCrumbs.clear();
689 }
690 }
691
692 @Override
693 public boolean onMenuItemClick(MenuItem item) {
694 switch (item.getItemId()) {
695 case R.id.list_view:
696 mSelectBookmarkView.setText(R.string.bookmark_list_view);
697 selectView(BrowserBookmarksPage.VIEW_LIST);
698 return true;
699 case R.id.thumbnail_view:
700 mSelectBookmarkView.setText(R.string.bookmark_thumbnail_view);
701 selectView(BrowserBookmarksPage.VIEW_THUMBNAILS);
702 return true;
703 }
704 return false;
705 }
706
707 public boolean onBackPressed() {
708 if (mCrumbs != null &&
709 mCrumbs.size() > 0) {
710 mCrumbs.popView();
711 return true;
712 }
713 return false;
714 }
715
716 public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
717 mCallbacks = callbackListener;
718 }
719
720 public void setEnableContextMenu(boolean enable) {
721 mEnableContextMenu = enable;
722 if (mGrid != null) {
723 if (mEnableContextMenu) {
724 registerForContextMenu(mGrid);
725 } else {
726 unregisterForContextMenu(mGrid);
727 mGrid.setLongClickable(false);
728 }
729 }
730 if (mList != null) {
731 if (mEnableContextMenu) {
732 registerForContextMenu(mList);
733 } else {
734 unregisterForContextMenu(mList);
735 mList.setLongClickable(false);
736 }
737 }
738 }
John Reckc8490812010-11-22 14:15:36 -0800739
740 private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
741 Context mContext;
742 BookmarkItem mHeader;
743
744 public LookupBookmarkCount(Context context, BookmarkItem header) {
745 mContext = context;
746 mHeader = header;
747 }
748
749 @Override
750 protected Integer doInBackground(Long... params) {
751 if (params.length != 1) {
752 throw new IllegalArgumentException("Missing folder id!");
753 }
754 Uri uri = BookmarkUtils.getBookmarksUri(mContext);
755 Cursor c = mContext.getContentResolver().query(uri,
756 null, BrowserContract.Bookmarks.PARENT + "=?",
757 new String[] {params[0].toString()}, null);
758 return c.getCount();
759 }
760
761 @Override
762 protected void onPostExecute(Integer result) {
763 if (result > 0) {
764 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount,
765 result));
766 } else if (result == 0) {
767 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty));
768 }
769 }
770 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800771}