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