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