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