/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.browser;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.provider.Browser;
import android.text.IClipboard;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.webkit.WebIconDatabase.IconListener;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.Toast;

/*package*/ enum BookmarkViewMode { NONE, GRID, LIST }
/**
 *  View showing the user's bookmarks in the browser.
 */
public class BrowserBookmarksPage extends Activity implements
        View.OnCreateContextMenuListener {

    private BookmarkViewMode        mViewMode = BookmarkViewMode.NONE;
    private GridView                mGridPage;
    private ListView                mVerticalList;
    private BrowserBookmarksAdapter mBookmarksAdapter;
    private static final int        BOOKMARKS_SAVE = 1;
    private boolean                 mDisableNewWindow;
    private BookmarkItem            mContextHeader;
    private AddNewBookmark          mAddHeader;
    private boolean                 mCanceled = false;
    private boolean                 mCreateShortcut;
    private boolean                 mMostVisited;
    private View                    mEmptyView;
    private int                     mIconSize;
    // XXX: There is no public string defining this intent so if Home changes
    // the value, we have to update this string.
    private static final String     INSTALL_SHORTCUT =
            "com.android.launcher.action.INSTALL_SHORTCUT";

    private final static String LOGTAG = "browser";
    private final static String PREF_BOOKMARK_VIEW_MODE = "pref_bookmark_view_mode";
    private final static String PREF_MOST_VISITED_VIEW_MODE = "pref_most_visited_view_mode";

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        // It is possible that the view has been canceled when we get to
        // this point as back has a higher priority
        if (mCanceled) {
            return true;
        }
        AdapterView.AdapterContextMenuInfo i =
            (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
        // If we have no menu info, we can't tell which item was selected.
        if (i == null) {
            return true;
        }

        switch (item.getItemId()) {
        case R.id.new_context_menu_id:
            saveCurrentPage();
            break;
        case R.id.open_context_menu_id:
            loadUrl(i.position);
            break;
        case R.id.edit_context_menu_id:
            editBookmark(i.position);
            break;
        case R.id.shortcut_context_menu_id:
            final Intent send = createShortcutIntent(i.position);
            send.setAction(INSTALL_SHORTCUT);
            sendBroadcast(send);
            break;
        case R.id.delete_context_menu_id:
            if (mMostVisited) {
                Browser.deleteFromHistory(getContentResolver(),
                        getUrl(i.position));
                refreshList();
            } else {
                displayRemoveBookmarkDialog(i.position);
            }
            break;
        case R.id.new_window_context_menu_id:
            openInNewWindow(i.position);
            break;
        case R.id.share_link_context_menu_id:
            BrowserActivity.sharePage(BrowserBookmarksPage.this,
                    mBookmarksAdapter.getTitle(i.position), getUrl(i.position),
                    getFavicon(i.position),
                    mBookmarksAdapter.getScreenshot(i.position));
            break;
        case R.id.copy_url_context_menu_id:
            copy(getUrl(i.position));
            break;
        case R.id.homepage_context_menu_id:
            BrowserSettings.getInstance().setHomePage(this,
                    getUrl(i.position));
            Toast.makeText(this, R.string.homepage_set,
                    Toast.LENGTH_LONG).show();
            break;
        // Only for the Most visited page
        case R.id.save_to_bookmarks_menu_id:
            boolean isBookmark;
            String name;
            String url;
            if (mViewMode == BookmarkViewMode.GRID) {
                isBookmark = mBookmarksAdapter.getIsBookmark(i.position);
                name = mBookmarksAdapter.getTitle(i.position);
                url = mBookmarksAdapter.getUrl(i.position);
            } else {
                HistoryItem historyItem = ((HistoryItem) i.targetView);
                isBookmark = historyItem.isBookmark();
                name = historyItem.getName();
                url = historyItem.getUrl();
            }
            // If the site is bookmarked, the item becomes remove from
            // bookmarks.
            if (isBookmark) {
                Bookmarks.removeFromBookmarks(this, getContentResolver(), url, name);
            } else {
                Browser.saveBookmark(this, name, url);
            }
            break;
        default:
            return super.onContextItemSelected(item);
        }
        return true;
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
                ContextMenuInfo menuInfo) {
            AdapterView.AdapterContextMenuInfo i =
                    (AdapterView.AdapterContextMenuInfo) menuInfo;

            MenuInflater inflater = getMenuInflater();
            if (mMostVisited) {
                inflater.inflate(R.menu.historycontext, menu);
            } else {
                inflater.inflate(R.menu.bookmarkscontext, menu);
            }

            if (0 == i.position && !mMostVisited) {
                menu.setGroupVisible(R.id.CONTEXT_MENU, false);
                if (mAddHeader == null) {
                    mAddHeader = new AddNewBookmark(BrowserBookmarksPage.this);
                } else if (mAddHeader.getParent() != null) {
                    ((ViewGroup) mAddHeader.getParent()).
                            removeView(mAddHeader);
                }
                mAddHeader.setUrl(getIntent().getStringExtra("url"));
                menu.setHeaderView(mAddHeader);
                return;
            }
            if (mMostVisited) {
                if ((mViewMode == BookmarkViewMode.LIST
                        && ((HistoryItem) i.targetView).isBookmark())
                        || mBookmarksAdapter.getIsBookmark(i.position)) {
                    MenuItem item = menu.findItem(
                            R.id.save_to_bookmarks_menu_id);
                    item.setTitle(R.string.remove_from_bookmarks);
                }
            } else {
                // The historycontext menu has no ADD_MENU group.
                menu.setGroupVisible(R.id.ADD_MENU, false);
            }
            if (mDisableNewWindow) {
                menu.findItem(R.id.new_window_context_menu_id).setVisible(
                        false);
            }
            if (mContextHeader == null) {
                mContextHeader = new BookmarkItem(BrowserBookmarksPage.this);
            } else if (mContextHeader.getParent() != null) {
                ((ViewGroup) mContextHeader.getParent()).
                        removeView(mContextHeader);
            }
            if (mViewMode == BookmarkViewMode.GRID) {
                mBookmarksAdapter.populateBookmarkItem(mContextHeader,
                        i.position);
            } else {
                BookmarkItem b = (BookmarkItem) i.targetView;
                b.copyTo(mContextHeader);
            }
            menu.setHeaderView(mContextHeader);
        }

    /**
     *  Create a new BrowserBookmarksPage.
     */
    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        // Grab the app icon size as a resource.
        mIconSize = getResources().getDimensionPixelSize(
                android.R.dimen.app_icon_size);

        Intent intent = getIntent();
        if (Intent.ACTION_CREATE_SHORTCUT.equals(intent.getAction())) {
            mCreateShortcut = true;
        }
        mDisableNewWindow = intent.getBooleanExtra("disable_new_window",
                false);
        mMostVisited = intent.getBooleanExtra("mostVisited", false);

        if (mCreateShortcut) {
            setTitle(R.string.browser_bookmarks_page_bookmarks_text);
        }

        setContentView(R.layout.empty_history);
        mEmptyView = findViewById(R.id.empty_view);
        mEmptyView.setVisibility(View.GONE);

        SharedPreferences p = getPreferences(MODE_PRIVATE);

        // See if the user has set a preference for the view mode of their
        // bookmarks. Otherwise default to grid mode.
        BookmarkViewMode preference = BookmarkViewMode.NONE;
        if (mMostVisited) {
            // For the most visited page, only use list mode.
            preference = BookmarkViewMode.LIST;
        } else {
            preference = BookmarkViewMode.values()[p.getInt(
                    PREF_BOOKMARK_VIEW_MODE, BookmarkViewMode.GRID.ordinal())];
        }
        switchViewMode(preference);

        final boolean createShortcut = mCreateShortcut;
        final boolean mostVisited = mMostVisited;
        final String url = intent.getStringExtra("url");
        final String title = intent.getStringExtra("title");
        final Bitmap thumbnail =
                (Bitmap) intent.getParcelableExtra("thumbnail");
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... unused) {
                BrowserBookmarksAdapter adapter = new BrowserBookmarksAdapter(
                        BrowserBookmarksPage.this,
                        url,
                        title,
                        thumbnail,
                        createShortcut,
                        mostVisited);
                mHandler.obtainMessage(ADAPTER_CREATED, adapter).sendToTarget();
                return null;
            }
        }.execute();
    }

    @Override
    protected void onDestroy() {
        mHandler.removeCallbacksAndMessages(null);
        super.onDestroy();
    }

    /**
     *  Set the ContentView to be either the grid of thumbnails or the vertical
     *  list.
     */
    private void switchViewMode(BookmarkViewMode viewMode) {
        if (mViewMode == viewMode) {
            return;
        }

        mViewMode = viewMode;

        // Update the preferences to make the new view mode sticky.
        Editor ed = getPreferences(MODE_PRIVATE).edit();
        if (mMostVisited) {
            ed.putInt(PREF_MOST_VISITED_VIEW_MODE, mViewMode.ordinal());
        } else {
            ed.putInt(PREF_BOOKMARK_VIEW_MODE, mViewMode.ordinal());
        }
        ed.apply();

        if (mBookmarksAdapter != null) {
            mBookmarksAdapter.switchViewMode(viewMode);
        }
        if (mViewMode == BookmarkViewMode.GRID) {
            if (mGridPage == null) {
                mGridPage = new GridView(this);
                if (mBookmarksAdapter != null) {
                    mGridPage.setAdapter(mBookmarksAdapter);
                }
                mGridPage.setOnItemClickListener(mListener);
                mGridPage.setNumColumns(GridView.AUTO_FIT);
                mGridPage.setColumnWidth(
                        BrowserActivity.getDesiredThumbnailWidth(this));
                mGridPage.setFocusable(true);
                mGridPage.setFocusableInTouchMode(true);
                mGridPage.setSelector(android.R.drawable.gallery_thumb);
                float density = getResources().getDisplayMetrics().density;
                mGridPage.setVerticalSpacing((int) (14 * density));
                mGridPage.setHorizontalSpacing((int) (8 * density));
                mGridPage.setStretchMode(GridView.STRETCH_SPACING);
                mGridPage.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
                mGridPage.setDrawSelectorOnTop(true);
                if (mMostVisited) {
                    mGridPage.setEmptyView(mEmptyView);
                }
                if (!mCreateShortcut) {
                    mGridPage.setOnCreateContextMenuListener(this);
                }
            }
            addContentView(mGridPage, FULL_SCREEN_PARAMS);
            if (mVerticalList != null) {
                ViewGroup parent = (ViewGroup) mVerticalList.getParent();
                if (parent != null) {
                    parent.removeView(mVerticalList);
                }
            }
        } else {
            if (null == mVerticalList) {
                ListView listView = new ListView(this);
                if (mBookmarksAdapter != null) {
                    listView.setAdapter(mBookmarksAdapter);
                }
                listView.setDrawSelectorOnTop(false);
                listView.setVerticalScrollBarEnabled(true);
                listView.setOnItemClickListener(mListener);
                if (mMostVisited) {
                    listView.setEmptyView(mEmptyView);
                }
                if (!mCreateShortcut) {
                    listView.setOnCreateContextMenuListener(this);
                }
                mVerticalList = listView;
            }
            addContentView(mVerticalList, FULL_SCREEN_PARAMS);
            if (mGridPage != null) {
                ViewGroup parent = (ViewGroup) mGridPage.getParent();
                if (parent != null) {
                    parent.removeView(mGridPage);
                }
            }
        }
    }

    private static final ViewGroup.LayoutParams FULL_SCREEN_PARAMS
            = new ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT);

    private static final int SAVE_CURRENT_PAGE = 1000;
    private static final int ADAPTER_CREATED = 1001;
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SAVE_CURRENT_PAGE:
                    saveCurrentPage();
                    break;
                case ADAPTER_CREATED:
                    mBookmarksAdapter = (BrowserBookmarksAdapter) msg.obj;
                    mBookmarksAdapter.switchViewMode(mViewMode);
                    if (mGridPage != null) {
                        mGridPage.setAdapter(mBookmarksAdapter);
                    }
                    if (mVerticalList != null) {
                        mVerticalList.setAdapter(mBookmarksAdapter);
                    }
                    // Add our own listener in case there are favicons that
                    // have yet to be loaded.
                    if (mMostVisited) {
                        IconListener listener = new IconListener() {
                            public void onReceivedIcon(String url,
                                    Bitmap icon) {
                                if (mGridPage != null) {
                                    mGridPage.setAdapter(mBookmarksAdapter);
                                }
                                if (mVerticalList != null) {
                                    mVerticalList.setAdapter(mBookmarksAdapter);
                                }
                            }
                        };
                        CombinedBookmarkHistoryActivity.getIconListenerSet()
                                .addListener(listener);
                    }
                    break;
            }
        }
    };

    private AdapterView.OnItemClickListener mListener = new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView parent, View v, int position, long id) {
            // It is possible that the view has been canceled when we get to
            // this point as back has a higher priority
            if (mCanceled) {
                android.util.Log.e(LOGTAG, "item clicked when dismissing");
                return;
            }
            if (!mCreateShortcut) {
                if (0 == position && !mMostVisited) {
                    // XXX: Work-around for a framework issue.
                    mHandler.sendEmptyMessage(SAVE_CURRENT_PAGE);
                } else {
                    loadUrl(position);
                }
            } else {
                final Intent intent = createShortcutIntent(position);
                setResultToParent(RESULT_OK, intent);
                finish();
            }
        }
    };

    private Intent createShortcutIntent(int position) {
        String url = getUrl(position);
        String title = getBookmarkTitle(position);
        Bitmap touchIcon = getTouchIcon(position);

        final Intent i = new Intent();
        final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW,
                Uri.parse(url));
        long urlHash = url.hashCode();
        long uniqueId = (urlHash << 32) | shortcutIntent.hashCode();
        shortcutIntent.putExtra(Browser.EXTRA_APPLICATION_ID,
                Long.toString(uniqueId));
        i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
        i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
        // Use the apple-touch-icon if available
        if (touchIcon != null) {
            // Make a copy so we can modify the pixels.  We can't use
            // createScaledBitmap or copy since they will preserve the config
            // and lose the ability to add alpha.
            Bitmap bm = Bitmap.createBitmap(mIconSize, mIconSize,
                    Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bm);
            Rect src = new Rect(0, 0, touchIcon.getWidth(),
                                touchIcon.getHeight());
            Rect dest = new Rect(0, 0, bm.getWidth(), bm.getHeight());

            // Paint used for scaling the bitmap and drawing the rounded rect.
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            paint.setFilterBitmap(true);
            canvas.drawBitmap(touchIcon, src, dest, paint);

            // Construct a path from a round rect. This will allow drawing with
            // an inverse fill so we can punch a hole using the round rect.
            Path path = new Path();
            path.setFillType(Path.FillType.INVERSE_WINDING);
            RectF rect = new RectF(0, 0, bm.getWidth(), bm.getHeight());
            rect.inset(1, 1);
            path.addRoundRect(rect, 8f, 8f, Path.Direction.CW);

            // Reuse the paint and clear the outside of the rectangle.
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            canvas.drawPath(path, paint);

            i.putExtra(Intent.EXTRA_SHORTCUT_ICON, bm);
        } else {
            Bitmap favicon = getFavicon(position);
            if (favicon == null) {
                i.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
                        Intent.ShortcutIconResource.fromContext(
                                BrowserBookmarksPage.this,
                                R.drawable.ic_launcher_shortcut_browser_bookmark));
            } else {
                Bitmap icon = BitmapFactory.decodeResource(getResources(),
                        R.drawable.ic_launcher_shortcut_browser_bookmark_icon);

                // Make a copy of the regular icon so we can modify the pixels.
                Bitmap copy = icon.copy(Bitmap.Config.ARGB_8888, true);
                Canvas canvas = new Canvas(copy);

                // Make a Paint for the white background rectangle and for
                // filtering the favicon.
                Paint p = new Paint(Paint.ANTI_ALIAS_FLAG
                        | Paint.FILTER_BITMAP_FLAG);
                p.setStyle(Paint.Style.FILL_AND_STROKE);
                p.setColor(Color.WHITE);

                final float density =
                        getResources().getDisplayMetrics().density;
                // Create a rectangle that is slightly wider than the favicon
                final float iconSize = 16 * density; // 16x16 favicon
                final float padding = 2 * density; // white padding around icon
                final float rectSize = iconSize + 2 * padding;

                final Rect iconBounds =
                        new Rect(0, 0, icon.getWidth(), icon.getHeight());
                final float x = iconBounds.exactCenterX() - (rectSize / 2);
                // Note: Subtract 2 dip from the y position since the box is
                // slightly higher than center. Use padding since it is already
                // 2 * density.
                final float y = iconBounds.exactCenterY() - (rectSize / 2)
                        - padding;
                RectF r = new RectF(x, y, x + rectSize, y + rectSize);

                // Draw a white rounded rectangle behind the favicon
                canvas.drawRoundRect(r, 2, 2, p);

                // Draw the favicon in the same rectangle as the rounded
                // rectangle but inset by the padding
                // (results in a 16x16 favicon).
                r.inset(padding, padding);
                canvas.drawBitmap(favicon, null, r, p);
                i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy);
            }
        }
        // Do not allow duplicate items
        i.putExtra("duplicate", false);
        return i;
    }

    private void saveCurrentPage() {
        Intent i = new Intent(BrowserBookmarksPage.this,
                AddBookmarkPage.class);
        i.putExtras(getIntent());
        startActivityForResult(i, BOOKMARKS_SAVE);
    }

    private void loadUrl(int position) {
        Intent intent = (new Intent()).setAction(getUrl(position));
        setResultToParent(RESULT_OK, intent);
        finish();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        boolean result = super.onCreateOptionsMenu(menu);
        if (!mCreateShortcut && !mMostVisited) {
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.bookmarks, menu);
            return true;
        }
        return result;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        boolean result = super.onPrepareOptionsMenu(menu);
        if (mCreateShortcut || mMostVisited || mBookmarksAdapter == null
                || mBookmarksAdapter.getCount() == 0) {
            // No need to show the menu if there are no items.
            return result;
        }
        MenuItem switchItem = menu.findItem(R.id.switch_mode_menu_id);
        int titleResId;
        int iconResId;
        if (mViewMode == BookmarkViewMode.GRID) {
            titleResId = R.string.switch_to_list;
            iconResId = R.drawable.ic_menu_list;
        } else {
            titleResId = R.string.switch_to_thumbnails;
            iconResId = R.drawable.ic_menu_thumbnail;
        }
        switchItem.setTitle(titleResId);
        switchItem.setIcon(iconResId);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.new_context_menu_id:
            saveCurrentPage();
            break;

        case R.id.switch_mode_menu_id:
            if (mViewMode == BookmarkViewMode.GRID) {
                switchViewMode(BookmarkViewMode.LIST);
            } else {
                switchViewMode(BookmarkViewMode.GRID);
            }
            break;

        default:
            return super.onOptionsItemSelected(item);
        }
        return true;
    }

    private void openInNewWindow(int position) {
        Bundle b = new Bundle();
        b.putBoolean("new_window", true);
        setResultToParent(RESULT_OK,
                (new Intent()).setAction(getUrl(position)).putExtras(b));

        finish();
    }


    private void editBookmark(int position) {
        Intent intent = new Intent(BrowserBookmarksPage.this,
            AddBookmarkPage.class);
        intent.putExtra("bookmark", getRow(position));
        startActivityForResult(intent, BOOKMARKS_SAVE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
                                    Intent data) {
        switch(requestCode) {
            case BOOKMARKS_SAVE:
                if (resultCode == RESULT_OK) {
                    Bundle extras;
                    if (data != null && (extras = data.getExtras()) != null) {
                        // If there are extras, then we need to save
                        // the edited bookmark. This is done in updateRow()
                        String title = extras.getString("title");
                        String url = extras.getString("url");
                        if (title != null && url != null) {
                            mBookmarksAdapter.updateRow(extras);
                        }
                    } else {
                        // extras == null then a new bookmark was added to
                        // the database.
                        refreshList();
                    }
                }
                break;
            default:
                break;
        }
    }

    private void displayRemoveBookmarkDialog(int position) {
        // Put up a dialog asking if the user really wants to
        // delete the bookmark
        final int deletePos = position;
        new AlertDialog.Builder(this)
                .setTitle(R.string.delete_bookmark)
                .setIcon(android.R.drawable.ic_dialog_alert)
                .setMessage(getText(R.string.delete_bookmark_warning).toString().replace(
                        "%s", getBookmarkTitle(deletePos)))
                .setPositiveButton(R.string.ok,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int whichButton) {
                                deleteBookmark(deletePos);
                            }
                        })
                .setNegativeButton(R.string.cancel, null)
                .show();
    }

    /**
     *  Refresh the shown list after the database has changed.
     */
    private void refreshList() {
        if (mBookmarksAdapter == null) return;
        mBookmarksAdapter.refreshList();
    }

    /**
     *  Return a hashmap representing the currently highlighted row.
     */
    public Bundle getRow(int position) {
        return mBookmarksAdapter == null ? null
                : mBookmarksAdapter.getRow(position);
    }

    /**
     *  Return the url of the currently highlighted row.
     */
    public String getUrl(int position) {
        return mBookmarksAdapter == null ? null
                : mBookmarksAdapter.getUrl(position);
    }

    /**
     * Return the favicon of the currently highlighted row.
     */
    public Bitmap getFavicon(int position) {
        return mBookmarksAdapter == null ? null
                : mBookmarksAdapter.getFavicon(position);
    }

    private Bitmap getTouchIcon(int position) {
        return mBookmarksAdapter == null ? null
                : mBookmarksAdapter.getTouchIcon(position);
    }

    private void copy(CharSequence text) {
        try {
            IClipboard clip = IClipboard.Stub.asInterface(ServiceManager.getService("clipboard"));
            if (clip != null) {
                clip.setClipboardText(text);
            }
        } catch (android.os.RemoteException e) {
            Log.e(LOGTAG, "Copy failed", e);
        }
    }

    public String getBookmarkTitle(int position) {
        return mBookmarksAdapter == null ? null
                : mBookmarksAdapter.getTitle(position);
    }

    /**
     *  Delete the currently highlighted row.
     */
    public void deleteBookmark(int position) {
        if (mBookmarksAdapter == null) return;
        mBookmarksAdapter.deleteRow(position);
    }

    @Override
    public void onBackPressed() {
        setResultToParent(RESULT_CANCELED, null);
        mCanceled = true;
        super.onBackPressed();
    }

    // This Activity is generally a sub-Activity of
    // CombinedBookmarkHistoryActivity. In that situation, we need to pass our
    // result code up to our parent. However, if someone calls this Activity
    // directly, then this has no parent, and it needs to set it on itself.
    private void setResultToParent(int resultCode, Intent data) {
        Activity parent = getParent();
        if (parent == null) {
            setResult(resultCode, data);
        } else {
            ((CombinedBookmarkHistoryActivity) parent).setResultFromChild(
                    resultCode, data);
        }
    }
}