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