BrowserBookmarksPage.java revision 71e76c71d8fb70433a60521dfdbcd4e7a8762ef8
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 public void onLoaderReset(Loader<Cursor> loader) { 235 onLoadFinished(loader, null); 236 switch (loader.getId()) { 237 case LOADER_BOOKMARKS: { 238 onLoadFinished(loader, null); 239 break; 240 } 241 } 242 } 243 244 long getFolderId() { 245 LoaderManager manager = getLoaderManager(); 246 BookmarksLoader loader = 247 (BookmarksLoader) ((Loader<?>)manager.getLoader(LOADER_BOOKMARKS)); 248 249 Uri uri = loader.getUri(); 250 if (uri != null) { 251 try { 252 return ContentUris.parseId(uri); 253 } catch (NumberFormatException nfx) { 254 return -1; 255 } 256 } 257 return -1; 258 } 259 260 @Override 261 public boolean onContextItemSelected(MenuItem item) { 262 final Activity activity = getActivity(); 263 // It is possible that the view has been canceled when we get to 264 // this point as back has a higher priority 265 if (mCanceled) { 266 return false; 267 } 268 AdapterView.AdapterContextMenuInfo i = 269 (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); 270 // If we have no menu info, we can't tell which item was selected. 271 if (i == null) { 272 return false; 273 } 274 275 switch (item.getItemId()) { 276 case R.id.open_context_menu_id: 277 loadUrl(i.position); 278 break; 279 case R.id.edit_context_menu_id: 280 editBookmark(i.position); 281 break; 282 case R.id.shortcut_context_menu_id: 283 Cursor c = mAdapter.getItem(i.position); 284 activity.sendBroadcast(createShortcutIntent(getActivity(), c)); 285 break; 286 case R.id.delete_context_menu_id: 287 displayRemoveBookmarkDialog(i.position); 288 break; 289 case R.id.new_window_context_menu_id: 290 openInNewWindow(i.position); 291 break; 292 case R.id.share_link_context_menu_id: { 293 Cursor cursor = mAdapter.getItem(i.position); 294 Controller.sharePage(activity, 295 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE), 296 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL), 297 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON), 298 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL)); 299 break; 300 } 301 case R.id.copy_url_context_menu_id: 302 copy(getUrl(i.position)); 303 break; 304 case R.id.homepage_context_menu_id: { 305 BrowserSettings.getInstance().setHomePage(activity, getUrl(i.position)); 306 Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show(); 307 break; 308 } 309 // Only for the Most visited page 310 case R.id.save_to_bookmarks_menu_id: { 311 Cursor cursor = mAdapter.getItem(i.position); 312 String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 313 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 314 // If the site is bookmarked, the item becomes remove from 315 // bookmarks. 316 Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name); 317 break; 318 } 319 default: 320 return super.onContextItemSelected(item); 321 } 322 return true; 323 } 324 325 static Bitmap getBitmap(Cursor cursor, int columnIndex) { 326 byte[] data = cursor.getBlob(columnIndex); 327 if (data == null) { 328 return null; 329 } 330 return BitmapFactory.decodeByteArray(data, 0, data.length); 331 } 332 333 private MenuItem.OnMenuItemClickListener mContextItemClickListener = 334 new MenuItem.OnMenuItemClickListener() { 335 @Override 336 public boolean onMenuItemClick(MenuItem item) { 337 return onContextItemSelected(item); 338 } 339 }; 340 341 @Override 342 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 343 AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; 344 Cursor cursor = mAdapter.getItem(info.position); 345 if (!canEdit(cursor)) { 346 return; 347 } 348 boolean isFolder 349 = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0; 350 351 final Activity activity = getActivity(); 352 MenuInflater inflater = activity.getMenuInflater(); 353 inflater.inflate(R.menu.bookmarkscontext, menu); 354 if (isFolder) { 355 menu.setGroupVisible(R.id.FOLDER_CONTEXT_MENU, true); 356 } else { 357 menu.setGroupVisible(R.id.BOOKMARK_CONTEXT_MENU, true); 358 if (mDisableNewWindow) { 359 menu.findItem(R.id.new_window_context_menu_id).setVisible(false); 360 } 361 } 362 BookmarkItem header = new BookmarkItem(activity); 363 populateBookmarkItem(cursor, header, isFolder); 364 menu.setHeaderView(header); 365 366 int count = menu.size(); 367 for (int i = 0; i < count; i++) { 368 menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener); 369 } 370 } 371 372 boolean canEdit(Cursor c) { 373 String unique = c.getString(BookmarksLoader.COLUMN_INDEX_SERVER_UNIQUE); 374 return !ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS.equals(unique); 375 } 376 377 private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) { 378 item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE)); 379 if (isFolder) { 380 item.setUrl(null); 381 Bitmap bitmap = 382 BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder_bookmark_widget_holo_dark); 383 item.setFavicon(bitmap); 384 new LookupBookmarkCount(getActivity(), item) 385 .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID)); 386 } else { 387 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 388 item.setUrl(url); 389 Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON); 390 if (bitmap == null) { 391 bitmap = CombinedBookmarkHistoryView.getIconListenerSet().getFavicon(url); 392 } 393 item.setFavicon(bitmap); 394 } 395 } 396 397 /** 398 * Create a new BrowserBookmarksPage. 399 */ 400 @Override 401 public void onCreate(Bundle icicle) { 402 super.onCreate(icicle); 403 404 Bundle args = getArguments(); 405 mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false); 406 } 407 408 @Override 409 public View onCreateView(LayoutInflater inflater, ViewGroup container, 410 Bundle savedInstanceState) { 411 Context context = getActivity(); 412 413 View root = inflater.inflate(R.layout.bookmarks, container, false); 414 mEmptyView = root.findViewById(android.R.id.empty); 415 416 mGrid = (GridView) root.findViewById(R.id.grid); 417 mGrid.setOnItemClickListener(this); 418 mGrid.setColumnWidth(Controller.getDesiredThumbnailWidth(getActivity())); 419 mList = (ListView) root.findViewById(R.id.list); 420 mList.setOnItemClickListener(this); 421 setEnableContextMenu(mEnableContextMenu); 422 423 // Prep the header 424 ViewGroup hc = mHeaderContainer; 425 if (hc == null) { 426 hc = (ViewGroup) root.findViewById(R.id.header_container); 427 hc.setVisibility(View.VISIBLE); 428 } 429 mHeader = inflater.inflate(R.layout.bookmarks_header, hc, false); 430 hc.addView(mHeader); 431 mCrumbs = (BreadCrumbView) mHeader.findViewById(R.id.crumbs); 432 mCrumbs.setController(this); 433 mCrumbs.setUseBackButton(mCrumbBackButton); 434 mCrumbs.setMaxVisible(mCrumbMaxVisible); 435 mCrumbs.setVisibility(mCrumbVisibility); 436 String name = getString(R.string.bookmarks); 437 mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER); 438 if (mCallbacks != null) { 439 mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER); 440 } 441 mSelectBookmarkView = (TextView) mHeader.findViewById(R.id.select_bookmark_view); 442 mSelectBookmarkView.setOnClickListener(this); 443 444 // Start the loaders 445 LoaderManager lm = getLoaderManager(); 446 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 447 mCurrentView = 448 prefs.getInt(PREF_SELECTED_VIEW, BrowserBookmarksPage.VIEW_THUMBNAILS); 449 if (mCurrentView == BrowserBookmarksPage.VIEW_THUMBNAILS) { 450 mSelectBookmarkView.setText(R.string.bookmark_list_view); 451 } else { 452 mSelectBookmarkView.setText(R.string.bookmark_thumbnail_view); 453 } 454 mAdapter = new BrowserBookmarksAdapter(getActivity(), mCurrentView); 455 String accountType = prefs.getString(PREF_ACCOUNT_TYPE, DEFAULT_ACCOUNT); 456 String accountName = prefs.getString(PREF_ACCOUNT_NAME, DEFAULT_ACCOUNT); 457 if (!TextUtils.isEmpty(accountType) && !TextUtils.isEmpty(accountName)) { 458 // There is an account set, load up that one 459 Bundle args = null; 460 if (!DEFAULT_ACCOUNT.equals(accountType) && !DEFAULT_ACCOUNT.equals(accountName)) { 461 args = new Bundle(); 462 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType); 463 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName); 464 } 465 lm.restartLoader(LOADER_BOOKMARKS, args, this); 466 } else { 467 // No account set, load the account list first 468 lm.restartLoader(LOADER_ACCOUNTS_THEN_BOOKMARKS, null, this); 469 } 470 471 // Add our own listener in case there are favicons that have yet to be loaded. 472 CombinedBookmarkHistoryView.getIconListenerSet().addListener(this); 473 474 return root; 475 } 476 477 @Override 478 public void onDestroyView() { 479 super.onDestroyView(); 480 if (mHeaderContainer != null) { 481 mHeaderContainer.removeView(mHeader); 482 } 483 mCrumbs.setController(null); 484 mCrumbs = null; 485 getLoaderManager().destroyLoader(LOADER_BOOKMARKS); 486 } 487 488 @Override 489 public void onReceivedIcon(String url, Bitmap icon) { 490 // A new favicon has been loaded, so let anything attached to the adapter know about it 491 // so new icons will be loaded. 492 mAdapter.notifyDataSetChanged(); 493 } 494 495 @Override 496 public void onItemClick(AdapterView<?> parent, View v, int position, long id) { 497 // It is possible that the view has been canceled when we get to 498 // this point as back has a higher priority 499 if (mCanceled) { 500 android.util.Log.e(LOGTAG, "item clicked when dismissing"); 501 return; 502 } 503 504 Cursor cursor = mAdapter.getItem(position); 505 boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0; 506 if (mCallbacks != null && 507 mCallbacks.onBookmarkSelected(cursor, isFolder)) { 508 return; 509 } 510 511 if (isFolder) { 512 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 513 Uri uri = ContentUris.withAppendedId( 514 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id); 515 if (mCrumbs != null) { 516 // update crumbs 517 mCrumbs.pushView(title, uri); 518 } 519 loadFolder(uri); 520 } 521 } 522 523 @Override 524 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 525 Adapter adapter = parent.getAdapter(); 526 String accountType = "com.google"; 527 String accountName = adapter.getItem(position).toString(); 528 529 Bundle args = null; 530 if (ACCOUNT_NAME_UNSYNCED.equals(accountName)) { 531 accountType = DEFAULT_ACCOUNT; 532 accountName = DEFAULT_ACCOUNT; 533 } else { 534 args = new Bundle(); 535 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType); 536 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName); 537 } 538 539 // Remember the selection for later 540 PreferenceManager.getDefaultSharedPreferences(getActivity()).edit() 541 .putString(PREF_ACCOUNT_TYPE, accountType) 542 .putString(PREF_ACCOUNT_NAME, accountName) 543 .apply(); 544 545 getLoaderManager().restartLoader(LOADER_BOOKMARKS, args, this); 546 } 547 548 @Override 549 public void onNothingSelected(AdapterView<?> parent) { 550 // Do nothing 551 } 552 553 /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) { 554 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 555 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 556 Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON); 557 Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON); 558 return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon); 559 } 560 561 private void loadUrl(int position) { 562 if (mCallbacks != null) { 563 mCallbacks.onBookmarkSelected(mAdapter.getItem(position), false); 564 } 565 } 566 567 private void openInNewWindow(int position) { 568 if (mCallbacks != null) { 569 mCallbacks.onOpenInNewWindow(mAdapter.getItem(position)); 570 } 571 } 572 573 private void editBookmark(int position) { 574 Intent intent = new Intent(getActivity(), AddBookmarkPage.class); 575 Cursor cursor = mAdapter.getItem(position); 576 Bundle item = new Bundle(); 577 item.putString(BrowserContract.Bookmarks.TITLE, 578 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE)); 579 item.putString(BrowserContract.Bookmarks.URL, 580 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL)); 581 byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON); 582 if (data != null) { 583 item.putParcelable(BrowserContract.Bookmarks.FAVICON, 584 BitmapFactory.decodeByteArray(data, 0, data.length)); 585 } 586 item.putLong(BrowserContract.Bookmarks._ID, 587 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID)); 588 item.putLong(BrowserContract.Bookmarks.PARENT, 589 cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT)); 590 intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item); 591 intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER, 592 cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1); 593 startActivity(intent); 594 } 595 596 private void displayRemoveBookmarkDialog(final int position) { 597 // Put up a dialog asking if the user really wants to 598 // delete the bookmark 599 Cursor cursor = mAdapter.getItem(position); 600 Context context = getActivity(); 601 final ContentResolver resolver = context.getContentResolver(); 602 final Uri uri = ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, 603 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID)); 604 605 new AlertDialog.Builder(context) 606 .setTitle(R.string.delete_bookmark) 607 .setIcon(android.R.drawable.ic_dialog_alert) 608 .setMessage(context.getString(R.string.delete_bookmark_warning, 609 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE))) 610 .setPositiveButton(R.string.ok, 611 new DialogInterface.OnClickListener() { 612 @Override 613 public void onClick(DialogInterface dialog, int whichButton) { 614 resolver.delete(uri, null, null); 615 } 616 }) 617 .setNegativeButton(R.string.cancel, null) 618 .show(); 619 } 620 621 private String getUrl(int position) { 622 return getUrl(mAdapter.getItem(position)); 623 } 624 625 /* package */ static String getUrl(Cursor c) { 626 return c.getString(BookmarksLoader.COLUMN_INDEX_URL); 627 } 628 629 private void copy(CharSequence text) { 630 ClipboardManager cm = (ClipboardManager) getActivity().getSystemService( 631 Context.CLIPBOARD_SERVICE); 632 cm.setPrimaryClip(ClipData.newRawUri(null, null, Uri.parse(text.toString()))); 633 } 634 635 void selectView(int view) { 636 if (view == mCurrentView) { 637 return; 638 } 639 mCurrentView = view; 640 if (mCurrentView == BrowserBookmarksPage.VIEW_THUMBNAILS) { 641 mSelectBookmarkView.setText(R.string.bookmark_list_view); 642 } else { 643 mSelectBookmarkView.setText(R.string.bookmark_thumbnail_view); 644 } 645 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); 646 Editor edit = prefs.edit(); 647 edit.putInt(PREF_SELECTED_VIEW, mCurrentView); 648 edit.apply(); 649 if (mEmptyView.getVisibility() == View.VISIBLE) { 650 return; 651 } 652 setupBookmarkView(); 653 } 654 655 private void setupBookmarkView() { 656 mAdapter.selectView(mCurrentView); 657 switch (mCurrentView) { 658 case VIEW_THUMBNAILS: 659 mList.setAdapter(null); 660 mGrid.setAdapter(mAdapter); 661 mGrid.setVisibility(View.VISIBLE); 662 mList.setVisibility(View.GONE); 663 break; 664 case VIEW_LIST: 665 mGrid.setAdapter(null); 666 mList.setAdapter(mAdapter); 667 mGrid.setVisibility(View.GONE); 668 mList.setVisibility(View.VISIBLE); 669 break; 670 } 671 } 672 673 /** 674 * BreadCrumb controller callback 675 */ 676 @Override 677 public void onTop(int level, Object data) { 678 Uri uri = (Uri) data; 679 if (uri == null) { 680 // top level 681 uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER; 682 } 683 loadFolder(uri); 684 } 685 686 /** 687 * @param uri 688 */ 689 private void loadFolder(Uri uri) { 690 LoaderManager manager = getLoaderManager(); 691 BookmarksLoader loader = 692 (BookmarksLoader) ((Loader<?>) manager.getLoader(LOADER_BOOKMARKS)); 693 loader.setUri(uri); 694 loader.forceLoad(); 695 if (mCallbacks != null) { 696 mCallbacks.onFolderChanged(mCrumbs.getTopLevel(), uri); 697 } 698 } 699 700 @Override 701 public void onClick(View view) { 702 if (mSelectBookmarkView == view) { 703 selectView(mCurrentView == BrowserBookmarksPage.VIEW_LIST 704 ? BrowserBookmarksPage.VIEW_THUMBNAILS 705 : BrowserBookmarksPage.VIEW_LIST); 706 } 707 } 708 709 @Override 710 public boolean onMenuItemClick(MenuItem item) { 711 switch (item.getItemId()) { 712 case R.id.list_view: 713 selectView(BrowserBookmarksPage.VIEW_LIST); 714 return true; 715 case R.id.thumbnail_view: 716 selectView(BrowserBookmarksPage.VIEW_THUMBNAILS); 717 return true; 718 } 719 return false; 720 } 721 722 public boolean onBackPressed() { 723 if (canGoBack()) { 724 mCrumbs.popView(); 725 return true; 726 } 727 return false; 728 } 729 730 private boolean canGoBack() { 731 Crumb c = mCrumbs.getTopCrumb(); 732 return c != null && c.canGoBack; 733 } 734 735 public void setCallbackListener(BookmarksPageCallbacks callbackListener) { 736 mCallbacks = callbackListener; 737 } 738 739 public void setEnableContextMenu(boolean enable) { 740 mEnableContextMenu = enable; 741 if (mGrid != null) { 742 if (mEnableContextMenu) { 743 registerForContextMenu(mGrid); 744 } else { 745 unregisterForContextMenu(mGrid); 746 mGrid.setLongClickable(false); 747 } 748 } 749 if (mList != null) { 750 if (mEnableContextMenu) { 751 registerForContextMenu(mList); 752 } else { 753 unregisterForContextMenu(mList); 754 mList.setLongClickable(false); 755 } 756 } 757 } 758 759 private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> { 760 Context mContext; 761 BookmarkItem mHeader; 762 763 public LookupBookmarkCount(Context context, BookmarkItem header) { 764 mContext = context; 765 mHeader = header; 766 } 767 768 @Override 769 protected Integer doInBackground(Long... params) { 770 if (params.length != 1) { 771 throw new IllegalArgumentException("Missing folder id!"); 772 } 773 Uri uri = BookmarkUtils.getBookmarksUri(mContext); 774 Cursor c = mContext.getContentResolver().query(uri, 775 null, BrowserContract.Bookmarks.PARENT + "=?", 776 new String[] {params[0].toString()}, null); 777 return c.getCount(); 778 } 779 780 @Override 781 protected void onPostExecute(Integer result) { 782 if (result > 0) { 783 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount, 784 result)); 785 } else if (result == 0) { 786 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty)); 787 } 788 } 789 } 790 791 public void setBreadCrumbVisibility(int visibility) { 792 mCrumbVisibility = visibility; 793 if (mCrumbs != null) { 794 mCrumbs.setVisibility(mCrumbVisibility); 795 } 796 } 797 798 public void setBreadCrumbUseBackButton(boolean use) { 799 mCrumbBackButton = use; 800 if (mCrumbs != null) { 801 mCrumbs.setUseBackButton(mCrumbBackButton); 802 } 803 } 804 805 public void setBreadCrumbMaxVisible(int max) { 806 mCrumbMaxVisible = max; 807 if (mCrumbs != null) { 808 mCrumbs.setMaxVisible(mCrumbMaxVisible); 809 } 810 } 811} 812