BrowserBookmarksPage.java revision 7f6cf3e4109426164c6fdd11aba0c69622e2353c
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 android.app.Activity; 20import android.app.AlertDialog; 21import android.app.Fragment; 22import android.app.LoaderManager; 23import android.content.ClipData; 24import android.content.ClipboardManager; 25import android.content.ContentResolver; 26import android.content.ContentUris; 27import android.content.ContentValues; 28import android.content.Context; 29import android.content.CursorLoader; 30import android.content.DialogInterface; 31import android.content.Intent; 32import android.content.Loader; 33import android.content.SharedPreferences; 34import android.database.Cursor; 35import android.graphics.Bitmap; 36import android.graphics.BitmapFactory; 37import android.net.Uri; 38import android.os.Bundle; 39import android.preference.PreferenceManager; 40import android.provider.BrowserContract; 41import android.provider.BrowserContract.Accounts; 42import android.text.TextUtils; 43import android.util.Pair; 44import android.view.ContextMenu; 45import android.view.ContextMenu.ContextMenuInfo; 46import android.view.LayoutInflater; 47import android.view.MenuInflater; 48import android.view.MenuItem; 49import android.view.View; 50import android.view.View.OnClickListener; 51import android.view.ViewGroup; 52import android.webkit.WebIconDatabase.IconListener; 53import android.widget.Adapter; 54import android.widget.AdapterView; 55import android.widget.AdapterView.OnItemClickListener; 56import android.widget.AdapterView.OnItemSelectedListener; 57import android.widget.ArrayAdapter; 58import android.widget.Button; 59import android.widget.GridView; 60import android.widget.Spinner; 61import android.widget.Toast; 62 63import java.util.ArrayList; 64import java.util.Stack; 65 66/** 67 * View showing the user's bookmarks in the browser. 68 */ 69public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener, 70 LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, IconListener, OnClickListener, 71 OnItemSelectedListener { 72 73 static final int BOOKMARKS_SAVE = 1; 74 static final String LOGTAG = "browser"; 75 76 static final int LOADER_BOOKMARKS = 1; 77 static final int LOADER_ACCOUNTS = 2; 78 static final int LOADER_ACCOUNTS_THEN_BOOKMARKS = 3; 79 80 static final String EXTRA_SHORTCUT = "create_shortcut"; 81 static final String EXTRA_DISABLE_WINDOW = "disable_new_window"; 82 83 public static final String PREF_ACCOUNT_TYPE = "acct_type"; 84 public static final String PREF_ACCOUNT_NAME = "acct_name"; 85 86 static final String DEFAULT_ACCOUNT = "local"; 87 88 BookmarksHistoryCallbacks mCallbacks; 89 GridView mGrid; 90 Spinner mAccountSelector; 91 BrowserBookmarksAdapter mAdapter; 92 boolean mDisableNewWindow; 93 BookmarkItem mContextHeader; 94 boolean mCanceled = false; 95 boolean mCreateShortcut; 96 View mEmptyView; 97 View mContentView; 98 Stack<Pair<String, Uri>> mFolderStack = new Stack<Pair<String, Uri>>(); 99 Button mUpButton; 100 101 @Override 102 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 103 switch (id) { 104 case LOADER_BOOKMARKS: { 105 String accountType = null; 106 String accountName = null; 107 if (args != null) { 108 accountType = args.getString(BookmarksLoader.ARG_ACCOUNT_TYPE); 109 accountName = args.getString(BookmarksLoader.ARG_ACCOUNT_NAME); 110 } 111 return new BookmarksLoader(getActivity(), accountType, accountName); 112 } 113 114 case LOADER_ACCOUNTS: 115 case LOADER_ACCOUNTS_THEN_BOOKMARKS: { 116 return new CursorLoader(getActivity(), Accounts.CONTENT_URI, 117 new String[] { Accounts.ACCOUNT_TYPE, Accounts.ACCOUNT_NAME }, null, null, 118 null); 119 } 120 } 121 throw new UnsupportedOperationException("Unknown loader id " + id); 122 } 123 124 @Override 125 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 126 switch (loader.getId()) { 127 case LOADER_BOOKMARKS: { 128 // Set the visibility of the empty vs. content views 129 if (cursor == null || cursor.getCount() == 0) { 130 mEmptyView.setVisibility(View.VISIBLE); 131 mGrid.setVisibility(View.GONE); 132 } else { 133 mEmptyView.setVisibility(View.GONE); 134 mGrid.setVisibility(View.VISIBLE); 135 } 136 137 // Fill in the "up" button if needed 138 BookmarksLoader bl = (BookmarksLoader) loader; 139 String path = bl.getUri().getPath(); 140 boolean rootFolder = 141 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER.getPath().equals(path); 142 if (rootFolder) { 143 mUpButton.setText(R.string.defaultBookmarksUpButton); 144 mUpButton.setEnabled(false); 145 } else { 146 mUpButton.setText(mFolderStack.peek().first); 147 mUpButton.setEnabled(true); 148 } 149 mUpButton.setVisibility(View.VISIBLE); 150 151 // Give the new data to the adapter 152 mAdapter.changeCursor(cursor); 153 154 break; 155 } 156 157 case LOADER_ACCOUNTS: 158 case LOADER_ACCOUNTS_THEN_BOOKMARKS: { 159 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( 160 getActivity()); 161 String storedAccountType = prefs.getString(PREF_ACCOUNT_TYPE, null); 162 String storedAccountName = prefs.getString(PREF_ACCOUNT_NAME, null); 163 String accountType = 164 TextUtils.isEmpty(storedAccountType) ? DEFAULT_ACCOUNT : storedAccountType; 165 String accountName = 166 TextUtils.isEmpty(storedAccountName) ? DEFAULT_ACCOUNT : storedAccountName; 167 168 Bundle args = null; 169 if (cursor == null || !cursor.moveToFirst()) { 170 // No accounts, set the prefs to the default 171 accountType = DEFAULT_ACCOUNT; 172 accountName = DEFAULT_ACCOUNT; 173 mAccountSelector.setVisibility(View.GONE); 174 } else { 175 int accountPosition = -1; 176 177 if (!DEFAULT_ACCOUNT.equals(accountType) && 178 !DEFAULT_ACCOUNT.equals(accountName)) { 179 // Check to see if the account in prefs still exists 180 cursor.moveToFirst(); 181 do { 182 if (accountType.equals(cursor.getString(0)) 183 && accountName.equals(cursor.getString(1))) { 184 accountPosition = cursor.getPosition(); 185 break; 186 } 187 } while (cursor.moveToNext()); 188 } 189 190 if (accountPosition == -1) { 191 // No account is set in prefs and there is at least one, 192 // so pick the first one as the default 193 cursor.moveToFirst(); 194 accountType = cursor.getString(0); 195 accountName = cursor.getString(1); 196 accountPosition = 0; 197 } 198 199 args = new Bundle(); 200 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType); 201 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName); 202 203 // Setup the account selector if there is more than 1 account 204 if (cursor.getCount() > 1) { 205 ArrayList<String> accounts = new ArrayList<String>(); 206 cursor.moveToFirst(); 207 do { 208 accounts.add(cursor.getString(1)); 209 } while (cursor.moveToNext()); 210 211 mAccountSelector.setAdapter(new ArrayAdapter<String>(getActivity(), 212 android.R.layout.simple_list_item_1, android.R.id.text1, accounts)); 213 mAccountSelector.setVisibility(View.VISIBLE); 214 mAccountSelector.setSelection(accountPosition); 215 } 216 } 217 if (!accountType.equals(storedAccountType) 218 || !accountName.equals(storedAccountName)) { 219 prefs.edit() 220 .putString(PREF_ACCOUNT_TYPE, accountType) 221 .putString(PREF_ACCOUNT_NAME, accountName) 222 .apply(); 223 } 224 if (loader.getId() == LOADER_ACCOUNTS_THEN_BOOKMARKS) { 225 getLoaderManager().initLoader(LOADER_BOOKMARKS, args, this); 226 } 227 228 break; 229 } 230 } 231 } 232 233 @Override 234 public void onClick(View view) { 235 if (view == mUpButton) { 236 Pair<String, Uri> pair = mFolderStack.pop(); 237 BookmarksLoader loader = 238 (BookmarksLoader) ((Loader) getLoaderManager().getLoader(LOADER_BOOKMARKS)); 239 loader.setUri(pair.second); 240 loader.forceLoad(); 241 } 242 } 243 244 @Override 245 public boolean onContextItemSelected(MenuItem item) { 246 final Activity activity = getActivity(); 247 // It is possible that the view has been canceled when we get to 248 // this point as back has a higher priority 249 if (mCanceled) { 250 return true; 251 } 252 AdapterView.AdapterContextMenuInfo i = 253 (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); 254 // If we have no menu info, we can't tell which item was selected. 255 if (i == null) { 256 return true; 257 } 258 259 switch (item.getItemId()) { 260 case R.id.open_context_menu_id: 261 loadUrl(i.position); 262 break; 263 case R.id.edit_context_menu_id: 264 editBookmark(i.position); 265 break; 266 case R.id.shortcut_context_menu_id: 267 activity.sendBroadcast(createShortcutIntent(i.position)); 268 break; 269 case R.id.delete_context_menu_id: 270 displayRemoveBookmarkDialog(i.position); 271 break; 272 case R.id.new_window_context_menu_id: 273 openInNewWindow(i.position); 274 break; 275 case R.id.share_link_context_menu_id: { 276 Cursor cursor = (Cursor) mAdapter.getItem(i.position); 277 BrowserActivity.sharePage(activity, 278 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE), 279 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL), 280 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON), 281 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL)); 282 break; 283 } 284 case R.id.copy_url_context_menu_id: 285 copy(getUrl(i.position)); 286 break; 287 case R.id.homepage_context_menu_id: { 288 BrowserSettings.getInstance().setHomePage(activity, getUrl(i.position)); 289 Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show(); 290 break; 291 } 292 // Only for the Most visited page 293 case R.id.save_to_bookmarks_menu_id: { 294 Cursor cursor = (Cursor) mAdapter.getItem(i.position); 295 String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 296 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 297 // If the site is bookmarked, the item becomes remove from 298 // bookmarks. 299 Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name); 300 break; 301 } 302 default: 303 return super.onContextItemSelected(item); 304 } 305 return true; 306 } 307 308 Bitmap getBitmap(Cursor cursor, int columnIndex) { 309 byte[] data = cursor.getBlob(columnIndex); 310 if (data == null) { 311 return null; 312 } 313 return BitmapFactory.decodeByteArray(data, 0, data.length); 314 } 315 316 @Override 317 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 318 AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; 319 320 final Activity activity = getActivity(); 321 MenuInflater inflater = activity.getMenuInflater(); 322 inflater.inflate(R.menu.bookmarkscontext, menu); 323 324 if (mDisableNewWindow) { 325 menu.findItem(R.id.new_window_context_menu_id).setVisible(false); 326 } 327 328 if (mContextHeader == null) { 329 mContextHeader = new BookmarkItem(activity); 330 } else if (mContextHeader.getParent() != null) { 331 ((ViewGroup) mContextHeader.getParent()).removeView(mContextHeader); 332 } 333 334 populateBookmarkItem(mAdapter, mContextHeader, info.position); 335 336 menu.setHeaderView(mContextHeader); 337 } 338 339 private void populateBookmarkItem(BrowserBookmarksAdapter adapter, BookmarkItem item, 340 int position) { 341 Cursor cursor = (Cursor) mAdapter.getItem(position); 342 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 343 item.setUrl(url); 344 item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE)); 345 Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON); 346 if (bitmap == null) { 347 bitmap = CombinedBookmarkHistoryActivity.getIconListenerSet().getFavicon(url); 348 } 349 item.setFavicon(bitmap); 350 } 351 352 /** 353 * Create a new BrowserBookmarksPage. 354 */ 355 @Override 356 public void onCreate(Bundle icicle) { 357 super.onCreate(icicle); 358 359 Bundle args = getArguments(); 360 mCreateShortcut = args == null ? false : args.getBoolean("create_shortcut", false); 361 mDisableNewWindow = args == null ? false : args.getBoolean("disable_new_window", false); 362 } 363 364 @Override 365 public void onAttach(Activity activity) { 366 super.onAttach(activity); 367 mCallbacks = (BookmarksHistoryCallbacks) activity; 368 } 369 370 @Override 371 public View onCreateView(LayoutInflater inflater, ViewGroup container, 372 Bundle savedInstanceState) { 373 Context context = getActivity(); 374 375 View root = inflater.inflate(R.layout.bookmarks, container, false); 376 mEmptyView = root.findViewById(android.R.id.empty); 377 mContentView = root.findViewById(android.R.id.content); 378 379 mGrid = (GridView) root.findViewById(R.id.grid); 380 mGrid.setOnItemClickListener(this); 381 mGrid.setColumnWidth(BrowserActivity.getDesiredThumbnailWidth(getActivity())); 382 if (!mCreateShortcut) { 383 mGrid.setOnCreateContextMenuListener(this); 384 } 385 386 mAccountSelector = (Spinner) root.findViewById(R.id.accounts); 387 mAccountSelector.setOnItemSelectedListener(this); 388 mAccountSelector.setVisibility(View.INVISIBLE); 389 390 mUpButton = (Button) root.findViewById(R.id.up); 391 mUpButton.setEnabled(false); 392 mUpButton.setOnClickListener(this); 393 mUpButton.setVisibility(View.GONE); 394 395 mAdapter = new BrowserBookmarksAdapter(getActivity()); 396 mGrid.setAdapter(mAdapter); 397 398 // Start the loaders 399 LoaderManager lm = getLoaderManager(); 400 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 401 String accountType = prefs.getString(PREF_ACCOUNT_TYPE, null); 402 String accountName = prefs.getString(PREF_ACCOUNT_NAME, null); 403 if (!TextUtils.isEmpty(accountType) && !TextUtils.isEmpty(accountName)) { 404 // There is an account set, load up that one 405 Bundle args = null; 406 if (!DEFAULT_ACCOUNT.equals(accountType) && !DEFAULT_ACCOUNT.equals(accountName)) { 407 args = new Bundle(); 408 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType); 409 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName); 410 } 411 lm.initLoader(LOADER_BOOKMARKS, args, this); 412 lm.initLoader(LOADER_ACCOUNTS, null, this); 413 } else { 414 // No account set, load them first 415 lm.initLoader(LOADER_ACCOUNTS_THEN_BOOKMARKS, null, this); 416 } 417 418 // Add our own listener in case there are favicons that have yet to be loaded. 419 CombinedBookmarkHistoryActivity.getIconListenerSet().addListener(this); 420 421 return root; 422 } 423 424 @Override 425 public void onReceivedIcon(String url, Bitmap icon) { 426 // A new favicon has been loaded, so let anything attached to the adapter know about it 427 // so new icons will be loaded. 428 mAdapter.notifyDataSetChanged(); 429 } 430 431 @Override 432 public void onItemClick(AdapterView parent, View v, int position, long id) { 433 // It is possible that the view has been canceled when we get to 434 // this point as back has a higher priority 435 if (mCanceled) { 436 android.util.Log.e(LOGTAG, "item clicked when dismissing"); 437 return; 438 } 439 440 if (mCreateShortcut) { 441 Intent intent = createShortcutIntent(position); 442 // the activity handles the intent in startActivityFromFragment 443 startActivity(intent); 444 return; 445 } 446 447 Cursor cursor = (Cursor) mAdapter.getItem(position); 448 boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0; 449 if (!isFolder) { 450 mCallbacks.onUrlSelected(getUrl(position), false); 451 } else { 452 String title; 453 if (mFolderStack.size() != 0) { 454 title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 455 } else { 456 // TODO localize 457 title = "Bookmarks"; 458 } 459 LoaderManager manager = getLoaderManager(); 460 BookmarksLoader loader = 461 (BookmarksLoader) ((Loader) manager.getLoader(LOADER_BOOKMARKS)); 462 mFolderStack.push(new Pair(title, loader.getUri())); 463 Uri uri = ContentUris.withAppendedId( 464 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id); 465 loader.setUri(uri); 466 loader.forceLoad(); 467 } 468 } 469 470 @Override 471 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 472 Adapter adapter = parent.getAdapter(); 473 String accountType = "com.google"; 474 String accountName = adapter.getItem(position).toString(); 475 476 // Remember the selection for later 477 PreferenceManager.getDefaultSharedPreferences(getActivity()).edit() 478 .putString(PREF_ACCOUNT_TYPE, accountType) 479 .putString(PREF_ACCOUNT_NAME, accountName) 480 .apply(); 481 482 Bundle args = new Bundle(); 483 args.putString(BookmarksLoader.ARG_ACCOUNT_TYPE, accountType); 484 args.putString(BookmarksLoader.ARG_ACCOUNT_NAME, accountName); 485 getLoaderManager().restartLoader(LOADER_BOOKMARKS, args, this); 486 } 487 488 @Override 489 public void onNothingSelected(AdapterView<?> parent) { 490 // Do nothing 491 } 492 493 private Intent createShortcutIntent(int position) { 494 Cursor cursor = (Cursor) mAdapter.getItem(position); 495 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 496 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 497 Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON); 498 Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON); 499 return BookmarkUtils.createAddToHomeIntent(getActivity(), url, title, touchIcon, favicon); 500 } 501 502 private void loadUrl(int position) { 503 mCallbacks.onUrlSelected(getUrl(position), false); 504 } 505 506 private void openInNewWindow(int position) { 507 mCallbacks.onUrlSelected(getUrl(position), true); 508 } 509 510 private void editBookmark(int position) { 511 Intent intent = new Intent(getActivity(), AddBookmarkPage.class); 512 Cursor cursor = (Cursor) mAdapter.getItem(position); 513 Bundle item = new Bundle(); 514 item.putString(BrowserContract.Bookmarks.TITLE, 515 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE)); 516 item.putString(BrowserContract.Bookmarks.URL, 517 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL)); 518 byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON); 519 if (data != null) { 520 item.putParcelable(BrowserContract.Bookmarks.FAVICON, 521 BitmapFactory.decodeByteArray(data, 0, data.length)); 522 } 523 item.putInt("id", cursor.getInt(BookmarksLoader.COLUMN_INDEX_ID)); 524 intent.putExtra("bookmark", item); 525 startActivityForResult(intent, BOOKMARKS_SAVE); 526 } 527 528 @Override 529 public void onActivityResult(int requestCode, int resultCode, Intent data) { 530 switch(requestCode) { 531 case BOOKMARKS_SAVE: 532 if (resultCode == Activity.RESULT_OK) { 533 Bundle extras; 534 if (data != null && (extras = data.getExtras()) != null) { 535 // If there are extras, then we need to save 536 // the edited bookmark. This is done in updateRow() 537 String title = extras.getString("title"); 538 String url = extras.getString("url"); 539 if (title != null && url != null) { 540 updateRow(extras); 541 } 542 } 543 } 544 break; 545 } 546 } 547 548 /** 549 * Update a row in the database with new information. 550 * @param map Bundle storing id, title and url of new information 551 */ 552 public void updateRow(Bundle map) { 553 554 // Find the record 555 int id = map.getInt("id"); 556 int position = -1; 557 Cursor cursor = mAdapter.getCursor(); 558 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { 559 if (cursor.getInt(BookmarksLoader.COLUMN_INDEX_ID) == id) { 560 position = cursor.getPosition(); 561 break; 562 } 563 } 564 if (position < 0) { 565 return; 566 } 567 568 cursor.moveToPosition(position); 569 ContentValues values = new ContentValues(); 570 String title = map.getString(BrowserContract.Bookmarks.TITLE); 571 if (!title.equals(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE))) { 572 values.put(BrowserContract.Bookmarks.TITLE, title); 573 } 574 String url = map.getString(BrowserContract.Bookmarks.URL); 575 if (!url.equals(cursor.getString(BookmarksLoader.COLUMN_INDEX_URL))) { 576 values.put(BrowserContract.Bookmarks.URL, url); 577 } 578 579 if (map.getBoolean("invalidateThumbnail") == true) { 580 values.putNull(BrowserContract.Bookmarks.THUMBNAIL); 581 } 582 583 if (values.size() > 0) { 584 getActivity().getContentResolver().update( 585 ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, id), 586 values, null, null); 587 } 588 } 589 590 private void displayRemoveBookmarkDialog(final int position) { 591 // Put up a dialog asking if the user really wants to 592 // delete the bookmark 593 Cursor cursor = (Cursor) mAdapter.getItem(position); 594 Context context = getActivity(); 595 final ContentResolver resolver = context.getContentResolver(); 596 final Uri uri = ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI, 597 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID)); 598 599 new AlertDialog.Builder(context) 600 .setTitle(R.string.delete_bookmark) 601 .setIcon(android.R.drawable.ic_dialog_alert) 602 .setMessage(context.getString(R.string.delete_bookmark_warning, 603 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE))) 604 .setPositiveButton(R.string.ok, 605 new DialogInterface.OnClickListener() { 606 public void onClick(DialogInterface dialog, int whichButton) { 607 resolver.delete(uri, null, null); 608 } 609 }) 610 .setNegativeButton(R.string.cancel, null) 611 .show(); 612 } 613 614 private String getUrl(int position) { 615 Cursor cursor = (Cursor) mAdapter.getItem(position); 616 return cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 617 } 618 619 private void copy(CharSequence text) { 620 ClipboardManager cm = (ClipboardManager) getActivity().getSystemService( 621 Context.CLIPBOARD_SERVICE); 622 cm.setPrimaryClip(ClipData.newRawUri(null, null, Uri.parse(text.toString()))); 623 } 624} 625