OSDN Git Service

Deprecate fill_parent and introduce match_parent.
[android-x86/packages-apps-Browser.git] / src / com / android / browser / BrowserBookmarksPage.java
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
17 package com.android.browser;
18
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.content.DialogInterface;
22 import android.content.Intent;
23 import android.content.SharedPreferences;
24 import android.content.SharedPreferences.Editor;
25 import android.graphics.Bitmap;
26 import android.graphics.BitmapFactory;
27 import android.graphics.Canvas;
28 import android.graphics.Color;
29 import android.graphics.Paint;
30 import android.graphics.Path;
31 import android.graphics.PorterDuff;
32 import android.graphics.PorterDuffXfermode;
33 import android.graphics.RectF;
34 import android.net.Uri;
35 import android.os.Bundle;
36 import android.os.Handler;
37 import android.os.Message;
38 import android.os.ServiceManager;
39 import android.provider.Browser;
40 import android.text.IClipboard;
41 import android.util.Log;
42 import android.view.ContextMenu;
43 import android.view.Menu;
44 import android.view.MenuInflater;
45 import android.view.MenuItem;
46 import android.view.View;
47 import android.view.ViewGroup;
48 import android.view.ContextMenu.ContextMenuInfo;
49 import android.widget.AdapterView;
50 import android.widget.GridView;
51 import android.widget.ListView;
52 import android.widget.Toast;
53
54 /*package*/ enum BookmarkViewMode { NONE, GRID, LIST }
55 /**
56  *  View showing the user's bookmarks in the browser.
57  */
58 public class BrowserBookmarksPage extends Activity implements 
59         View.OnCreateContextMenuListener {
60
61     private BookmarkViewMode        mViewMode = BookmarkViewMode.NONE;
62     private GridView                mGridPage;
63     private ListView                mVerticalList;
64     private BrowserBookmarksAdapter mBookmarksAdapter;
65     private static final int        BOOKMARKS_SAVE = 1;
66     private boolean                 mDisableNewWindow;
67     private BookmarkItem            mContextHeader;
68     private AddNewBookmark          mAddHeader;
69     private boolean                 mCanceled = false;
70     private boolean                 mCreateShortcut;
71     private boolean                 mMostVisited;
72     private View                    mEmptyView;
73     // XXX: There is no public string defining this intent so if Home changes
74     // the value, we have to update this string.
75     private static final String     INSTALL_SHORTCUT =
76             "com.android.launcher.action.INSTALL_SHORTCUT";
77     
78     private final static String LOGTAG = "browser";
79     private final static String PREF_BOOKMARK_VIEW_MODE = "pref_bookmark_view_mode";
80     private final static String PREF_MOST_VISITED_VIEW_MODE = "pref_most_visited_view_mode";
81
82     @Override
83     public boolean onContextItemSelected(MenuItem item) {
84         // It is possible that the view has been canceled when we get to
85         // this point as back has a higher priority 
86         if (mCanceled) {
87             return true;
88         }
89         AdapterView.AdapterContextMenuInfo i = 
90             (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
91         // If we have no menu info, we can't tell which item was selected.
92         if (i == null) {
93             return true;
94         }
95         
96         switch (item.getItemId()) {
97         case R.id.new_context_menu_id:
98             saveCurrentPage();
99             break;
100         case R.id.open_context_menu_id:
101             loadUrl(i.position);
102             break;
103         case R.id.edit_context_menu_id:
104             editBookmark(i.position);
105             break;
106         case R.id.shortcut_context_menu_id:
107             final Intent send = createShortcutIntent(i.position);
108             send.setAction(INSTALL_SHORTCUT);
109             sendBroadcast(send);
110             break;
111         case R.id.delete_context_menu_id:
112             if (mMostVisited) {
113                 Browser.deleteFromHistory(getContentResolver(),
114                         getUrl(i.position));
115                 refreshList();
116             } else {
117                 displayRemoveBookmarkDialog(i.position);
118             }
119             break;
120         case R.id.new_window_context_menu_id:
121             openInNewWindow(i.position);
122             break;
123         case R.id.share_link_context_menu_id:
124             Browser.sendString(BrowserBookmarksPage.this, getUrl(i.position),
125                     getText(R.string.choosertitle_sharevia).toString());
126             break;
127         case R.id.copy_url_context_menu_id:
128             copy(getUrl(i.position));
129             break;
130         case R.id.homepage_context_menu_id:
131             BrowserSettings.getInstance().setHomePage(this,
132                     getUrl(i.position));
133             Toast.makeText(this, R.string.homepage_set,
134                     Toast.LENGTH_LONG).show();
135             break;
136         // Only for the Most visited page
137         case R.id.save_to_bookmarks_menu_id:
138             boolean isBookmark;
139             String name;
140             String url;
141             if (mViewMode == BookmarkViewMode.GRID) {
142                 isBookmark = mBookmarksAdapter.getIsBookmark(i.position);
143                 name = mBookmarksAdapter.getTitle(i.position);
144                 url = mBookmarksAdapter.getUrl(i.position);
145             } else {
146                 HistoryItem historyItem = ((HistoryItem) i.targetView);
147                 isBookmark = historyItem.isBookmark();
148                 name = historyItem.getName();
149                 url = historyItem.getUrl();
150             }
151             // If the site is bookmarked, the item becomes remove from
152             // bookmarks.
153             if (isBookmark) {
154                 Bookmarks.removeFromBookmarks(this, getContentResolver(), url, name);
155             } else {
156                 Browser.saveBookmark(this, name, url);
157             }
158             break;
159         default:
160             return super.onContextItemSelected(item);
161         }
162         return true;
163     }
164
165     @Override
166     public void onCreateContextMenu(ContextMenu menu, View v,
167                 ContextMenuInfo menuInfo) {
168             AdapterView.AdapterContextMenuInfo i = 
169                     (AdapterView.AdapterContextMenuInfo) menuInfo;
170
171             MenuInflater inflater = getMenuInflater();
172             if (mMostVisited) {
173                 inflater.inflate(R.menu.historycontext, menu);
174             } else {
175                 inflater.inflate(R.menu.bookmarkscontext, menu);
176             }
177
178             if (0 == i.position && !mMostVisited) {
179                 menu.setGroupVisible(R.id.CONTEXT_MENU, false);
180                 if (mAddHeader == null) {
181                     mAddHeader = new AddNewBookmark(BrowserBookmarksPage.this);
182                 } else if (mAddHeader.getParent() != null) {
183                     ((ViewGroup) mAddHeader.getParent()).
184                             removeView(mAddHeader);
185                 }
186                 mAddHeader.setUrl(getIntent().getStringExtra("url"));
187                 menu.setHeaderView(mAddHeader);
188                 return;
189             }
190             if (mMostVisited) {
191                 if ((mViewMode == BookmarkViewMode.LIST
192                         && ((HistoryItem) i.targetView).isBookmark())
193                         || mBookmarksAdapter.getIsBookmark(i.position)) {
194                     MenuItem item = menu.findItem(
195                             R.id.save_to_bookmarks_menu_id);
196                     item.setTitle(R.string.remove_from_bookmarks);
197                 }
198             } else {
199                 // The historycontext menu has no ADD_MENU group.
200                 menu.setGroupVisible(R.id.ADD_MENU, false);
201             }
202             if (mDisableNewWindow) {
203                 menu.findItem(R.id.new_window_context_menu_id).setVisible(
204                         false);
205             }
206             if (mContextHeader == null) {
207                 mContextHeader = new BookmarkItem(BrowserBookmarksPage.this);
208             } else if (mContextHeader.getParent() != null) {
209                 ((ViewGroup) mContextHeader.getParent()).
210                         removeView(mContextHeader);
211             }
212             if (mViewMode == BookmarkViewMode.GRID) {
213                 mBookmarksAdapter.populateBookmarkItem(mContextHeader,
214                         i.position);
215             } else {
216                 BookmarkItem b = (BookmarkItem) i.targetView;
217                 b.copyTo(mContextHeader);
218             }
219             menu.setHeaderView(mContextHeader);
220         }
221
222     /**
223      *  Create a new BrowserBookmarksPage.
224      */  
225     @Override
226     protected void onCreate(Bundle icicle) {
227         super.onCreate(icicle);
228
229         if (Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())) {
230             mCreateShortcut = true;
231         }
232         mDisableNewWindow = getIntent().getBooleanExtra("disable_new_window",
233                 false);
234         mMostVisited = getIntent().getBooleanExtra("mostVisited", false);
235
236         if (mCreateShortcut) {
237             setTitle(R.string.browser_bookmarks_page_bookmarks_text);
238         }
239         mHandler.obtainMessage(CREATE_ADAPTER).sendToTarget();
240
241         setContentView(R.layout.empty_history);
242         mEmptyView = findViewById(R.id.empty_view);
243         mEmptyView.setVisibility(View.GONE);
244
245         SharedPreferences p = getPreferences(MODE_PRIVATE);
246
247         // See if the user has set a preference for the view mode of their
248         // bookmarks. Otherwise default to grid mode.
249         BookmarkViewMode preference = BookmarkViewMode.NONE;
250         if (mMostVisited) {
251             // For the most visited page, only use list mode.
252             preference = BookmarkViewMode.LIST;
253         } else {
254             preference = BookmarkViewMode.values()[p.getInt(
255                     PREF_BOOKMARK_VIEW_MODE, BookmarkViewMode.GRID.ordinal())];
256         }
257         switchViewMode(preference);
258     }
259
260     /**
261      *  Set the ContentView to be either the grid of thumbnails or the vertical
262      *  list.
263      */
264     private void switchViewMode(BookmarkViewMode viewMode) {
265         if (mViewMode == viewMode) {
266             return;
267         }
268
269         mViewMode = viewMode;
270
271         // Update the preferences to make the new view mode sticky.
272         Editor ed = getPreferences(MODE_PRIVATE).edit();
273         if (mMostVisited) {
274             ed.putInt(PREF_MOST_VISITED_VIEW_MODE, mViewMode.ordinal());
275         } else {
276             ed.putInt(PREF_BOOKMARK_VIEW_MODE, mViewMode.ordinal());
277         }
278         ed.commit();
279
280         if (mBookmarksAdapter != null) {
281             mBookmarksAdapter.switchViewMode(viewMode);
282         }
283         if (mViewMode == BookmarkViewMode.GRID) {
284             if (mGridPage == null) {
285                 mGridPage = new GridView(this);
286                 if (mBookmarksAdapter != null) {
287                     mGridPage.setAdapter(mBookmarksAdapter);
288                 }
289                 mGridPage.setOnItemClickListener(mListener);
290                 mGridPage.setNumColumns(GridView.AUTO_FIT);
291                 mGridPage.setColumnWidth(
292                         BrowserActivity.getDesiredThumbnailWidth(this));
293                 mGridPage.setFocusable(true);
294                 mGridPage.setFocusableInTouchMode(true);
295                 mGridPage.setSelector(android.R.drawable.gallery_thumb);
296                 float density = getResources().getDisplayMetrics().density;
297                 mGridPage.setVerticalSpacing((int) (14 * density));
298                 mGridPage.setHorizontalSpacing((int) (8 * density));
299                 mGridPage.setStretchMode(GridView.STRETCH_SPACING);
300                 mGridPage.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
301                 mGridPage.setDrawSelectorOnTop(true);
302                 if (mMostVisited) {
303                     mGridPage.setEmptyView(mEmptyView);
304                 }
305                 if (!mCreateShortcut) {
306                     mGridPage.setOnCreateContextMenuListener(this);
307                 }
308             }
309             addContentView(mGridPage, FULL_SCREEN_PARAMS);
310             if (mVerticalList != null) {
311                 ViewGroup parent = (ViewGroup) mVerticalList.getParent();
312                 if (parent != null) {
313                     parent.removeView(mVerticalList);
314                 }
315             }
316         } else {
317             if (null == mVerticalList) {
318                 ListView listView = new ListView(this);
319                 if (mBookmarksAdapter != null) {
320                     listView.setAdapter(mBookmarksAdapter);
321                 }
322                 listView.setDrawSelectorOnTop(false);
323                 listView.setVerticalScrollBarEnabled(true);
324                 listView.setOnItemClickListener(mListener);
325                 if (mMostVisited) {
326                     listView.setEmptyView(mEmptyView);
327                 }
328                 if (!mCreateShortcut) {
329                     listView.setOnCreateContextMenuListener(this);
330                 }
331                 mVerticalList = listView;
332             }
333             addContentView(mVerticalList, FULL_SCREEN_PARAMS);
334             if (mGridPage != null) {
335                 ViewGroup parent = (ViewGroup) mGridPage.getParent();
336                 if (parent != null) {
337                     parent.removeView(mGridPage);
338                 }
339             }
340         }
341     }
342
343     private static final ViewGroup.LayoutParams FULL_SCREEN_PARAMS
344             = new ViewGroup.LayoutParams(
345             ViewGroup.LayoutParams.MATCH_PARENT,
346             ViewGroup.LayoutParams.MATCH_PARENT);
347
348     private static final int SAVE_CURRENT_PAGE = 1000;
349     private static final int CREATE_ADAPTER = 1001;
350     private final Handler mHandler = new Handler() {
351         @Override
352         public void handleMessage(Message msg) {
353             switch (msg.what) {
354                 case SAVE_CURRENT_PAGE:
355                     saveCurrentPage();
356                     break;
357                 case CREATE_ADAPTER:
358                     Intent intent = getIntent();
359                     mBookmarksAdapter = new BrowserBookmarksAdapter(
360                             BrowserBookmarksPage.this,
361                             intent.getStringExtra("url"),
362                             intent.getStringExtra("title"),
363                             (Bitmap) intent.getParcelableExtra("thumbnail"),
364                             mCreateShortcut,
365                             mMostVisited);
366                     mBookmarksAdapter.switchViewMode(mViewMode);
367                     if (mGridPage != null) {
368                         mGridPage.setAdapter(mBookmarksAdapter);
369                     }
370                     if (mVerticalList != null) {
371                         mVerticalList.setAdapter(mBookmarksAdapter);
372                     }
373                     break;
374             }
375         }
376     };
377
378     private AdapterView.OnItemClickListener mListener = new AdapterView.OnItemClickListener() {
379         public void onItemClick(AdapterView parent, View v, int position, long id) {
380             // It is possible that the view has been canceled when we get to
381             // this point as back has a higher priority 
382             if (mCanceled) {
383                 android.util.Log.e(LOGTAG, "item clicked when dismissing");
384                 return;
385             }
386             if (!mCreateShortcut) {
387                 if (0 == position && !mMostVisited) {
388                     // XXX: Work-around for a framework issue.
389                     mHandler.sendEmptyMessage(SAVE_CURRENT_PAGE);
390                 } else {
391                     loadUrl(position);
392                 }
393             } else {
394                 final Intent intent = createShortcutIntent(position);
395                 setResultToParent(RESULT_OK, intent);
396                 finish();
397             }
398         }
399     };
400
401     private Intent createShortcutIntent(int position) {
402         String url = getUrl(position);
403         String title = getBookmarkTitle(position);
404         Bitmap touchIcon = getTouchIcon(position);
405
406         final Intent i = new Intent();
407         final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW,
408                 Uri.parse(url));
409         long urlHash = url.hashCode();
410         long uniqueId = (urlHash << 32) | shortcutIntent.hashCode();
411         shortcutIntent.putExtra(Browser.EXTRA_APPLICATION_ID,
412                 Long.toString(uniqueId));
413         i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
414         i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
415         // Use the apple-touch-icon if available
416         if (touchIcon != null) {
417             // Make a copy so we can modify the pixels.
418             Bitmap copy = touchIcon.copy(Bitmap.Config.ARGB_8888, true);
419             Canvas canvas = new Canvas(copy);
420
421             // Construct a path from a round rect. This will allow drawing with
422             // an inverse fill so we can punch a hole using the round rect.
423             Path path = new Path();
424             path.setFillType(Path.FillType.INVERSE_WINDING);
425             RectF rect = new RectF(0, 0, touchIcon.getWidth(),
426                     touchIcon.getHeight());
427             rect.inset(1, 1);
428             path.addRoundRect(rect, 8f, 8f, Path.Direction.CW);
429
430             // Construct a paint that clears the outside of the rectangle and
431             // draw.
432             Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
433             paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
434             canvas.drawPath(path, paint);
435
436             i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy);
437         } else {
438             Bitmap favicon = getFavicon(position);
439             if (favicon == null) {
440                 i.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
441                         Intent.ShortcutIconResource.fromContext(
442                                 BrowserBookmarksPage.this,
443                                 R.drawable.ic_launcher_shortcut_browser_bookmark));
444             } else {
445                 Bitmap icon = BitmapFactory.decodeResource(getResources(),
446                         R.drawable.ic_launcher_shortcut_browser_bookmark);
447
448                 // Make a copy of the regular icon so we can modify the pixels.
449                 Bitmap copy = icon.copy(Bitmap.Config.ARGB_8888, true);
450                 Canvas canvas = new Canvas(copy);
451
452                 // Make a Paint for the white background rectangle and for
453                 // filtering the favicon.
454                 Paint p = new Paint(Paint.ANTI_ALIAS_FLAG
455                         | Paint.FILTER_BITMAP_FLAG);
456                 p.setStyle(Paint.Style.FILL_AND_STROKE);
457                 p.setColor(Color.WHITE);
458
459                 float density = getResources().getDisplayMetrics().density;
460                 // Create a rectangle that is slightly wider than the favicon
461                 final float iconSize = 16 * density; // 16x16 favicon
462                 final float padding = 2; // white padding around icon
463                 final float rectSize = iconSize + 2 * padding;
464                 final float y = icon.getHeight() - rectSize;
465                 RectF r = new RectF(0, y, rectSize, y + rectSize);
466
467                 // Draw a white rounded rectangle behind the favicon
468                 canvas.drawRoundRect(r, 2, 2, p);
469
470                 // Draw the favicon in the same rectangle as the rounded
471                 // rectangle but inset by the padding
472                 // (results in a 16x16 favicon).
473                 r.inset(padding, padding);
474                 canvas.drawBitmap(favicon, null, r, p);
475                 i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy);
476             }
477         }
478         // Do not allow duplicate items
479         i.putExtra("duplicate", false);
480         return i;
481     }
482
483     private void saveCurrentPage() {
484         Intent i = new Intent(BrowserBookmarksPage.this,
485                 AddBookmarkPage.class);
486         i.putExtras(getIntent());
487         startActivityForResult(i, BOOKMARKS_SAVE);
488     }
489
490     private void loadUrl(int position) {
491         Intent intent = (new Intent()).setAction(getUrl(position));
492         setResultToParent(RESULT_OK, intent);
493         finish();
494     }
495
496     @Override
497     public boolean onCreateOptionsMenu(Menu menu) {
498         boolean result = super.onCreateOptionsMenu(menu);
499         if (!mCreateShortcut && !mMostVisited) {
500             MenuInflater inflater = getMenuInflater();
501             inflater.inflate(R.menu.bookmarks, menu);
502             return true;
503         }
504         return result;
505     }
506
507     @Override
508     public boolean onPrepareOptionsMenu(Menu menu) {
509         boolean result = super.onPrepareOptionsMenu(menu);
510         if (mCreateShortcut || mMostVisited || mBookmarksAdapter == null
511                 || mBookmarksAdapter.getCount() == 0) {
512             // No need to show the menu if there are no items.
513             return result;
514         }
515         MenuItem switchItem = menu.findItem(R.id.switch_mode_menu_id);
516         int titleResId;
517         int iconResId;
518         if (mViewMode == BookmarkViewMode.GRID) {
519             titleResId = R.string.switch_to_list;
520             iconResId = R.drawable.ic_menu_list;
521         } else {
522             titleResId = R.string.switch_to_thumbnails;
523             iconResId = R.drawable.ic_menu_thumbnail;
524         }
525         switchItem.setTitle(titleResId);
526         switchItem.setIcon(iconResId);
527         return true;
528     }
529
530     @Override
531     public boolean onOptionsItemSelected(MenuItem item) {
532         switch (item.getItemId()) {
533         case R.id.new_context_menu_id:
534             saveCurrentPage();
535             break;
536
537         case R.id.switch_mode_menu_id:
538             if (mViewMode == BookmarkViewMode.GRID) {
539                 switchViewMode(BookmarkViewMode.LIST);
540             } else {
541                 switchViewMode(BookmarkViewMode.GRID);
542             }
543             break;
544
545         default:
546             return super.onOptionsItemSelected(item);
547         }
548         return true;
549     }
550
551     private void openInNewWindow(int position) {
552         Bundle b = new Bundle();
553         b.putBoolean("new_window", true);
554         setResultToParent(RESULT_OK,
555                 (new Intent()).setAction(getUrl(position)).putExtras(b));
556
557         finish();
558     }
559     
560
561     private void editBookmark(int position) {
562         Intent intent = new Intent(BrowserBookmarksPage.this, 
563             AddBookmarkPage.class);
564         intent.putExtra("bookmark", getRow(position));
565         startActivityForResult(intent, BOOKMARKS_SAVE);
566     }
567
568     @Override
569     protected void onActivityResult(int requestCode, int resultCode,
570                                     Intent data) {
571         switch(requestCode) {
572             case BOOKMARKS_SAVE:
573                 if (resultCode == RESULT_OK) {
574                     Bundle extras;
575                     if (data != null && (extras = data.getExtras()) != null) {
576                         // If there are extras, then we need to save
577                         // the edited bookmark. This is done in updateRow()
578                         String title = extras.getString("title");
579                         String url = extras.getString("url");
580                         if (title != null && url != null) {
581                             mBookmarksAdapter.updateRow(extras);
582                         }
583                     } else {
584                         // extras == null then a new bookmark was added to
585                         // the database.
586                         refreshList();
587                     }
588                 }
589                 break;
590             default:
591                 break;
592         }
593     }
594     
595     private void displayRemoveBookmarkDialog(int position) {
596         // Put up a dialog asking if the user really wants to
597         // delete the bookmark
598         final int deletePos = position;
599         new AlertDialog.Builder(this)
600                 .setTitle(R.string.delete_bookmark)
601                 .setIcon(android.R.drawable.ic_dialog_alert)
602                 .setMessage(getText(R.string.delete_bookmark_warning).toString().replace(
603                         "%s", getBookmarkTitle(deletePos)))
604                 .setPositiveButton(R.string.ok, 
605                         new DialogInterface.OnClickListener() {
606                             public void onClick(DialogInterface dialog, int whichButton) {
607                                 deleteBookmark(deletePos);
608                             }
609                         })
610                 .setNegativeButton(R.string.cancel, null)
611                 .show();
612     }
613
614     /**
615      *  Refresh the shown list after the database has changed.
616      */
617     private void refreshList() {
618         mBookmarksAdapter.refreshList();
619     }
620     
621     /**
622      *  Return a hashmap representing the currently highlighted row.
623      */
624     public Bundle getRow(int position) {
625         return mBookmarksAdapter == null ? null
626                 : mBookmarksAdapter.getRow(position);
627     }
628
629     /**
630      *  Return the url of the currently highlighted row.
631      */
632     public String getUrl(int position) {
633         return mBookmarksAdapter == null ? null
634                 : mBookmarksAdapter.getUrl(position);
635     }
636
637     /**
638      * Return the favicon of the currently highlighted row.
639      */
640     public Bitmap getFavicon(int position) {
641         return mBookmarksAdapter == null ? null
642                 : mBookmarksAdapter.getFavicon(position);
643     }
644
645     private Bitmap getTouchIcon(int position) {
646         return mBookmarksAdapter == null ? null
647                 : mBookmarksAdapter.getTouchIcon(position);
648     }
649
650     private void copy(CharSequence text) {
651         try {
652             IClipboard clip = IClipboard.Stub.asInterface(ServiceManager.getService("clipboard"));
653             if (clip != null) {
654                 clip.setClipboardText(text);
655             }
656         } catch (android.os.RemoteException e) {
657             Log.e(LOGTAG, "Copy failed", e);
658         }
659     }
660     
661     public String getBookmarkTitle(int position) {
662         return mBookmarksAdapter == null ? null
663                 : mBookmarksAdapter.getTitle(position);
664     }
665
666     /**
667      *  Delete the currently highlighted row.
668      */
669     public void deleteBookmark(int position) {
670         if (mBookmarksAdapter == null) return;
671         mBookmarksAdapter.deleteRow(position);
672     }
673
674     @Override
675     public void onBackPressed() {
676         setResultToParent(RESULT_CANCELED, null);
677         mCanceled = true;
678         super.onBackPressed();
679     }
680
681     // This Activity is generally a sub-Activity of CombinedHistoryActivity. In
682     // that situation, we need to pass our result code up to our parent.
683     // However, if someone calls this Activity directly, then this has no
684     // parent, and it needs to set it on itself.
685     private void setResultToParent(int resultCode, Intent data) {
686         Activity a = getParent() == null ? this : getParent();
687         a.setResult(resultCode, data);
688     }
689 }