1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package org.chromium.chrome.browser;
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.annotation.SuppressLint;
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.app.SearchManager;
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.ContentProvider;
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.ContentUris;
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.ContentValues;
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.Context;
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.SharedPreferences;
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.UriMatcher;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.database.Cursor;
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.database.MatrixCursor;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.net.Uri;
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.Binder;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Build;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Bundle;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Parcel;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Parcelable;
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.os.UserHandle;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.preference.PreferenceManager;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.provider.BaseColumns;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.provider.Browser;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.provider.Browser.BookmarkColumns;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.provider.Browser.SearchColumns;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.text.TextUtils;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Log;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.base.CalledByNative;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.base.CalledByNativeUnchecked;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.base.ThreadUtils;
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport org.chromium.base.VisibleForTesting;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.chrome.browser.database.SQLiteCursor;
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import org.chromium.sync.notifier.SyncStatusHelper;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.ArrayList;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.Arrays;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.HashMap;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.List;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.Vector;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.concurrent.atomic.AtomicBoolean;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * This class provides access to user data stored in Chrome, such as bookmarks, most visited pages,
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * etc. It is used to support android.provider.Browser.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public class ChromeBrowserProvider extends ContentProvider {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String TAG = "ChromeBrowserProvider";
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The permission required for using the bookmark folders API. Android build system does
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // not generate Manifest.java for java libraries, hence use the permission name string. When
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // making changes to this permission, also update the permission in AndroidManifest.xml.
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private static final String PERMISSION_READ_WRITE_BOOKMARKS = "READ_WRITE_BOOKMARK_FOLDERS";
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Defines the API methods that the Client can call by name.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String CLIENT_API_BOOKMARK_NODE_EXISTS = "BOOKMARK_NODE_EXISTS";
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String CLIENT_API_CREATE_BOOKMARKS_FOLDER_ONCE = "CREATE_BOOKMARKS_FOLDER_ONCE";
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    static final String CLIENT_API_GET_EDITABLE_BOOKMARK_FOLDER_HIERARCHY =
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            "GET_EDITABLE_BOOKMARK_FOLDER_HIERARCHY";
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String CLIENT_API_GET_BOOKMARK_NODE = "GET_BOOKMARK_NODE";
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String CLIENT_API_GET_DEFAULT_BOOKMARK_FOLDER = "GET_DEFAULT_BOOKMARK_FOLDER";
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String CLIENT_API_GET_MOBILE_BOOKMARKS_FOLDER_ID =
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "GET_MOBILE_BOOKMARKS_FOLDER_ID";
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String CLIENT_API_IS_BOOKMARK_IN_MOBILE_BOOKMARKS_BRANCH =
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "IS_BOOKMARK_IN_MOBILE_BOOKMARKS_BRANCH";
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    static final String CLIENT_API_DELETE_ALL_USER_BOOKMARKS = "DELETE_ALL_USER_BOOKMARKS";
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String CLIENT_API_RESULT_KEY = "result";
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Defines Chrome's API authority, so it can be run and tested
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // independently.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String API_AUTHORITY_SUFFIX = ".browser";
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String BROWSER_CONTRACT_API_AUTHORITY =
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "com.google.android.apps.chrome.browser-contract";
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // These values are taken from android.provider.BrowserContract.java since
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that class is hidden from the SDK.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String BROWSER_CONTRACT_AUTHORITY = "com.android.browser";
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String BROWSER_CONTRACT_HISTORY_CONTENT_TYPE =
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "vnd.android.cursor.dir/browser-history";
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String BROWSER_CONTRACT_HISTORY_CONTENT_ITEM_TYPE =
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "vnd.android.cursor.item/browser-history";
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This Authority is for internal interface. It's concatenated with
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Context.getPackageName() so that we can install different channels
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // SxS and have different authorities.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String AUTHORITY_SUFFIX = ".ChromeBrowserProvider";
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String BOOKMARKS_PATH = "bookmarks";
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String SEARCHES_PATH = "searches";
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String HISTORY_PATH = "history";
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String COMBINED_PATH = "combined";
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String BOOKMARK_FOLDER_PATH = "hierarchy";
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final Uri BROWSER_CONTRACTS_BOOKMAKRS_API_URI = buildContentUri(
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            BROWSER_CONTRACT_API_AUTHORITY, BOOKMARKS_PATH);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final Uri BROWSER_CONTRACTS_SEARCHES_API_URI = buildContentUri(
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            BROWSER_CONTRACT_API_AUTHORITY, SEARCHES_PATH);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final Uri BROWSER_CONTRACTS_HISTORY_API_URI = buildContentUri(
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            BROWSER_CONTRACT_API_AUTHORITY, HISTORY_PATH);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final Uri BROWSER_CONTRACTS_COMBINED_API_URI = buildContentUri(
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            BROWSER_CONTRACT_API_AUTHORITY, COMBINED_PATH);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /** The parameter used to specify a bookmark parent ID in ContentValues. */
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final String BOOKMARK_PARENT_ID_PARAM = "parentId";
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /** The parameter used to specify whether this is a bookmark folder. */
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final String BOOKMARK_IS_FOLDER_PARAM = "isFolder";
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    /**
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)     * Invalid ID value for the Android ContentProvider API calls.
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)     * The value 0 is intentional: if the ID represents a bookmark node then it's the root node
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)     * and not accessible. Otherwise it represents a SQLite row id, so 0 is also invalid.
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)     */
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static final long INVALID_CONTENT_PROVIDER_ID = 0;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ID used to indicate an invalid id for bookmark nodes.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Client API queries should use ChromeBrowserProviderClient.INVALID_BOOKMARK_ID.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final long INVALID_BOOKMARK_ID = -1;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String LAST_MODIFIED_BOOKMARK_FOLDER_ID_KEY = "last_bookmark_folder_id";
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URI_MATCH_BOOKMARKS = 0;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URI_MATCH_BOOKMARKS_ID = 1;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URL_MATCH_API_BOOKMARK = 2;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URL_MATCH_API_BOOKMARK_ID = 3;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URL_MATCH_API_SEARCHES = 4;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URL_MATCH_API_SEARCHES_ID = 5;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URL_MATCH_API_HISTORY_CONTENT = 6;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URL_MATCH_API_HISTORY_CONTENT_ID = 7;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URL_MATCH_API_BOOKMARK_CONTENT = 8;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URL_MATCH_API_BOOKMARK_CONTENT_ID = 9;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URL_MATCH_BOOKMARK_SUGGESTIONS_ID = 10;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int URL_MATCH_BOOKMARK_HISTORY_SUGGESTIONS_ID = 11;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO : Using Android.provider.Browser.HISTORY_PROJECTION once THUMBNAIL,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TOUCH_ICON, and USER_ENTERED fields are supported.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String[] BOOKMARK_DEFAULT_PROJECTION = new String[] {
145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        BookmarkColumns._ID, BookmarkColumns.URL, BookmarkColumns.VISITS,
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        BookmarkColumns.DATE, BookmarkColumns.BOOKMARK, BookmarkColumns.TITLE,
147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        BookmarkColumns.FAVICON, BookmarkColumns.CREATED
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    };
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String[] SUGGEST_PROJECTION = new String[] {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BookmarkColumns._ID,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BookmarkColumns.TITLE,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BookmarkColumns.URL,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BookmarkColumns.DATE,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BookmarkColumns.BOOKMARK
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private final Object mInitializeUriMatcherLock = new Object();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private final Object mLoadNativeLock = new Object();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private UriMatcher mUriMatcher;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private long mLastModifiedBookmarkFolderId = INVALID_BOOKMARK_ID;
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private long mNativeChromeBrowserProvider;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private BookmarkNode mMobileBookmarksFolder;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    /**
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)     * Records whether we've received a call to one of the public ContentProvider APIs.
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)     */
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    protected boolean mContentProviderApiCalled;
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void ensureUriMatcherInitialized() {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        synchronized (mInitializeUriMatcherLock) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (mUriMatcher != null) return;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // The internal URIs
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String authority = getContext().getPackageName() + AUTHORITY_SUFFIX;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(authority, BOOKMARKS_PATH, URI_MATCH_BOOKMARKS);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(authority, BOOKMARKS_PATH + "/#", URI_MATCH_BOOKMARKS_ID);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // The internal authority for public APIs
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String apiAuthority = getContext().getPackageName() + API_AUTHORITY_SUFFIX;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(apiAuthority, BOOKMARKS_PATH, URL_MATCH_API_BOOKMARK);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(apiAuthority, BOOKMARKS_PATH + "/#", URL_MATCH_API_BOOKMARK_ID);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(apiAuthority, SEARCHES_PATH, URL_MATCH_API_SEARCHES);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(apiAuthority, SEARCHES_PATH + "/#", URL_MATCH_API_SEARCHES_ID);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(apiAuthority, HISTORY_PATH, URL_MATCH_API_HISTORY_CONTENT);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(apiAuthority, HISTORY_PATH + "/#", URL_MATCH_API_HISTORY_CONTENT_ID);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(apiAuthority, COMBINED_PATH, URL_MATCH_API_BOOKMARK);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(apiAuthority, COMBINED_PATH + "/#", URL_MATCH_API_BOOKMARK_ID);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // The internal authority for BrowserContracts
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_API_AUTHORITY, HISTORY_PATH,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_HISTORY_CONTENT);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_API_AUTHORITY, HISTORY_PATH + "/#",
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_HISTORY_CONTENT_ID);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_API_AUTHORITY, COMBINED_PATH,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_BOOKMARK);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_API_AUTHORITY, COMBINED_PATH + "/#",
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_BOOKMARK_ID);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_API_AUTHORITY, SEARCHES_PATH,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_SEARCHES);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_API_AUTHORITY, SEARCHES_PATH + "/#",
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_SEARCHES_ID);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_API_AUTHORITY, BOOKMARKS_PATH,
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_BOOKMARK_CONTENT);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_API_AUTHORITY, BOOKMARKS_PATH + "/#",
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_BOOKMARK_CONTENT_ID);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Added the Android Framework URIs, so the provider can easily switched
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // by adding 'browser' and 'com.android.browser' in manifest.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // The Android's BrowserContract
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_AUTHORITY, HISTORY_PATH,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_HISTORY_CONTENT);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_AUTHORITY, HISTORY_PATH + "/#",
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_HISTORY_CONTENT_ID);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_AUTHORITY, "combined", URL_MATCH_API_BOOKMARK);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_AUTHORITY, "combined/#", URL_MATCH_API_BOOKMARK_ID);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_AUTHORITY, SEARCHES_PATH, URL_MATCH_API_SEARCHES);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_AUTHORITY, SEARCHES_PATH + "/#",
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_SEARCHES_ID);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_AUTHORITY, BOOKMARKS_PATH,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_BOOKMARK_CONTENT);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(BROWSER_CONTRACT_AUTHORITY, BOOKMARKS_PATH + "/#",
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_API_BOOKMARK_CONTENT_ID);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // For supporting android.provider.browser.BookmarkColumns and
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // SearchColumns
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI("browser", BOOKMARKS_PATH, URL_MATCH_API_BOOKMARK);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI("browser", BOOKMARKS_PATH + "/#", URL_MATCH_API_BOOKMARK_ID);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI("browser", SEARCHES_PATH, URL_MATCH_API_SEARCHES);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI("browser", SEARCHES_PATH + "/#", URL_MATCH_API_SEARCHES_ID);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(apiAuthority,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               BOOKMARKS_PATH + "/" + SearchManager.SUGGEST_URI_PATH_QUERY,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_BOOKMARK_SUGGESTIONS_ID);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUriMatcher.addURI(apiAuthority,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               SearchManager.SUGGEST_URI_PATH_QUERY,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               URL_MATCH_BOOKMARK_HISTORY_SUGGESTIONS_ID);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @Override
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public boolean onCreate() {
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Pre-load shared preferences object, this happens on a separate thread
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        PreferenceManager.getDefaultSharedPreferences(getContext());
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * Lazily fetches the last modified bookmark folder id.
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private long getLastModifiedBookmarkFolderId() {
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (mLastModifiedBookmarkFolderId == INVALID_BOOKMARK_ID) {
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            SharedPreferences sharedPreferences =
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    PreferenceManager.getDefaultSharedPreferences(getContext());
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            mLastModifiedBookmarkFolderId = sharedPreferences.getLong(
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    LAST_MODIFIED_BOOKMARK_FOLDER_ID_KEY, INVALID_BOOKMARK_ID);
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return mLastModifiedBookmarkFolderId;
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private String buildSuggestWhere(String selection, int argc) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StringBuilder sb = new StringBuilder(selection);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (int i = 0; i < argc - 1; i++) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sb.append(" OR ");
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sb.append(selection);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return sb.toString();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private String getReadWritePermissionNameForBookmarkFolders() {
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return getContext().getApplicationContext().getPackageName() + ".permission."
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                + PERMISSION_READ_WRITE_BOOKMARKS;
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private Cursor getBookmarkHistorySuggestions(String selection, String[] selectionArgs,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String sortOrder, boolean excludeHistory) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        boolean matchTitles = false;
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        Vector<String> args = new Vector<String>();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        String like = selectionArgs[0] + "%";
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (selectionArgs[0].startsWith("http") || selectionArgs[0].startsWith("file")) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            args.add(like);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Match against common URL prefixes.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            args.add("http://" + like);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            args.add("https://" + like);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            args.add("http://www." + like);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            args.add("https://www." + like);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            args.add("file://" + like);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            matchTitles = true;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StringBuilder urlWhere = new StringBuilder("(");
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        urlWhere.append(buildSuggestWhere(selection, args.size()));
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (matchTitles) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            args.add(like);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            urlWhere.append(" OR title LIKE ?");
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        urlWhere.append(")");
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (excludeHistory) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            urlWhere.append(" AND bookmark=?");
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            args.add("1");
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selectionArgs = args.toArray(selectionArgs);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Cursor cursor = queryBookmarkFromAPI(SUGGEST_PROJECTION, urlWhere.toString(),
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                selectionArgs, sortOrder);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return new ChromeBrowserProviderSuggestionsCursor(cursor);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    /**
309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)     * @see android.content.ContentUris#parseId(Uri)
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)     * @return The id from a content URI or -1 if the URI has no id or is malformed.
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)     */
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    private static long getContentUriId(Uri uri) {
313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        try {
314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            return ContentUris.parseId(uri);
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        } catch (UnsupportedOperationException e) {
316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            return -1;
317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        } catch (NumberFormatException e) {
318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            return -1;
319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        }
320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @Override
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String sortOrder) {
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!canHandleContentProviderApiCall()) return null;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Check for invalid id values if provided.
328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        long bookmarkId = getContentUriId(uri);
329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (bookmarkId == INVALID_CONTENT_PROVIDER_ID) return null;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int match = mUriMatcher.match(uri);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Cursor cursor = null;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        switch (match) {
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_BOOKMARK_SUGGESTIONS_ID:
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cursor = getBookmarkHistorySuggestions(selection, selectionArgs, sortOrder, true);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_BOOKMARK_HISTORY_SUGGESTIONS_ID:
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cursor = getBookmarkHistorySuggestions(selection, selectionArgs, sortOrder, false);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK:
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cursor = queryBookmarkFromAPI(projection, selection, selectionArgs, sortOrder);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_ID:
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cursor = queryBookmarkFromAPI(projection, buildWhereClause(bookmarkId, selection),
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs, sortOrder);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_SEARCHES:
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cursor = querySearchTermFromAPI(projection, selection, selectionArgs, sortOrder);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_SEARCHES_ID:
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cursor = querySearchTermFromAPI(projection, buildWhereClause(bookmarkId, selection),
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs, sortOrder);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_HISTORY_CONTENT:
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cursor = queryBookmarkFromAPI(projection, buildHistoryWhereClause(selection),
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs, sortOrder);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_HISTORY_CONTENT_ID:
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cursor = queryBookmarkFromAPI(projection,
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        buildHistoryWhereClause(bookmarkId, selection), selectionArgs, sortOrder);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_CONTENT:
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cursor = queryBookmarkFromAPI(projection, buildBookmarkWhereClause(selection),
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs, sortOrder);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_CONTENT_ID:
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cursor = queryBookmarkFromAPI(projection,
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        buildBookmarkWhereClause(bookmarkId, selection), selectionArgs, sortOrder);
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            default:
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                throw new IllegalArgumentException(TAG + ": query - unknown URL uri = " + uri);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (cursor == null) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            cursor = new MatrixCursor(new String[] { });
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cursor.setNotificationUri(getContext().getContentResolver(), uri);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return cursor;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @Override
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public Uri insert(Uri uri, ContentValues values) {
38290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!canHandleContentProviderApiCall()) return null;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int match = mUriMatcher.match(uri);
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Uri res = null;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        long id;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        switch (match) {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URI_MATCH_BOOKMARKS:
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                id = addBookmark(values);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (id == INVALID_BOOKMARK_ID) return null;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_CONTENT:
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                values.put(BookmarkColumns.BOOKMARK, 1);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                //$FALL-THROUGH$
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK:
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_HISTORY_CONTENT:
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                id = addBookmarkFromAPI(values);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (id == INVALID_CONTENT_PROVIDER_ID) return null;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_SEARCHES:
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                id = addSearchTermFromAPI(values);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (id == INVALID_CONTENT_PROVIDER_ID) return null;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            default:
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                throw new IllegalArgumentException(TAG + ": insert - unknown URL " + uri);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        res = ContentUris.withAppendedId(uri, id);
409a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        notifyChange(res);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return res;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @Override
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int delete(Uri uri, String selection, String[] selectionArgs) {
41590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!canHandleContentProviderApiCall()) return 0;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Check for invalid id values if provided.
418a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        long bookmarkId = getContentUriId(uri);
419a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (bookmarkId == INVALID_CONTENT_PROVIDER_ID) return 0;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int match = mUriMatcher.match(uri);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int result;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        switch (match) {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URI_MATCH_BOOKMARKS_ID :
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = nativeRemoveBookmark(mNativeChromeBrowserProvider, bookmarkId);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_ID:
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = removeBookmarkFromAPI(
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        buildWhereClause(bookmarkId, selection), selectionArgs);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK:
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = removeBookmarkFromAPI(selection, selectionArgs);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_SEARCHES_ID:
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = removeSearchFromAPI(buildWhereClause(bookmarkId, selection),
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_SEARCHES:
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = removeSearchFromAPI(selection, selectionArgs);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_HISTORY_CONTENT:
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = removeHistoryFromAPI(selection, selectionArgs);
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_HISTORY_CONTENT_ID:
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = removeHistoryFromAPI(buildWhereClause(bookmarkId, selection),
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_CONTENT:
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = removeBookmarkFromAPI(buildBookmarkWhereClause(selection), selectionArgs);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_CONTENT_ID:
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = removeBookmarkFromAPI(buildBookmarkWhereClause(bookmarkId, selection),
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs);
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            default:
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                throw new IllegalArgumentException(TAG + ": delete - unknown URL " + uri);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
458a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (result != 0) notifyChange(uri);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return result;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @Override
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
46490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!canHandleContentProviderApiCall()) return 0;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Check for invalid id values if provided.
467a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        long bookmarkId = getContentUriId(uri);
468a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (bookmarkId == INVALID_CONTENT_PROVIDER_ID) return 0;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int match = mUriMatcher.match(uri);
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int result;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        switch (match) {
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URI_MATCH_BOOKMARKS_ID:
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                String url = null;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (values.containsKey(Browser.BookmarkColumns.URL)) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    url = values.getAsString(Browser.BookmarkColumns.URL);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                String title = values.getAsString(Browser.BookmarkColumns.TITLE);
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                long parentId = INVALID_BOOKMARK_ID;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (values.containsKey(BOOKMARK_PARENT_ID_PARAM)) {
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    parentId = values.getAsLong(BOOKMARK_PARENT_ID_PARAM);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = nativeUpdateBookmark(mNativeChromeBrowserProvider, bookmarkId, url, title,
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        parentId);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                updateLastModifiedBookmarkFolder(parentId);
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_ID:
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = updateBookmarkFromAPI(values, buildWhereClause(bookmarkId, selection),
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK:
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = updateBookmarkFromAPI(values, selection, selectionArgs);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_SEARCHES_ID:
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = updateSearchTermFromAPI(values, buildWhereClause(bookmarkId, selection),
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs);
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_SEARCHES:
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = updateSearchTermFromAPI(values, selection, selectionArgs);
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_HISTORY_CONTENT:
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = updateBookmarkFromAPI(values, buildHistoryWhereClause(selection),
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs);
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_HISTORY_CONTENT_ID:
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = updateBookmarkFromAPI(values,
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        buildHistoryWhereClause(bookmarkId, selection), selectionArgs);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_CONTENT:
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = updateBookmarkFromAPI(values, buildBookmarkWhereClause(selection),
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        selectionArgs);
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_CONTENT_ID:
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                result = updateBookmarkFromAPI(values,
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        buildBookmarkWhereClause(bookmarkId, selection), selectionArgs);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            default:
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                throw new IllegalArgumentException(TAG + ": update - unknown URL " + uri);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
520a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (result != 0) notifyChange(uri);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return result;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @Override
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public String getType(Uri uri) {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ensureUriMatcherInitialized();
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int match = mUriMatcher.match(uri);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        switch (match) {
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URI_MATCH_BOOKMARKS:
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK:
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return "vnd.android.cursor.dir/bookmark";
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URI_MATCH_BOOKMARKS_ID:
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_BOOKMARK_ID:
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return "vnd.android.cursor.item/bookmark";
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_SEARCHES:
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return "vnd.android.cursor.dir/searches";
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_SEARCHES_ID:
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return "vnd.android.cursor.item/searches";
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_HISTORY_CONTENT:
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return BROWSER_CONTRACT_HISTORY_CONTENT_TYPE;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case URL_MATCH_API_HISTORY_CONTENT_ID:
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return BROWSER_CONTRACT_HISTORY_CONTENT_ITEM_TYPE;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            default:
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                throw new IllegalArgumentException(TAG + ": getType - unknown URL " + uri);
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private long addBookmark(ContentValues values) {
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        String url = values.getAsString(Browser.BookmarkColumns.URL);
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        String title = values.getAsString(Browser.BookmarkColumns.TITLE);
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        boolean isFolder = false;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (values.containsKey(BOOKMARK_IS_FOLDER_PARAM)) {
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            isFolder = values.getAsBoolean(BOOKMARK_IS_FOLDER_PARAM);
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        long parentId = INVALID_BOOKMARK_ID;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (values.containsKey(BOOKMARK_PARENT_ID_PARAM)) {
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            parentId = values.getAsLong(BOOKMARK_PARENT_ID_PARAM);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        long id = nativeAddBookmark(mNativeChromeBrowserProvider, url, title, isFolder, parentId);
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (id == INVALID_BOOKMARK_ID) return id;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (isFolder) {
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            updateLastModifiedBookmarkFolder(id);
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            updateLastModifiedBookmarkFolder(parentId);
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return id;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void updateLastModifiedBookmarkFolder(long id) {
571c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (getLastModifiedBookmarkFolderId() == id) return;
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mLastModifiedBookmarkFolderId = id;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SharedPreferences sharedPreferences =
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                PreferenceManager.getDefaultSharedPreferences(getContext());
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sharedPreferences.edit()
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                .putLong(LAST_MODIFIED_BOOKMARK_FOLDER_ID_KEY, mLastModifiedBookmarkFolderId)
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                .apply();
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static String getApiAuthority(Context context) {
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return context.getPackageName() + API_AUTHORITY_SUFFIX;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static String getInternalAuthority(Context context) {
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return context.getPackageName() + AUTHORITY_SUFFIX;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static Uri getBookmarksUri(Context context) {
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return buildContentUri(getInternalAuthority(context), BOOKMARKS_PATH);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static Uri getBookmarkFolderUri(Context context) {
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return buildContentUri(getInternalAuthority(context), BOOKMARK_FOLDER_PATH);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static Uri getBookmarksApiUri(Context context) {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return buildContentUri(getApiAuthority(context), BOOKMARKS_PATH);
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static Uri getSearchesApiUri(Context context) {
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return buildContentUri(getApiAuthority(context), SEARCHES_PATH);
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private boolean bookmarkNodeExists(long nodeId) {
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (nodeId < 0) return false;
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeBookmarkNodeExists(mNativeChromeBrowserProvider, nodeId);
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private long createBookmarksFolderOnce(String title, long parentId) {
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeCreateBookmarksFolderOnce(mNativeChromeBrowserProvider, title, parentId);
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
614f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private BookmarkNode getEditableBookmarkFolderHierarchy() {
615f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return nativeGetEditableBookmarkFolders(mNativeChromeBrowserProvider);
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protected BookmarkNode getBookmarkNode(long nodeId, boolean getParent, boolean getChildren,
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            boolean getFavicons, boolean getThumbnails) {
620c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Don't allow going up the hierarchy if sync is disabled and the requested node
621c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // is the Mobile Bookmarks folder.
622c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (getParent && nodeId == getMobileBookmarksFolderId()
623c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                && !SyncStatusHelper.get(getContext()).isSyncEnabled()) {
624c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            getParent = false;
625c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
626c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BookmarkNode node = nativeGetBookmarkNode(mNativeChromeBrowserProvider, nodeId, getParent,
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                getChildren);
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!getFavicons && !getThumbnails) return node;
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Favicons and thumbnails need to be populated separately as they are provided
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // asynchronously by Chromium services other than the bookmark model.
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (node.parent() != null) populateNodeImages(node.parent(), getFavicons, getThumbnails);
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (BookmarkNode child : node.children()) {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            populateNodeImages(child, getFavicons, getThumbnails);
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return node;
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private BookmarkNode getDefaultBookmarkFolder() {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Try to access the bookmark folder last modified by us. If it doesn't exist anymore
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // then use the synced node (Mobile Bookmarks).
644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        BookmarkNode lastModified = getBookmarkNode(getLastModifiedBookmarkFolderId(), false, false,
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                false, false);
6465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        if (lastModified == null || lastModified.isUrl()) {
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            lastModified = getMobileBookmarksFolder();
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mLastModifiedBookmarkFolderId = lastModified != null ? lastModified.id() :
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    INVALID_BOOKMARK_ID;
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return lastModified;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void populateNodeImages(BookmarkNode node, boolean favicon, boolean thumbnail) {
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (node == null || node.type() != Type.URL) return;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (favicon) {
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            node.setFavicon(nativeGetFaviconOrTouchIcon(mNativeChromeBrowserProvider, node.url()));
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (thumbnail) {
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            node.setThumbnail(nativeGetThumbnail(mNativeChromeBrowserProvider, node.url()));
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private BookmarkNode getMobileBookmarksFolder() {
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (mMobileBookmarksFolder == null) {
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mMobileBookmarksFolder = nativeGetMobileBookmarksFolder(mNativeChromeBrowserProvider);
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return mMobileBookmarksFolder;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protected long getMobileBookmarksFolderId() {
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BookmarkNode mobileBookmarks = getMobileBookmarksFolder();
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return mobileBookmarks != null ? mobileBookmarks.id() : INVALID_BOOKMARK_ID;
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private boolean isBookmarkInMobileBookmarksBranch(long nodeId) {
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (nodeId <= 0) return false;
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeIsBookmarkInMobileBookmarksBranch(mNativeChromeBrowserProvider, nodeId);
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static String argKey(int i) {
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return "arg" + i;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @Override
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public Bundle call(String method, String arg, Bundle extras) {
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // TODO(shashishekhar): Refactor this code into a separate class.
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Caller must have the READ_WRITE_BOOKMARK_FOLDERS permission.
691c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        getContext().enforcePermission(getReadWritePermissionNameForBookmarkFolders(),
692c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       Binder.getCallingPid(), Binder.getCallingUid(), TAG);
69390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!canHandleContentProviderApiCall()) return null;
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (method == null || extras == null) return null;
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Bundle result = new Bundle();
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (CLIENT_API_BOOKMARK_NODE_EXISTS.equals(method)) {
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            result.putBoolean(CLIENT_API_RESULT_KEY,
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    bookmarkNodeExists(extras.getLong(argKey(0))));
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (CLIENT_API_CREATE_BOOKMARKS_FOLDER_ONCE.equals(method)) {
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            result.putLong(CLIENT_API_RESULT_KEY,
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    createBookmarksFolderOnce(extras.getString(argKey(0)),
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              extras.getLong(argKey(1))));
704f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        } else if (CLIENT_API_GET_EDITABLE_BOOKMARK_FOLDER_HIERARCHY.equals(method)) {
705f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            result.putParcelable(CLIENT_API_RESULT_KEY, getEditableBookmarkFolderHierarchy());
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (CLIENT_API_GET_BOOKMARK_NODE.equals(method)) {
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            result.putParcelable(CLIENT_API_RESULT_KEY,
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    getBookmarkNode(extras.getLong(argKey(0)),
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    extras.getBoolean(argKey(1)),
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    extras.getBoolean(argKey(2)),
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    extras.getBoolean(argKey(3)),
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    extras.getBoolean(argKey(4))));
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (CLIENT_API_GET_DEFAULT_BOOKMARK_FOLDER.equals(method)) {
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            result.putParcelable(CLIENT_API_RESULT_KEY, getDefaultBookmarkFolder());
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (method.equals(CLIENT_API_GET_MOBILE_BOOKMARKS_FOLDER_ID)) {
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            result.putLong(CLIENT_API_RESULT_KEY, getMobileBookmarksFolderId());
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (CLIENT_API_IS_BOOKMARK_IN_MOBILE_BOOKMARKS_BRANCH.equals(method)) {
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            result.putBoolean(CLIENT_API_RESULT_KEY,
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    isBookmarkInMobileBookmarksBranch(extras.getLong(argKey(0))));
720f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        } else if (CLIENT_API_DELETE_ALL_USER_BOOKMARKS.equals(method)) {
721f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            nativeRemoveAllUserBookmarks(mNativeChromeBrowserProvider);
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            Log.w(TAG, "Received invalid method " + method);
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return null;
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return result;
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
73190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)     * Checks whether Chrome is sufficiently initialized to handle a call to the
73290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)     * ChromeBrowserProvider.
73390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)     */
73490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    private boolean canHandleContentProviderApiCall() {
73590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        mContentProviderApiCalled = true;
73690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
73790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (isInUiThread()) return false;
73890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        if (!ensureNativeChromeLoaded()) return false;
73990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        return true;
74090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
74190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
74290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    /**
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The type of a BookmarkNode.
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public enum Type {
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        URL,
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FOLDER,
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BOOKMARK_BAR,
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OTHER_NODE,
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        MOBILE
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Simple Data Object representing the chrome bookmark node.
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static class BookmarkNode implements Parcelable {
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private final long mId;
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private final String mName;
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private final String mUrl;
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private final Type mType;
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private final BookmarkNode mParent;
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private final List<BookmarkNode> mChildren = new ArrayList<BookmarkNode>();
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Favicon and thumbnail optionally set in a 2-step procedure.
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private byte[] mFavicon;
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private byte[] mThumbnail;
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /** Used to pass structured data back from the native code. */
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @VisibleForTesting
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public BookmarkNode(long id, Type type, String name, String url, BookmarkNode parent) {
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mId = id;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mName = name;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mUrl = url;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mType = type;
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mParent = parent;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return The id of this bookmark entry.
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public long id() {
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mId;
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return The name of this bookmark entry.
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public String name() {
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mName;
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return The URL of this bookmark entry.
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public String url() {
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mUrl;
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return The type of this bookmark entry.
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public Type type() {
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mType;
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return The bookmark favicon, if any.
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public byte[] favicon() {
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mFavicon;
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return The bookmark thumbnail, if any.
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public byte[] thumbnail() {
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mThumbnail;
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return The parent folder of this bookmark entry.
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public BookmarkNode parent() {
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mParent;
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Adds a child to this node.
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         *
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * <p>
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Used solely by the native code.
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @VisibleForTesting
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @CalledByNativeUnchecked("BookmarkNode")
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void addChild(BookmarkNode child) {
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mChildren.add(child);
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return The child bookmark nodes of this node.
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public List<BookmarkNode> children() {
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mChildren;
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return Whether this node represents a bookmarked URL or not.
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public boolean isUrl() {
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mUrl != null;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return true if the two individual nodes contain the same information.
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * The existence of parent and children nodes is checked, but their contents are not.
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public boolean equalContents(BookmarkNode node) {
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return node != null &&
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    mId == node.mId &&
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    !(mName == null ^ node.mName == null) &&
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    (mName == null || mName.equals(node.mName)) &&
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    !(mUrl == null ^ node.mUrl == null) &&
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    (mUrl == null || mUrl.equals(node.mUrl)) &&
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    mType == node.mType &&
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    byteArrayEqual(mFavicon, node.mFavicon) &&
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    byteArrayEqual(mThumbnail, node.mThumbnail) &&
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    !(mParent == null ^ node.mParent == null) &&
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    children().size() == node.children().size();
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private static boolean byteArrayEqual(byte[] byte1, byte[] byte2) {
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (byte1 == null && byte2 != null) return byte2.length == 0;
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (byte2 == null && byte1 != null) return byte1.length == 0;
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return Arrays.equals(byte1, byte2);
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @CalledByNative("BookmarkNode")
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private static BookmarkNode create(
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                long id, int type, String name, String url, BookmarkNode parent) {
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return new BookmarkNode(id, Type.values()[type], name, url, parent);
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @VisibleForTesting
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void setFavicon(byte[] favicon) {
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mFavicon = favicon;
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @VisibleForTesting
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void setThumbnail(byte[] thumbnail) {
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mThumbnail = thumbnail;
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public int describeContents() {
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return 0;
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void writeToParcel(Parcel dest, int flags) {
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Write the current node id.
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dest.writeLong(mId);
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Serialize the full hierarchy from the root.
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            getHierarchyRoot().writeNodeContentsRecursive(dest);
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @VisibleForTesting
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public BookmarkNode getHierarchyRoot() {
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            BookmarkNode root = this;
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            while (root.parent() != null) {
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                root = root.parent();
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return root;
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private void writeNodeContentsRecursive(Parcel dest) {
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            writeNodeContents(dest);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dest.writeInt(mChildren.size());
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            for (BookmarkNode child : mChildren) {
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                child.writeNodeContentsRecursive(dest);
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        private void writeNodeContents(Parcel dest) {
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dest.writeLong(mId);
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dest.writeString(mName);
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dest.writeString(mUrl);
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dest.writeInt(mType.ordinal());
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dest.writeByteArray(mFavicon);
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dest.writeByteArray(mThumbnail);
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dest.writeLong(mParent != null ? mParent.mId : INVALID_BOOKMARK_ID);
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public static final Creator<BookmarkNode> CREATOR = new Creator<BookmarkNode>() {
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            private HashMap<Long, BookmarkNode> mNodeMap;
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            @Override
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            public BookmarkNode createFromParcel(Parcel source) {
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                mNodeMap = new HashMap<Long, BookmarkNode>();
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                long currentNodeId = source.readLong();
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                readNodeContentsRecursive(source);
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                BookmarkNode node = getNode(currentNodeId);
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                mNodeMap.clear();
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return node;
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            @Override
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            public BookmarkNode[] newArray(int size) {
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return new BookmarkNode[size];
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            private BookmarkNode getNode(long id) {
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (id == INVALID_BOOKMARK_ID) return null;
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                Long nodeId = Long.valueOf(id);
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (!mNodeMap.containsKey(nodeId)) {
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    Log.e(TAG, "Invalid BookmarkNode hierarchy. Unknown id " + id);
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    return null;
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return mNodeMap.get(nodeId);
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            private BookmarkNode readNodeContents(Parcel source) {
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                long id = source.readLong();
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                String name = source.readString();
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                String url = source.readString();
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                int type = source.readInt();
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                byte[] favicon = source.createByteArray();
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                byte[] thumbnail = source.createByteArray();
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                long parentId = source.readLong();
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (type < 0 || type >= Type.values().length) {
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    Log.w(TAG, "Invalid node type ordinal value.");
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    return null;
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                BookmarkNode node = new BookmarkNode(id, Type.values()[type], name, url,
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        getNode(parentId));
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                node.setFavicon(favicon);
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                node.setThumbnail(thumbnail);
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return node;
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            private BookmarkNode readNodeContentsRecursive(Parcel source) {
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                BookmarkNode node = readNodeContents(source);
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (node == null) return null;
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                Long nodeId = Long.valueOf(node.id());
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (mNodeMap.containsKey(nodeId)) {
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    Log.e(TAG, "Invalid BookmarkNode hierarchy. Duplicate id " + node.id());
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    return null;
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                mNodeMap.put(nodeId, node);
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                int numChildren = source.readInt();
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                for (int i = 0; i < numChildren; ++i) {
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    node.addChild(readNodeContentsRecursive(source));
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return node;
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        };
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private long addBookmarkFromAPI(ContentValues values) {
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BookmarkRow row = BookmarkRow.fromContentValues(values);
10056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        if (row.mUrl == null) {
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throw new IllegalArgumentException("Must have a bookmark URL");
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeAddBookmarkFromAPI(mNativeChromeBrowserProvider,
10096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mUrl, row.mCreated, row.mIsBookmark, row.mDate, row.mFavicon,
10106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mTitle, row.mVisits, row.mParentId);
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private Cursor queryBookmarkFromAPI(String[] projectionIn, String selection,
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String[] selectionArgs, String sortOrder) {
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        String[] projection = null;
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (projectionIn == null || projectionIn.length == 0) {
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            projection = BOOKMARK_DEFAULT_PROJECTION;
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            projection = projectionIn;
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeQueryBookmarkFromAPI(mNativeChromeBrowserProvider, projection, selection,
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                selectionArgs, sortOrder);
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private int updateBookmarkFromAPI(ContentValues values, String selection,
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String[] selectionArgs) {
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BookmarkRow row = BookmarkRow.fromContentValues(values);
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeUpdateBookmarkFromAPI(mNativeChromeBrowserProvider,
10306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mUrl, row.mCreated, row.mIsBookmark, row.mDate,
10316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mFavicon, row.mTitle, row.mVisits, row.mParentId, selection, selectionArgs);
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private int removeBookmarkFromAPI(String selection, String[] selectionArgs) {
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeRemoveBookmarkFromAPI(mNativeChromeBrowserProvider, selection, selectionArgs);
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private int removeHistoryFromAPI(String selection, String[] selectionArgs) {
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeRemoveHistoryFromAPI(mNativeChromeBrowserProvider, selection, selectionArgs);
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @CalledByNative
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void onBookmarkChanged() {
1044a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        notifyChange(buildAPIContentUri(getContext(), BOOKMARKS_PATH));
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @CalledByNative
10481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    private void onHistoryChanged() {
10491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        notifyChange(buildAPIContentUri(getContext(), HISTORY_PATH));
10501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
10511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
10521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @CalledByNative
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void onSearchTermChanged() {
1054a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        notifyChange(buildAPIContentUri(getContext(), SEARCHES_PATH));
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private long addSearchTermFromAPI(ContentValues values) {
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SearchRow row = SearchRow.fromContentValues(values);
10596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        if (row.mTerm == null) {
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throw new IllegalArgumentException("Must have a search term");
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return nativeAddSearchTermFromAPI(mNativeChromeBrowserProvider, row.mTerm, row.mDate);
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private int updateSearchTermFromAPI(ContentValues values, String selection,
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String[] selectionArgs) {
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SearchRow row = SearchRow.fromContentValues(values);
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeUpdateSearchTermFromAPI(mNativeChromeBrowserProvider,
10696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mTerm, row.mDate, selection, selectionArgs);
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private Cursor querySearchTermFromAPI(String[] projectionIn, String selection,
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String[] selectionArgs, String sortOrder) {
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        String[] projection = null;
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (projectionIn == null || projectionIn.length == 0) {
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            projection = android.provider.Browser.SEARCHES_PROJECTION;
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            projection = projectionIn;
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeQuerySearchTermFromAPI(mNativeChromeBrowserProvider, projection, selection,
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                selectionArgs, sortOrder);
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private int removeSearchFromAPI(String selection, String[] selectionArgs) {
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return nativeRemoveSearchTermFromAPI(mNativeChromeBrowserProvider,
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                selection, selectionArgs);
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static boolean isInUiThread() {
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!ThreadUtils.runningOnUiThread()) return false;
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!"REL".equals(Build.VERSION.CODENAME)) {
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throw new IllegalStateException("Shouldn't run in the UI thread");
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Log.w(TAG, "ChromeBrowserProvider methods cannot be called from the UI thread.");
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static Uri buildContentUri(String authority, String path) {
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return Uri.parse("content://" + authority + "/" + path);
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static Uri buildAPIContentUri(Context context, String path) {
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return buildContentUri(context.getPackageName() + API_AUTHORITY_SUFFIX, path);
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static String buildWhereClause(long id, String selection) {
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StringBuffer sb = new StringBuffer();
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sb.append(BaseColumns._ID);
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sb.append(" = ");
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sb.append(id);
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!TextUtils.isEmpty(selection)) {
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sb.append(" AND (");
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sb.append(selection);
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sb.append(")");
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return sb.toString();
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static String buildHistoryWhereClause(long id, String selection) {
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return buildWhereClause(id, buildBookmarkWhereClause(selection, false));
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static String buildHistoryWhereClause(String selection) {
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return buildBookmarkWhereClause(selection, false);
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return a SQL where class which is inserted the bookmark condition.
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private static String buildBookmarkWhereClause(String selection, boolean isBookmark) {
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StringBuffer sb = new StringBuffer();
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sb.append(BookmarkColumns.BOOKMARK);
1135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        sb.append(isBookmark ? " = 1 " : " = 0");
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!TextUtils.isEmpty(selection)) {
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sb.append(" AND (");
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sb.append(selection);
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sb.append(")");
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return sb.toString();
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static String buildBookmarkWhereClause(long id, String selection) {
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return buildWhereClause(id, buildBookmarkWhereClause(selection, true));
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static String buildBookmarkWhereClause(String selection) {
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return buildBookmarkWhereClause(selection, true);
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wrap the value of BookmarkColumn.
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static class BookmarkRow {
11546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        Boolean mIsBookmark;
11556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        Long mCreated;
11566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        String mUrl;
11576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        Long mDate;
11586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        byte[] mFavicon;
11596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        String mTitle;
11606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        Integer mVisits;
11616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        long mParentId;
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static BookmarkRow fromContentValues(ContentValues values) {
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            BookmarkRow row = new BookmarkRow();
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (values.containsKey(BookmarkColumns.URL)) {
11666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mUrl = values.getAsString(BookmarkColumns.URL);
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (values.containsKey(BookmarkColumns.BOOKMARK)) {
11696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mIsBookmark = values.getAsInteger(BookmarkColumns.BOOKMARK) != 0;
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (values.containsKey(BookmarkColumns.CREATED)) {
11726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mCreated = values.getAsLong(BookmarkColumns.CREATED);
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (values.containsKey(BookmarkColumns.DATE)) {
11756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mDate = values.getAsLong(BookmarkColumns.DATE);
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (values.containsKey(BookmarkColumns.FAVICON)) {
11786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mFavicon = values.getAsByteArray(BookmarkColumns.FAVICON);
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                // We need to know that the caller set the favicon column.
11806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                if (row.mFavicon == null) {
11816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    row.mFavicon = new byte[0];
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (values.containsKey(BookmarkColumns.TITLE)) {
11856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mTitle = values.getAsString(BookmarkColumns.TITLE);
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (values.containsKey(BookmarkColumns.VISITS)) {
11886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mVisits = values.getAsInteger(BookmarkColumns.VISITS);
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (values.containsKey(BOOKMARK_PARENT_ID_PARAM)) {
11916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mParentId = values.getAsLong(BOOKMARK_PARENT_ID_PARAM);
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return row;
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wrap the value of SearchColumn.
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static class SearchRow {
11996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        String mTerm;
12006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        Long mDate;
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static SearchRow fromContentValues(ContentValues values) {
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SearchRow row = new SearchRow();
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (values.containsKey(SearchColumns.SEARCH)) {
12056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mTerm = values.getAsString(SearchColumns.SEARCH);
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (values.containsKey(SearchColumns.DATE)) {
12086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                row.mDate = values.getAsLong(SearchColumns.DATE);
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return row;
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Returns true if the native side of the class is initialized.
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protected boolean isNativeSideInitialized() {
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return mNativeChromeBrowserProvider != 0;
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Make sure chrome is running. This method mustn't run on UI thread.
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return Whether the native chrome process is running successfully once this has returned.
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private boolean ensureNativeChromeLoaded() {
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ensureUriMatcherInitialized();
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        synchronized (mLoadNativeLock) {
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (mNativeChromeBrowserProvider != 0) return true;
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final AtomicBoolean retVal = new AtomicBoolean(true);
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ThreadUtils.runOnUiThreadBlocking(new Runnable() {
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                @Override
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                public void run() {
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    retVal.set(ensureNativeChromeLoadedOnUIThread());
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            });
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return retVal.get();
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * This method should only run on UI thread.
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protected boolean ensureNativeChromeLoadedOnUIThread() {
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (isNativeSideInitialized()) return true;
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mNativeChromeBrowserProvider = nativeInit();
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return isNativeSideInitialized();
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @Override
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    protected void finalize() throws Throwable {
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try {
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Tests might try to destroy this in the wrong thread.
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ThreadUtils.runOnUiThreadBlocking(new Runnable() {
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                @Override
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                public void run() {
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    ensureNativeChromeDestroyedOnUIThread();
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            });
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } finally {
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            super.finalize();
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * This method should only run on UI thread.
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void ensureNativeChromeDestroyedOnUIThread() {
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (isNativeSideInitialized()) {
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            nativeDestroy(mNativeChromeBrowserProvider);
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mNativeChromeBrowserProvider = 0;
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    @SuppressLint("NewApi")
1278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    private void notifyChange(final Uri uri) {
1279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // If the calling user is different than current one, we need to post a
1280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // task to notify change, otherwise, a system level hidden permission
1281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // INTERACT_ACROSS_USERS_FULL is needed.
1282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // The related APIs were added in API 17, it should be safe to fallback to
1283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // normal way for notifying change, because caller can't be other users in
1284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // devices whose API level is less than API 17.
1285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
1286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            UserHandle callingUserHandle = Binder.getCallingUserHandle();
1287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            if (callingUserHandle != null &&
1288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    !callingUserHandle.equals(android.os.Process.myUserHandle())) {
1289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                ThreadUtils.postOnUiThread(new Runnable() {
1290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    @Override
1291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    public void run() {
1292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                        getContext().getContentResolver().notifyChange(uri, null);
1293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    }
1294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                });
1295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                return;
1296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            }
1297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        }
1298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        getContext().getContentResolver().notifyChange(uri, null);
1299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
1300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native long nativeInit();
1302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native void nativeDestroy(long nativeChromeBrowserProvider);
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Public API native methods.
1305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native long nativeAddBookmark(long nativeChromeBrowserProvider,
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String url, String title, boolean isFolder, long parentId);
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native int nativeRemoveBookmark(long nativeChromeBrowserProvider, long id);
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native int nativeUpdateBookmark(long nativeChromeBrowserProvider,
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            long id, String url, String title, long parentId);
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native long nativeAddBookmarkFromAPI(long nativeChromeBrowserProvider,
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String url, Long created, Boolean isBookmark, Long date, byte[] favicon,
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String title, Integer visits, long parentId);
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native SQLiteCursor nativeQueryBookmarkFromAPI(long nativeChromeBrowserProvider,
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String[] projection, String selection, String[] selectionArgs, String sortOrder);
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native int nativeUpdateBookmarkFromAPI(long nativeChromeBrowserProvider,
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String url, Long created, Boolean isBookmark, Long date, byte[] favicon,
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String title, Integer visits, long parentId, String selection, String[] selectionArgs);
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native int nativeRemoveBookmarkFromAPI(long nativeChromeBrowserProvider,
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String selection, String[] selectionArgs);
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native int nativeRemoveHistoryFromAPI(long nativeChromeBrowserProvider,
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String selection, String[] selectionArgs);
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native long nativeAddSearchTermFromAPI(long nativeChromeBrowserProvider,
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String term, Long date);
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native SQLiteCursor nativeQuerySearchTermFromAPI(long nativeChromeBrowserProvider,
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String[] projection, String selection, String[] selectionArgs, String sortOrder);
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native int nativeUpdateSearchTermFromAPI(long nativeChromeBrowserProvider,
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String search, Long date, String selection, String[] selectionArgs);
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native int nativeRemoveSearchTermFromAPI(long nativeChromeBrowserProvider,
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String selection, String[] selectionArgs);
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Client API native methods.
1343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native boolean nativeBookmarkNodeExists(long nativeChromeBrowserProvider, long id);
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native long nativeCreateBookmarksFolderOnce(long nativeChromeBrowserProvider,
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            String title, long parentId);
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private native BookmarkNode nativeGetEditableBookmarkFolders(long nativeChromeBrowserProvider);
13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    private native void nativeRemoveAllUserBookmarks(long nativeChromeBrowserProvider);
1351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native BookmarkNode nativeGetBookmarkNode(long nativeChromeBrowserProvider,
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            long id, boolean getParent, boolean getChildren);
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native BookmarkNode nativeGetMobileBookmarksFolder(long nativeChromeBrowserProvider);
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native boolean nativeIsBookmarkInMobileBookmarksBranch(long nativeChromeBrowserProvider,
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            long id);
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native byte[] nativeGetFaviconOrTouchIcon(long nativeChromeBrowserProvider, String url);
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native byte[] nativeGetThumbnail(long nativeChromeBrowserProvider, String url);
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1364