BrowserBookmarksPage.java revision 1cebb445779da9ca597621c79b020d6e5ea54fb2
1/* 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 com.android.browser.BreadCrumbView.Crumb; 20 21import android.app.Activity; 22import android.app.AlertDialog; 23import android.app.Fragment; 24import android.app.LoaderManager; 25import android.content.ClipData; 26import android.content.ClipboardManager; 27import android.content.ContentResolver; 28import android.content.ContentUris; 29import android.content.Context; 30import android.content.CursorLoader; 31import android.content.DialogInterface; 32import android.content.Intent; 33import android.content.Loader; 34import android.content.SharedPreferences; 35import android.content.SharedPreferences.Editor; 36import android.database.Cursor; 37import android.graphics.Bitmap; 38import android.graphics.BitmapFactory; 39import android.net.Uri; 40import android.os.AsyncTask; 41import android.os.Bundle; 42import android.preference.PreferenceManager; 43import android.provider.BrowserContract; 44import android.provider.BrowserContract.Accounts; 45import android.provider.BrowserContract.ChromeSyncColumns; 46import android.text.TextUtils; 47import android.view.ContextMenu; 48import android.view.ContextMenu.ContextMenuInfo; 49import android.view.LayoutInflater; 50import android.view.MenuInflater; 51import android.view.MenuItem; 52import android.view.View; 53import android.view.View.OnClickListener; 54import android.view.ViewGroup; 55import android.webkit.WebIconDatabase.IconListener; 56import android.widget.Adapter; 57import android.widget.AdapterView; 58import android.widget.AdapterView.OnItemClickListener; 59import android.widget.AdapterView.OnItemSelectedListener; 60import android.widget.GridView; 61import android.widget.ListView; 62import android.widget.PopupMenu.OnMenuItemClickListener; 63import android.widget.TextView; 64import android.widget.Toast; 65 66interface BookmarksPageCallbacks { 67 // Return true if handled 68 boolean onBookmarkSelected(Cursor c, boolean isFolder); 69 // Return true if handled 70 boolean onOpenInNewWindow(Cursor c); 71 void onFolderChanged(int level, Uri uri); 72} 73 74/** 75 * View showing the user's bookmarks in the browser. 76 */ 77public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener, 78 LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, IconListener, 79 OnItemSelectedListener, BreadCrumbView.Controller, OnClickListener, OnMenuItemClickListener { 80 81 static final String LOGTAG = "browser"; 82 83 static final int LOADER_BOOKMARKS = 1; 84 static final int LOADER_ACCOUNTS_THEN_BOOKMARKS = 2; 85 86 static final String EXTRA_DISABLE_WINDOW = "disable_new_window"; 87 88 static final String ACCOUNT_NAME_UNSYNCED = "Unsynced"; 89 90 public static final String PREF_ACCOUNT_TYPE = "acct_type"; 91 public static final String PREF_ACCOUNT_NAME = "acct_name"; 92 93 static final String DEFAULT_ACCOUNT = "local"; 94 static final int VIEW_THUMBNAILS = 1; 95 static final int VIEW_LIST = 2; 96 static final String PREF_SELECTED_VIEW = "bookmarks_view"; 97 98 BookmarksPageCallbacks mCallbacks; 99 GridView mGrid; 100 ListView mList; 101 BrowserBookmarksAdapter mAdapter; 102 boolean mDisableNewWindow; 103 boolean mCanceled = false; 104 boolean mEnableContextMenu = true; 105 boolean mShowRootFolder = false; 106 View mEmptyView; 107 int mCurrentView; 108 View mHeader; 109 ViewGroup mHeaderContainer; 110 BreadCrumbView mCrumbs; 111 TextView mSelectBookmarkView; 112 int mCrumbVisibility = View.VISIBLE; 113 int mCrumbMaxVisible = -1; 114 boolean mCrumbBackButton = false; 115 116 static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb, 117 Bundle args, ViewGroup headerContainer) { 118 BrowserBookmarksPage bbp = new BrowserBookmarksPage(); 119 bbp.mCallbacks = cb; 120 bbp.mHeaderContainer = headerContainer; 121 bbp.setArguments(args); 122 return bbp; 123 } 124 125 @Override 126 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 127 switch (id) { 128 case LOADER_BOOKMARKS: { 129 String accountType = null; 130 String accountName = null; 131 if (args != null) { 132 accountType = args.getString(BookmarksLoader.ARG_ACCOUNT_TYPE); 133 accountName = args.getString(BookmarksLoader.ARG_ACCOUNT_NAME); 134 } 135 BookmarksLoader bl = new BookmarksLoader(getActivity(), accountType, accountName); 136 if (mCrumbs != null) { 137 Uri uri = (Uri) mCrumbs.getTopData(); 138 if (uri != null) { 139 bl.setUri(uri); 140 } 141 } 142 return bl; 143 } 144 case LOADER_ACCOUNTS_THEN_BOOKMARKS: { 145 return new CursorLoader(getActivity(), Accounts.CONTENT_URI, 146 new String[] { Accounts.ACCOUNT_TYPE, Accounts.ACCOUNT_NAME }, null, null, 147 null); 148 } 149 } 150 throw new UnsupportedOperationException("Unknown loader id " + id); 151 } 152 153 @Override 154 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 155 switch (loader.getId()) { 156 case LOADER_BOOKMARKS: { 157 // Set the visibility of the empty vs. content views 158 if (cursor == null || cursor.getCount() == 0) { 159 mEmptyView.setVisibility(View.VISIBLE); 160 mGrid.setVisibility(View.GONE); 161 mList.setVisibility(View.GONE); 162 } else { 163 mEmptyView.setVisibility(View.GONE); 164 setupBookmarkView(); 165 } 166 167 // Give the new data to the adapter 168 mAdapter.changeCursor(cursor); 169 break; 170 } 171 172 case LOADER_ACCOUNTS_THEN_BOOKMARKS: { 173 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( 174 getActivity()); 175 String storedAccountType = prefs.getString(PREF_ACCOUNT_TYPE, null); 176 String storedAccountName = prefs.getString(PREF_ACCOUNT_NAME, null); 177 String accountType = 178 TextUtils.isEmpty(storedAccountType) ? DEFAULT_ACCOUNT : storedAccountType; 179 String accountName = 180 TextUtils.isEmpty(storedAccountName) ? DEFAULT_ACCOUNT : storedAccountName; 181 182 Bundle args = null; 183 if (cursor == null || !cursor.moveToFirst()) { 184 // No accounts, set the prefs to the default 185 accountType = DEFAULT_ACCOUNT; 186 accountName = DEFAULT_ACCOUNT; 187 } else { 188 int accountPosition = -1; 189 190 if (!DEFAULT_ACCOUNT.equals(accountType) && 191 !DEFAULT_ACCOUNT.equals(accountName)) { 192 // Check to see if the account in prefs still exists 193 cursor.moveToFirst(); 194 do { 195 if (accountType.equals(cursor.getString(0)) 196 && accountName.equals(cursor.getString(1))) { 197 accountPosition = cursor.getPosition(); 198 break; 199 } 200 } while (cursor.moveToNext()); 201 } 202 203 if (accountPosition == -1) { 204 if (!(DEFAULT_ACCOUNT.equals(accountType) 205 && DEFAULT_ACCOUNT.equals(accountName))) { 206 // No account is set in prefs and there is at least one, 207 // so pick the first one as the default 208 cursor.moveToFirst(); 209 accountType = cursor.getString(0); 210 accountName = cursor.getString(1); 211 } 212 } 213 214 args = new Bundle(); 215 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType); 216 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName); 217 } 218 219 // The stored account name wasn't found, update the stored account with a valid one 220 if (!accountType.equals(storedAccountType) 221 || !accountName.equals(storedAccountName)) { 222 prefs.edit() 223 .putString(PREF_ACCOUNT_TYPE, accountType) 224 .putString(PREF_ACCOUNT_NAME, accountName) 225 .apply(); 226 } 227 getLoaderManager().initLoader(LOADER_BOOKMARKS, args, this); 228 229 break; 230 } 231 } 232 } 233 234 long getFolderId() { 235 LoaderManager manager = getLoaderManager(); 236 BookmarksLoader loader = 237 (BookmarksLoader) ((Loader<?>)manager.getLoader(LOADER_BOOKMARKS)); 238 239 Uri uri = loader.getUri(); 240 if (uri != null) { 241 try { 242 return ContentUris.parseId(uri); 243 } catch (NumberFormatException nfx) { 244 return -1; 245 } 246 } 247 return -1; 248 } 249 250 @Override 251 public boolean onContextItemSelected(MenuItem item) { 252 final Activity activity = getActivity(); 253 // It is possible that the view has been canceled when we get to 254 // this point as back has a higher priority 255 if (mCanceled) { 256 return false; 257 } 258 AdapterView.AdapterContextMenuInfo i = 259 (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); 260 // If we have no menu info, we can't tell which item was selected. 261 if (i == null) { 262 return false; 263 } 264 265 switch (item.getItemId()) { 266 case R.id.open_context_menu_id: 267 loadUrl(i.position); 268 break; 269 case R.id.edit_context_menu_id: 270 editBookmark(i.position); 271 break; 272 case R.id.shortcut_context_menu_id: 273 Cursor c = mAdapter.getItem(i.position); 274 activity.sendBroadcast(createShortcutIntent(getActivity(), c)); 275 break; 276 case R.id.delete_context_menu_id: 277 displayRemoveBookmarkDialog(i.position); 278 break; 279 case R.id.new_window_context_menu_id: 280 openInNewWindow(i.position); 281 break; 282 case R.id.share_link_context_menu_id: { 283 Cursor cursor = mAdapter.getItem(i.position); 284 Controller.sharePage(activity, 285 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE), 286 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL), 287 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON), 288 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL)); 289 break; 290 } 291 case R.id.copy_url_context_menu_id: 292 copy(getUrl(i.position)); 293 break; 294 case R.id.homepage_context_menu_id: { 295 BrowserSettings.getInstance().setHomePage(activity, getUrl(i.position)); 296 Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show(); 297 break; 298 } 299 // Only for the Most visited page 300 case R.id.save_to_bookmarks_menu_id: { 301 Cursor cursor = mAdapter.getItem(i.position); 302 String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 303 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 304 // If the site is bookmarked, the item becomes remove from 305 // bookmarks. 306 Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name); 307 break; 308 } 309 default: 310 return super.onContextItemSelected(item); 311 } 312 return true; 313 } 314 315 static Bitmap getBitmap(Cursor cursor, int columnIndex) { 316 byte[] data = cursor.getBlob(columnIndex); 317 if (data == null) { 318 return null; 319 } 320 return BitmapFactory.decodeByteArray(data, 0, data.length); 321 } 322 323 private MenuItem.OnMenuItemClickListener mContextItemClickListener = 324 new MenuItem.OnMenuItemClickListener() { 325 @Override 326 public boolean onMenuItemClick(MenuItem item) { 327 return onContextItemSelected(item); 328 } 329 }; 330 331 @Override 332 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 333 AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; 334 Cursor cursor = mAdapter.getItem(info.position); 335 if (!canEdit(cursor)) { 336 return; 337 } 338 boolean isFolder 339 = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0; 340 341 final Activity activity = getActivity(); 342 MenuInflater inflater = activity.getMenuInflater(); 343 inflater.inflate(R.menu.bookmarkscontext, menu); 344 if (isFolder) { 345 menu.setGroupVisible(R.id.FOLDER_CONTEXT_MENU, true); 346 } else { 347 menu.setGroupVisible(R.id.BOOKMARK_CONTEXT_MENU, true); 348 if (mDisableNewWindow) { 349 menu.findItem(R.id.new_window_context_menu_id).setVisible(false); 350 } 351 } 352 BookmarkItem header = new BookmarkItem(activity); 353 populateBookmarkItem(cursor, header, isFolder); 354 menu.setHeaderView(header); 355 356 int count = menu.size(); 357 for (int i = 0; i < count; i++) { 358 menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener); 359 } 360 } 361 362 boolean canEdit(Cursor c) { 363 String unique = c.getString(BookmarksLoader.COLUMN_INDEX_SERVER_UNIQUE); 364 return !ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS.equals(unique); 365 } 366 367 private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) { 368 item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE)); 369 if (isFolder) { 370 item.setUrl(null); 371 Bitmap bitmap = 372 BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder); 373 item.setFavicon(bitmap); 374 new LookupBookmarkCount(getActivity(), item) 375 .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID)); 376 } else { 377 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 378 item.setUrl(url); 379 Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON); 380 if (bitmap == null) { 381 bitmap = CombinedBookmarkHistoryView.getIconListenerSet().getFavicon(url); 382 } 383 item.setFavicon(bitmap); 384 } 385 } 386 387 /** 388 * Create a new BrowserBookmarksPage. 389 */ 390 @Override 391 public void onCreate(Bundle icicle) { 392 super.onCreate(icicle); 393 394 Bundle args = getArguments(); 395 mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false); 396 } 397 398 @Override 399 public View onCreateView(LayoutInflater inflater, ViewGroup container, 400 Bundle savedInstanceState) { 401 Context context = getActivity(); 402 403 View root = inflater.inflate(R.layout.bookmarks, container, false); 404 mEmptyView = root.findViewById(android.R.id.empty); 405 406 mGrid = (GridView) root.findViewById(R.id.grid); 407 mGrid.setOnItemClickListener(this); 408 mGrid.setColumnWidth(Controller.getDesiredThumbnailWidth(getActivity())); 409 mList = (ListView) root.findViewById(R.id.list); 410 mList.setOnItemClickListener(this); 411 setEnableContextMenu(mEnableContextMenu); 412 413 // Prep the header 414 ViewGroup hc = mHeaderContainer; 415 if (hc == null) { 416 hc = (ViewGroup) root.findViewById(R.id.header_container); 417 hc.setVisibility(View.VISIBLE); 418 } 419 mHeader = inflater.inflate(R.layout.bookmarks_header, hc, false); 420 hc.addView(mHeader); 421 mCrumbs = (BreadCrumbView) mHeader.findViewById(R.id.crumbs); 422 mCrumbs.setController(this); 423 mCrumbs.setUseBackButton(mCrumbBackButton); 424 mCrumbs.setMaxVisible(mCrumbMaxVisible); 425 mCrumbs.setVisibility(mCrumbVisibility); 426 String name = getString(R.string.bookmarks); 427 mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER); 428 if (mCallbacks != null) { 429 mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER); 430 } 431 mSelectBookmarkView = (TextView) mHeader.findViewById(R.id.select_bookmark_view); 432 mSelectBookmarkView.setOnClickListener(this); 433 434 // Start the loaders 435 LoaderManager lm = getLoaderManager(); 436 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 437 mCurrentView = 438 prefs.getInt(PREF_SELECTED_VIEW, BrowserBookmarksPage.VIEW_THUMBNAILS); 439 if (mCurrentView == BrowserBookmarksPage.VIEW_THUMBNAILS) { 440 mSelectBookmarkView.setText(R.string.bookmark_list_view); 441 } else { 442 mSelectBookmarkView.setText(R.string.bookmark_thumbnail_view); 443 } 444 mAdapter = new BrowserBookmarksAdapter(getActivity(), mCurrentView); 445 String accountType = prefs.getString(PREF_ACCOUNT_TYPE, DEFAULT_ACCOUNT); 446 String accountName = prefs.getString(PREF_ACCOUNT_NAME, DEFAULT_ACCOUNT); 447 if (!TextUtils.isEmpty(accountType) && !TextUtils.isEmpty(accountName)) { 448 // There is an account set, load up that one 449 Bundle args = null; 450 if (!DEFAULT_ACCOUNT.equals(accountType) && !DEFAULT_ACCOUNT.equals(accountName)) { 451 args = new Bundle(); 452 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType); 453 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName); 454 } 455 lm.restartLoader(LOADER_BOOKMARKS, args, this); 456 } else { 457 // No account set, load the account list first 458 lm.restartLoader(LOADER_ACCOUNTS_THEN_BOOKMARKS, null, this); 459 } 460 461 // Add our own listener in case there are favicons that have yet to be loaded. 462 CombinedBookmarkHistoryView.getIconListenerSet().addListener(this); 463 464 return root; 465 } 466 467 @Override 468 public void onDestroyView() { 469 super.onDestroyView(); 470 if (mHeaderContainer != null) { 471 mHeaderContainer.removeView(mHeader); 472 } 473 mCrumbs.setController(null); 474 mCrumbs = null; 475 } 476 477 @Override 478 public void onReceivedIcon(String url, Bitmap icon) { 479 // A new favicon has been loaded, so let anything attached to the adapter know about it 480 // so new icons will be loaded. 481 mAdapter.notifyDataSetChanged(); 482 } 483 484 @Override 485 public void onItemClick(AdapterView<?> parent, View v, int position, long id) { 486 // It is possible that the view has been canceled when we get to 487 // this point as back has a higher priority 488 if (mCanceled) { 489 android.util.Log.e(LOGTAG, "item clicked when dismissing"); 490 return; 491 } 492 493 Cursor cursor = mAdapter.getItem(position); 494 boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0; 495 if (mCallbacks != null && 496 mCallbacks.onBookmarkSelected(cursor, isFolder)) { 497 return; 498 } 499 500 if (isFolder) { 501 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 502 Uri uri = ContentUris.withAppendedId( 503 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id); 504 if (mCrumbs != null) { 505 // update crumbs 506 mCrumbs.pushView(title, uri); 507 } 508 loadFolder(uri); 509 } 510 } 511 512 @Override 513 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 514 Adapter adapter = parent.getAdapter(); 515 String accountType = "com.google"; 516 String accountName = adapter.getItem(position).toString(); 517 518 Bundle args = null; 519 if (ACCOUNT_NAME_UNSYNCED.equals(accountName)) { 520 accountType = DEFAULT_ACCOUNT; 521 accountName = DEFAULT_ACCOUNT; 522 } else { 523 args = new Bundle(); 524 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType); 525 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName); 526 } 527 528 // Remember the selection for later 529 PreferenceManager.getDefaultSharedPreferences(getActivity()).edit() 530 .putString(PREF_ACCOUNT_TYPE, accountType) 531 .putString(PREF_ACCOUNT_NAME, accountName) 532 .apply(); 533 534 getLoaderManager().restartLoader(LOADER_BOOKMARKS, args, this); 535 } 536 537 @Override 538 public void onNothingSelected(AdapterView<?> parent) { 539 // Do nothing 540 } 541 542 /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) { 543 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 544 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 545 Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON); 546 Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON); 547 return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon); 548 } 549 550 private void loadUrl(int position) { 551 if (mCallbacks != null) { 552 mCallbacks.onBookmarkSelected(mAdapter.getItem(position), false); 553 } 554 } 555 556 private void openInNewWindow(int position) { 557 if (mCallbacks != null) { 558 mCallbacks.onOpenInNewWindow(mAdapter.getItem(position)); 559 } 560 } 561 562 private void editBookmark(int position) { 563 Intent intent = new Intent(getActivity(), AddBookmarkPage.class); 564 Cursor cursor = mAdapter.getItem(position); 565 Bundle item = new Bundle(); 566 item.putString(BrowserContract.Bookmarks.TITLE, 567 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE)); 568 item.putString(BrowserContract.Bookmarks.URL, 569 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL)); 570 byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON); 571 if (data != null) { 572 item.putParcelable(BrowserContract.Bookmarks.FAVICON, 573 BitmapFactory.decodeByteArray(data, 0, data.length)); 574 } 575 item.putLong(BrowserContract.Bookmarks._ID, 576 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID)); 577 item.putLong(BrowserContract.Bookmarks.PARENT, 578 cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT)); 579 intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item); 580 intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER, 581 cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1); 582 startActivity(intent); 583 } 584 585 private void displayRemoveBookmarkDialog(final int position) { 586 // Put up a dialog asking if the user really wants to 587 // delete the bookmark 588 Cursor cursor = mAdapter.getItem(position); 589 Context context = getActivity(); 590 final ContentResolver resolver = context.getContentResolver(); 591 final Uri uri = ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, 592 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID)); 593 594 new AlertDialog.Builder(context) 595 .setTitle(R.string.delete_bookmark) 596 .setIcon(android.R.drawable.ic_dialog_alert) 597 .setMessage(context.getString(R.string.delete_bookmark_warning, 598 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE))) 599 .setPositiveButton(R.string.ok, 600 new DialogInterface.OnClickListener() { 601 @Override 602 public void onClick(DialogInterface dialog, int whichButton) { 603 resolver.delete(uri, null, null); 604 } 605 }) 606 .setNegativeButton(R.string.cancel, null) 607 .show(); 608 } 609 610 private String getUrl(int position) { 611 return getUrl(mAdapter.getItem(position)); 612 } 613 614 /* package */ static String getUrl(Cursor c) { 615 return c.getString(BookmarksLoader.COLUMN_INDEX_URL); 616 } 617 618 private void copy(CharSequence text) { 619 ClipboardManager cm = (ClipboardManager) getActivity().getSystemService( 620 Context.CLIPBOARD_SERVICE); 621 cm.setPrimaryClip(ClipData.newRawUri(null, null, Uri.parse(text.toString()))); 622 } 623 624 void selectView(int view) { 625 if (view == mCurrentView) { 626 return; 627 } 628 mCurrentView = view; 629 if (mCurrentView == BrowserBookmarksPage.VIEW_THUMBNAILS) { 630 mSelectBookmarkView.setText(R.string.bookmark_list_view); 631 } else { 632 mSelectBookmarkView.setText(R.string.bookmark_thumbnail_view); 633 } 634 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); 635 Editor edit = prefs.edit(); 636 edit.putInt(PREF_SELECTED_VIEW, mCurrentView); 637 edit.apply(); 638 if (mEmptyView.getVisibility() == View.VISIBLE) { 639 return; 640 } 641 setupBookmarkView(); 642 } 643 644 private void setupBookmarkView() { 645 mAdapter.selectView(mCurrentView); 646 switch (mCurrentView) { 647 case VIEW_THUMBNAILS: 648 mList.setAdapter(null); 649 mGrid.setAdapter(mAdapter); 650 mGrid.setVisibility(View.VISIBLE); 651 mList.setVisibility(View.GONE); 652 break; 653 case VIEW_LIST: 654 mGrid.setAdapter(null); 655 mList.setAdapter(mAdapter); 656 mGrid.setVisibility(View.GONE); 657 mList.setVisibility(View.VISIBLE); 658 break; 659 } 660 } 661 662 /** 663 * BreadCrumb controller callback 664 */ 665 @Override 666 public void onTop(int level, Object data) { 667 Uri uri = (Uri) data; 668 if (uri == null) { 669 // top level 670 uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER; 671 } 672 loadFolder(uri); 673 } 674 675 /** 676 * @param uri 677 */ 678 private void loadFolder(Uri uri) { 679 LoaderManager manager = getLoaderManager(); 680 BookmarksLoader loader = 681 (BookmarksLoader) ((Loader<?>) manager.getLoader(LOADER_BOOKMARKS)); 682 loader.setUri(uri); 683 loader.forceLoad(); 684 if (mCallbacks != null) { 685 mCallbacks.onFolderChanged(mCrumbs.getTopLevel(), uri); 686 } 687 } 688 689 @Override 690 public void onClick(View view) { 691 if (mSelectBookmarkView == view) { 692 selectView(mCurrentView == BrowserBookmarksPage.VIEW_LIST 693 ? BrowserBookmarksPage.VIEW_THUMBNAILS 694 : BrowserBookmarksPage.VIEW_LIST); 695 } 696 } 697 698 @Override 699 public boolean onMenuItemClick(MenuItem item) { 700 switch (item.getItemId()) { 701 case R.id.list_view: 702 selectView(BrowserBookmarksPage.VIEW_LIST); 703 return true; 704 case R.id.thumbnail_view: 705 selectView(BrowserBookmarksPage.VIEW_THUMBNAILS); 706 return true; 707 } 708 return false; 709 } 710 711 public boolean onBackPressed() { 712 if (canGoBack()) { 713 mCrumbs.popView(); 714 return true; 715 } 716 return false; 717 } 718 719 private boolean canGoBack() { 720 Crumb c = mCrumbs.getTopCrumb(); 721 return c != null && c.canGoBack; 722 } 723 724 public void setCallbackListener(BookmarksPageCallbacks callbackListener) { 725 mCallbacks = callbackListener; 726 } 727 728 public void setEnableContextMenu(boolean enable) { 729 mEnableContextMenu = enable; 730 if (mGrid != null) { 731 if (mEnableContextMenu) { 732 registerForContextMenu(mGrid); 733 } else { 734 unregisterForContextMenu(mGrid); 735 mGrid.setLongClickable(false); 736 } 737 } 738 if (mList != null) { 739 if (mEnableContextMenu) { 740 registerForContextMenu(mList); 741 } else { 742 unregisterForContextMenu(mList); 743 mList.setLongClickable(false); 744 } 745 } 746 } 747 748 private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> { 749 Context mContext; 750 BookmarkItem mHeader; 751 752 public LookupBookmarkCount(Context context, BookmarkItem header) { 753 mContext = context; 754 mHeader = header; 755 } 756 757 @Override 758 protected Integer doInBackground(Long... params) { 759 if (params.length != 1) { 760 throw new IllegalArgumentException("Missing folder id!"); 761 } 762 Uri uri = BookmarkUtils.getBookmarksUri(mContext); 763 Cursor c = mContext.getContentResolver().query(uri, 764 null, BrowserContract.Bookmarks.PARENT + "=?", 765 new String[] {params[0].toString()}, null); 766 return c.getCount(); 767 } 768 769 @Override 770 protected void onPostExecute(Integer result) { 771 if (result > 0) { 772 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount, 773 result)); 774 } else if (result == 0) { 775 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty)); 776 } 777 } 778 } 779 780 public void setBreadCrumbVisibility(int visibility) { 781 mCrumbVisibility = visibility; 782 if (mCrumbs != null) { 783 mCrumbs.setVisibility(mCrumbVisibility); 784 } 785 } 786 787 public void setBreadCrumbUseBackButton(boolean use) { 788 mCrumbBackButton = use; 789 if (mCrumbs != null) { 790 mCrumbs.setUseBackButton(mCrumbBackButton); 791 } 792 } 793 794 public void setBreadCrumbMaxVisible(int max) { 795 mCrumbMaxVisible = max; 796 if (mCrumbs != null) { 797 mCrumbs.setMaxVisible(mCrumbMaxVisible); 798 } 799 } 800} 801