// 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.partnerbookmarks;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import java.util.NoSuchElementException;
/**
* Imports bookmarks from partner content provider using the private provider API.
*/
public class PartnerBookmarksProviderIterator implements PartnerBookmarksReader.BookmarkIterator {
private static final String TAG = "PartnerBookmarksProviderIterator";
private static final String PROVIDER_AUTHORITY = "com.android.partnerbookmarks";
private static final Uri CONTENT_URI = new Uri.Builder().scheme("content")
.authority(PROVIDER_AUTHORITY).build();
// Private bookmarks structure.
private static final String BOOKMARKS_PATH = "bookmarks";
private static final Uri BOOKMARKS_CONTENT_URI =
CONTENT_URI.buildUpon().appendPath(BOOKMARKS_PATH).build();
private static final String BOOKMARKS_COLUMN_ID = "_id";
private static final String BOOKMARKS_COLUMN_URL = "url";
private static final String BOOKMARKS_COLUMN_TITLE = "title";
private static final String BOOKMARKS_COLUMN_TYPE = "type";
private static final String BOOKMARKS_COLUMN_PARENT = "parent";
private static final String BOOKMARKS_COLUMN_FAVICON = "favicon";
private static final String BOOKMARKS_COLUMN_TOUCHICON = "touchicon";
private static final int BOOKMARK_TYPE_FOLDER = 2;
// Bookmark id of the main container folder.
private static final long BOOKMARK_CONTAINER_FOLDER_ID = 0;
private static final String BOOKMARKS_SORT_ORDER = BOOKMARKS_COLUMN_TYPE
+ " DESC, " + BOOKMARKS_COLUMN_ID + " ASC";
private static final String[] BOOKMARKS_PROJECTION = {
BOOKMARKS_COLUMN_ID,
BOOKMARKS_COLUMN_URL,
BOOKMARKS_COLUMN_TITLE,
BOOKMARKS_COLUMN_TYPE,
BOOKMARKS_COLUMN_PARENT,
BOOKMARKS_COLUMN_FAVICON,
BOOKMARKS_COLUMN_TOUCHICON
};
private final Cursor mCursor;
/**
* Creates the bookmarks iterator if possible.
* @param contentResolver The content resolver to use.
* @return Iterator over bookmarks or null.
*/
public static PartnerBookmarksProviderIterator createIfAvailable(
ContentResolver contentResolver) {
Cursor cursor = contentResolver.query(BOOKMARKS_CONTENT_URI,
BOOKMARKS_PROJECTION, null, null, BOOKMARKS_SORT_ORDER);
if (cursor == null) return null;
return new PartnerBookmarksProviderIterator(cursor);
}
private PartnerBookmarksProviderIterator(Cursor cursor) {
mCursor = cursor;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void close() {
if (mCursor == null) throw new IllegalStateException();
mCursor.close();
}
@Override
public boolean hasNext() {
if (mCursor == null) throw new IllegalStateException();
// While the combination of !isLast() && !isAfterLast() should have been
// sufficient, Android Cursor API doesn't specify isAfterLast's behavior
// in the case of an empty cursor; hence, we fall back to
// getCount() > 0 check.
return mCursor.getCount() > 0 && !mCursor.isLast() && !mCursor.isAfterLast();
}
@Override
public PartnerBookmarksReader.Bookmark next() {
if (mCursor == null) throw new IllegalStateException();
if (!mCursor.moveToNext()) throw new NoSuchElementException();
PartnerBookmarksReader.Bookmark bookmark = new PartnerBookmarksReader.Bookmark();
try {
bookmark.mId = mCursor.getLong(mCursor.getColumnIndexOrThrow(BOOKMARKS_COLUMN_ID));
// The container folder should not be among the results.
if (bookmark.mId == BOOKMARK_CONTAINER_FOLDER_ID) {
Log.i(TAG, "Dropping the bookmark: reserved _id was used");
return null;
}
bookmark.mParentId =
mCursor.getLong(mCursor.getColumnIndexOrThrow(BOOKMARKS_COLUMN_PARENT));
if (bookmark.mParentId == BOOKMARK_CONTAINER_FOLDER_ID) {
bookmark.mParentId = PartnerBookmarksReader.ROOT_FOLDER_ID;
}
bookmark.mIsFolder =
mCursor.getInt(mCursor.getColumnIndexOrThrow(BOOKMARKS_COLUMN_TYPE))
== BOOKMARK_TYPE_FOLDER;
bookmark.mUrl = mCursor.getString(mCursor.getColumnIndexOrThrow(BOOKMARKS_COLUMN_URL));
bookmark.mTitle =
mCursor.getString(mCursor.getColumnIndexOrThrow(BOOKMARKS_COLUMN_TITLE));
bookmark.mFavicon =
mCursor.getBlob(mCursor.getColumnIndexOrThrow(BOOKMARKS_COLUMN_FAVICON));
bookmark.mTouchicon =
mCursor.getBlob(mCursor.getColumnIndexOrThrow(BOOKMARKS_COLUMN_TOUCHICON));
} catch (IllegalArgumentException e) {
Log.i(TAG, "Dropping the bookmark: " + e.getMessage());
return null;
}
if ((!bookmark.mIsFolder && bookmark.mUrl == null) || bookmark.mTitle == null) {
Log.i(TAG, "Dropping the bookmark: no title, or no url on a non-foler");
return null;
}
return bookmark;
}
}