| Index: chrome/android/java_staging/src/org/chromium/chrome/browser/bookmarkimport/BookmarkImporter.java
|
| diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/bookmarkimport/BookmarkImporter.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/bookmarkimport/BookmarkImporter.java
|
| deleted file mode 100644
|
| index cc851130921fdb6b0e67fa2b43ccd16bbf80c2f0..0000000000000000000000000000000000000000
|
| --- a/chrome/android/java_staging/src/org/chromium/chrome/browser/bookmarkimport/BookmarkImporter.java
|
| +++ /dev/null
|
| @@ -1,364 +0,0 @@
|
| -// Copyright 2015 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -package org.chromium.chrome.browser.bookmarkimport;
|
| -
|
| -import android.content.ContentValues;
|
| -import android.content.Context;
|
| -import android.database.Cursor;
|
| -import android.net.Uri;
|
| -import android.os.AsyncTask;
|
| -import android.provider.Browser;
|
| -import android.provider.Browser.BookmarkColumns;
|
| -import android.util.Log;
|
| -
|
| -import org.chromium.chrome.browser.ChromeBrowserProvider;
|
| -import org.chromium.chrome.browser.ChromeBrowserProviderClient;
|
| -
|
| -import java.util.ArrayList;
|
| -import java.util.HashSet;
|
| -import java.util.Iterator;
|
| -import java.util.LinkedHashMap;
|
| -
|
| -/**
|
| - * Imports bookmarks from another browser into Chrome.
|
| - */
|
| -public abstract class BookmarkImporter {
|
| - private static final String TAG = "BookmarkImporter";
|
| -
|
| - /** Class containing the results of a bookmark import operation */
|
| - public static class ImportResults {
|
| - public int newBookmarks; // Number of new bookmarks that could be imported.
|
| - public int numImported; // Number of bookmarks that were successfully imported.
|
| - public long rootFolderId; // ID of the folder where the bookmarks were imported.
|
| - }
|
| -
|
| - /** Listener for asynchronous import events. */
|
| - public interface OnBookmarksImportedListener {
|
| - /**
|
| - * Triggered after finishing the bookmark importing operation.
|
| - * @param results Results of the importing operation. Will be null in case of failure.
|
| - */
|
| - public void onBookmarksImported(ImportResults results);
|
| - }
|
| -
|
| - /** Object defining an imported bookmark. */
|
| - static class Bookmark {
|
| - // To be provided by the bookmark extractors.
|
| - public long id; // Local id of the imported bookmark. Value ROOT_FOLDER_ID is reserved.
|
| - public long parentId; // Import id of the parent node.
|
| - public boolean isFolder; // True if the object describes a bookmark folder.
|
| - public String url; // URL of the bookmark. Required for non-folders.
|
| - public String title; // Title of the bookmark.
|
| - public Long created; // Creation date (timestamp) of the bookmark. Optional.
|
| - public Long lastVisit; // Date (timestamp) of the last visit. Optional.
|
| - public Long visits; // Number of visits to the page. Optional.
|
| - public byte[] favicon; // Favicon of the bookmark. Optional.
|
| -
|
| - // For auxiliary use while importing. Not to be set by the bookmark extractors.
|
| - public long nativeId;
|
| - public Bookmark parent;
|
| - public ArrayList<Bookmark> entries = new ArrayList<Bookmark>();
|
| - public boolean processed;
|
| - }
|
| -
|
| - /** Closable iterator for available bookmarks. */
|
| - public interface BookmarkIterator extends Iterator<Bookmark> {
|
| - public void close();
|
| - }
|
| -
|
| - /**
|
| - * Returns an array of iterators to the available bookmarks.
|
| - * The first one is tried and in case of complete importing failure the second one is then used
|
| - * and so on until the array is exhausted. Note that no new bookmarks is not a failure.
|
| - *
|
| - * Called by an async task.
|
| - */
|
| - protected abstract BookmarkIterator[] availableBookmarks();
|
| -
|
| - /** Imported bookmark id reserved for the root folder. */
|
| - static final long ROOT_FOLDER_ID = 0;
|
| -
|
| - // Auxiliary query constants.
|
| - private static final Integer VALUE_IS_BOOKMARK = 1;
|
| - private static final String SELECT_IS_BOOKMARK = Browser.BookmarkColumns.BOOKMARK + "="
|
| - + VALUE_IS_BOOKMARK.toString();
|
| - private static final String HAS_URL = Browser.BookmarkColumns.URL + "=?";
|
| - private static final String[] EXISTS_PROJECTION = new String[]{ BookmarkColumns.URL };
|
| -
|
| - protected final Context mContext;
|
| -
|
| - private ImportBookmarksTask mTask;
|
| -
|
| - protected BookmarkImporter(Context context) {
|
| - mContext = context;
|
| - }
|
| -
|
| - /** Asynchronously import bookmarks from another browser */
|
| - public void importBookmarks(OnBookmarksImportedListener listener) {
|
| - mTask = new ImportBookmarksTask(listener);
|
| - mTask.execute();
|
| - }
|
| -
|
| - public void cancel() {
|
| - mTask.cancel(true);
|
| - }
|
| -
|
| - /**
|
| - * Handles loading Android Browser bookmarks in a background thread.
|
| - */
|
| - private class ImportBookmarksTask extends AsyncTask<Void, Void, ImportResults> {
|
| - private final OnBookmarksImportedListener mBookmarksImportedListener;
|
| -
|
| - ImportBookmarksTask(OnBookmarksImportedListener listener) {
|
| - mBookmarksImportedListener = listener;
|
| - }
|
| -
|
| - @Override
|
| - protected ImportResults doInBackground(Void... params) {
|
| - BookmarkIterator[] iterators = null;
|
| - try {
|
| - iterators = availableBookmarks();
|
| - } catch (Exception e) {
|
| - Log.w(TAG, "Unexpected exception while requesting available bookmarks: "
|
| - + e.getMessage());
|
| - return null;
|
| - }
|
| -
|
| - if (iterators == null) {
|
| - Log.e(TAG, "No bookmark iterators found.");
|
| - return null;
|
| - }
|
| -
|
| - for (BookmarkIterator iterator : iterators) {
|
| - ImportResults results = importFromIterator(iterator);
|
| - if (results != null) return results;
|
| - }
|
| -
|
| - return null;
|
| - }
|
| -
|
| - @Override
|
| - protected void onPostExecute(ImportResults results) {
|
| - if (mBookmarksImportedListener != null) {
|
| - mBookmarksImportedListener.onBookmarksImported(results);
|
| - }
|
| - }
|
| -
|
| - private ImportResults importFromIterator(BookmarkIterator bookmarkIterator) {
|
| - try {
|
| - if (bookmarkIterator == null) return null;
|
| -
|
| - // Get a snapshot of the bookmarks.
|
| - LinkedHashMap<Long, Bookmark> idMap = new LinkedHashMap<Long, Bookmark>();
|
| - HashSet<String> urlSet = new HashSet<String>();
|
| -
|
| - // The root folder is used for hierarchy reconstruction purposes only.
|
| - // Bookmarks are directly imported into the Mobile Bookmarks folder.
|
| - Bookmark rootFolder = createRootFolderBookmark();
|
| - idMap.put(ROOT_FOLDER_ID, rootFolder);
|
| -
|
| - int failedImports = 0;
|
| - while (bookmarkIterator.hasNext()) {
|
| - Bookmark bookmark = bookmarkIterator.next();
|
| - if (bookmark == null) {
|
| - ++failedImports;
|
| - continue;
|
| - }
|
| -
|
| - // Check for duplicate ids.
|
| - if (idMap.containsKey(bookmark.id)) {
|
| - Log.e(TAG, "Duplicate bookmark id: " + bookmark.id
|
| - + ". Dropping bookmark.");
|
| - ++failedImports;
|
| - continue;
|
| - }
|
| -
|
| - // Check for duplicate URLs.
|
| - if (!bookmark.isFolder && urlSet.contains(bookmark.url)) {
|
| - Log.i(TAG, "More than one bookmark pointing to " + bookmark.url
|
| - + ". Keeping only the first one for consistency with Chromium.");
|
| - continue;
|
| - }
|
| -
|
| - // Reject bookmarks that already exist in the native model.
|
| - if (alreadyExists(bookmark)) continue;
|
| -
|
| - idMap.put(bookmark.id, bookmark);
|
| - urlSet.add(bookmark.url);
|
| - }
|
| - bookmarkIterator.close();
|
| -
|
| - // Abort if no new bookmarks to import.
|
| - ImportResults results = new ImportResults();
|
| - results.rootFolderId = rootFolder.nativeId;
|
| - results.newBookmarks = idMap.size() + failedImports - 1;
|
| - if (results.newBookmarks == 0) return results;
|
| -
|
| - // Check if all imports failed.
|
| - if (idMap.size() == 1 && failedImports > 0) return null;
|
| -
|
| - // Recreate the folder hierarchy and import it.
|
| - recreateFolderHierarchy(idMap);
|
| - importBookmarkHierarchy(rootFolder, results);
|
| -
|
| - return results;
|
| - } catch (Exception e) {
|
| - Log.w(TAG, "Unexpected exception while importing bookmarks: " + e.getMessage());
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - private ContentValues getBookmarkValues(Bookmark bookmark) {
|
| - ContentValues values = new ContentValues();
|
| - values.put(BookmarkColumns.BOOKMARK, VALUE_IS_BOOKMARK);
|
| - values.put(BookmarkColumns.URL, bookmark.url);
|
| - values.put(BookmarkColumns.TITLE, bookmark.title);
|
| - values.put(ChromeBrowserProvider.BOOKMARK_PARENT_ID_PARAM, bookmark.parent.nativeId);
|
| - if (bookmark.created != null) values.put(BookmarkColumns.CREATED, bookmark.created);
|
| - if (bookmark.lastVisit != null) values.put(BookmarkColumns.DATE, bookmark.lastVisit);
|
| - if (bookmark.visits != null) {
|
| - // TODO(michaelbai) http://crbug.com/149376, http://b/6362473
|
| - // See android_provider_backend.cc IsHistoryAndBookmarkRowValid().
|
| - if (bookmark.created != null && bookmark.lastVisit != null
|
| - && bookmark.visits.longValue() > 2
|
| - && bookmark.lastVisit.longValue() - bookmark.created.longValue()
|
| - > bookmark.visits.longValue()) {
|
| - values.put(BookmarkColumns.VISITS, bookmark.visits);
|
| - }
|
| - }
|
| - if (bookmark.favicon != null) values.put(BookmarkColumns.FAVICON, bookmark.favicon);
|
| - return values;
|
| - }
|
| -
|
| - private boolean alreadyExists(Bookmark bookmark) {
|
| - // Folders are re-used if they already exist. No need to filter them out.
|
| - if (bookmark.isFolder) return false;
|
| -
|
| - Cursor cursor = mContext.getContentResolver().query(
|
| - ChromeBrowserProvider.getBookmarksApiUri(mContext), EXISTS_PROJECTION,
|
| - SELECT_IS_BOOKMARK + " AND " + HAS_URL, new String[]{ bookmark.url }, null);
|
| - if (cursor != null) {
|
| - boolean exists = cursor.getCount() > 0;
|
| - cursor.close();
|
| - return exists;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - private void recreateFolderHierarchy(LinkedHashMap<Long, Bookmark> idMap) {
|
| - for (Bookmark bookmark : idMap.values()) {
|
| - if (bookmark.id == ROOT_FOLDER_ID) continue;
|
| -
|
| - // Look for invalid parent ids and self-cycles.
|
| - if (!idMap.containsKey(bookmark.parentId) || bookmark.parentId == bookmark.id) {
|
| - bookmark.parent = idMap.get(ROOT_FOLDER_ID);
|
| - bookmark.parent.entries.add(bookmark);
|
| - continue;
|
| - }
|
| -
|
| - bookmark.parent = idMap.get(bookmark.parentId);
|
| - bookmark.parent.entries.add(bookmark);
|
| - }
|
| - }
|
| -
|
| - private Bookmark createRootFolderBookmark() {
|
| - Bookmark root = new Bookmark();
|
| - root.id = ROOT_FOLDER_ID;
|
| - root.nativeId = ChromeBrowserProviderClient.getMobileBookmarksFolderId(mContext);
|
| - root.parentId = ROOT_FOLDER_ID;
|
| - root.parent = root;
|
| - root.isFolder = true;
|
| - return root;
|
| - }
|
| -
|
| - private void importBookmarkHierarchy(Bookmark bookmark, ImportResults results) {
|
| - // Avoid cycles in the hierarchy that could lead to infinite loops.
|
| - if (bookmark.processed) return;
|
| - bookmark.processed = true;
|
| -
|
| - if (bookmark.isFolder) {
|
| - if (bookmark.id != ROOT_FOLDER_ID) {
|
| - bookmark.nativeId = ChromeBrowserProviderClient.createBookmarksFolderOnce(
|
| - mContext, bookmark.title, bookmark.parent.nativeId);
|
| - ++results.numImported;
|
| - }
|
| -
|
| - if (bookmark.nativeId == ChromeBrowserProviderClient.INVALID_BOOKMARK_ID
|
| - && bookmark.id != ROOT_FOLDER_ID) {
|
| - Log.e(TAG, "Error creating the folder '" + bookmark.title
|
| - + "'. Skipping entries.");
|
| - return;
|
| - }
|
| -
|
| - for (Bookmark entry : bookmark.entries) {
|
| - if (entry.parent != bookmark) {
|
| - Log.w(TAG, "Hierarchy error in bookmark '" + bookmark.title
|
| - + "'. Skipping.");
|
| - continue;
|
| - }
|
| - importBookmarkHierarchy(entry, results);
|
| - }
|
| - } else {
|
| - sanitizeBookmarkDates(bookmark);
|
| - ContentValues values = getBookmarkValues(bookmark);
|
| - try {
|
| - // Check if the URL already exists in the database.
|
| - String[] urlArgs = new String[]{ bookmark.url };
|
| - Uri bookmarksApiUri = ChromeBrowserProvider.getBookmarksApiUri(mContext);
|
| - Cursor history = mContext.getContentResolver().query(
|
| - bookmarksApiUri, null, HAS_URL, urlArgs, null);
|
| - boolean alreadyExists = history != null && history.getCount() > 0;
|
| - if (history != null) history.close();
|
| -
|
| - if (alreadyExists) {
|
| - // If so, update the existing information.
|
| - if (mContext.getContentResolver().update(
|
| - bookmarksApiUri, values, HAS_URL, urlArgs) == 0) {
|
| - throw new IllegalArgumentException(
|
| - "Couldn't update the existing history information");
|
| - }
|
| - } else {
|
| - // Otherwise insert the new information.
|
| - if (mContext.getContentResolver().insert(
|
| - bookmarksApiUri, values) == null) {
|
| - throw new IllegalArgumentException(
|
| - "Couldn't insert the bookmark");
|
| - }
|
| - }
|
| - ++results.numImported;
|
| - } catch (IllegalArgumentException e) {
|
| - Log.w(TAG, "Error inserting bookmark " + bookmark.title + ": "
|
| - + e.getMessage());
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Sanitize timestamp inputs as the provider backend might reject some of the bookmarks
|
| - // if the values are inconsistent.
|
| - private void sanitizeBookmarkDates(Bookmark bookmark) {
|
| - final long now = System.currentTimeMillis();
|
| - if (bookmark.created != null && bookmark.created.longValue() > now) {
|
| - bookmark.created = Long.valueOf(now);
|
| - }
|
| -
|
| - if (bookmark.lastVisit != null && bookmark.lastVisit.longValue() > now) {
|
| - bookmark.lastVisit = Long.valueOf(now);
|
| - }
|
| -
|
| - if (bookmark.created != null && bookmark.lastVisit != null
|
| - && bookmark.created.longValue() > bookmark.lastVisit.longValue()) {
|
| - bookmark.created = bookmark.lastVisit;
|
| - }
|
| -
|
| - // The provider backend assumes one visit per timestamp and actually checks this.
|
| - if (bookmark.lastVisit != null && bookmark.created != null && bookmark.visits != null) {
|
| - long maxVisits = bookmark.lastVisit.longValue() - bookmark.created.longValue() + 1;
|
| - if (bookmark.visits.longValue() > maxVisits) {
|
| - bookmark.visits = Long.valueOf(maxVisits);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -}
|
|
|