summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/partnerbookmarks/PartnerBookmarksProvider.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/providers/partnerbookmarks/PartnerBookmarksProvider.java')
-rw-r--r--src/com/android/providers/partnerbookmarks/PartnerBookmarksProvider.java450
1 files changed, 450 insertions, 0 deletions
diff --git a/src/com/android/providers/partnerbookmarks/PartnerBookmarksProvider.java b/src/com/android/providers/partnerbookmarks/PartnerBookmarksProvider.java
new file mode 100644
index 0000000..2ad371e
--- /dev/null
+++ b/src/com/android/providers/partnerbookmarks/PartnerBookmarksProvider.java
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.partnerbookmarks;
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.content.UriMatcher;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.MatrixCursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Default partner bookmarks provider implementation of {@link PartnerBookmarksContract} API.
+ * It reads the flat list of bookmarks and the name of the root partner
+ * bookmarks folder using getResources() API.
+ *
+ * Sample resources structure:
+ * res/
+ * values/
+ * strings.xml
+ * string name="bookmarks_folder_name"
+ * string-array name="bookmarks"
+ * item TITLE1
+ * item URL1
+ * item TITLE2
+ * item URL2...
+ * bookmarks_icons.xml
+ * array name="bookmark_preloads"
+ * item @raw/favicon1
+ * item @raw/touchicon1
+ * item @raw/favicon2
+ * item @raw/touchicon2
+ * ...
+ */
+public class PartnerBookmarksProvider extends ContentProvider {
+ private static final String TAG = "PartnerBookmarksProvider";
+
+ // URI matcher
+ private static final int URI_MATCH_BOOKMARKS = 1000;
+ private static final int URI_MATCH_BOOKMARKS_ID = 1001;
+ private static final int URI_MATCH_BOOKMARKS_FOLDER = 1002;
+ private static final int URI_MATCH_BOOKMARKS_FOLDER_ID = 1003;
+ private static final int URI_MATCH_BOOKMARKS_PARTNER_BOOKMARKS_FOLDER_ID = 1004;
+
+ private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
+ private static final Map<String, String> BOOKMARKS_PROJECTION_MAP
+ = new HashMap<String, String>();
+
+ // Default sort order for unsync'd bookmarks
+ private static final String DEFAULT_BOOKMARKS_SORT_ORDER =
+ PartnerBookmarksContract.Bookmarks.ID + " DESC, "
+ + PartnerBookmarksContract.Bookmarks.ID + " ASC";
+
+ // Initial bookmark id when for getResources() importing
+ // Make sure to fix tests if you are changing this
+ private static final long FIXED_ID_PARTNER_BOOKMARKS_ROOT =
+ PartnerBookmarksContract.Bookmarks.BOOKMARK_PARENT_ROOT_ID + 1;
+
+ // DB table name
+ private static final String TABLE_BOOKMARKS = "bookmarks";
+
+ static {
+ final UriMatcher matcher = URI_MATCHER;
+ final String authority = PartnerBookmarksContract.AUTHORITY;
+ matcher.addURI(authority, "bookmarks", URI_MATCH_BOOKMARKS);
+ matcher.addURI(authority, "bookmarks/#", URI_MATCH_BOOKMARKS_ID);
+ matcher.addURI(authority, "bookmarks/folder", URI_MATCH_BOOKMARKS_FOLDER);
+ matcher.addURI(authority, "bookmarks/folder/#", URI_MATCH_BOOKMARKS_FOLDER_ID);
+ matcher.addURI(authority, "bookmarks/folder/id",
+ URI_MATCH_BOOKMARKS_PARTNER_BOOKMARKS_FOLDER_ID);
+ // Projection maps
+ Map<String, String> map = BOOKMARKS_PROJECTION_MAP;
+ map.put(PartnerBookmarksContract.Bookmarks.ID,
+ PartnerBookmarksContract.Bookmarks.ID);
+ map.put(PartnerBookmarksContract.Bookmarks.TITLE,
+ PartnerBookmarksContract.Bookmarks.TITLE);
+ map.put(PartnerBookmarksContract.Bookmarks.URL,
+ PartnerBookmarksContract.Bookmarks.URL);
+ map.put(PartnerBookmarksContract.Bookmarks.TYPE,
+ PartnerBookmarksContract.Bookmarks.TYPE);
+ map.put(PartnerBookmarksContract.Bookmarks.PARENT,
+ PartnerBookmarksContract.Bookmarks.PARENT);
+ map.put(PartnerBookmarksContract.Bookmarks.FAVICON,
+ PartnerBookmarksContract.Bookmarks.FAVICON);
+ map.put(PartnerBookmarksContract.Bookmarks.TOUCHICON,
+ PartnerBookmarksContract.Bookmarks.TOUCHICON);
+ }
+
+ private final class DatabaseHelper extends SQLiteOpenHelper {
+ private static final String DATABASE_FILENAME = "partnerBookmarks.db";
+ private static final int DATABASE_VERSION = 1;
+ private static final String PREFERENCES_FILENAME = "pbppref";
+ private static final String ACTIVE_CONFIGURATION_PREFNAME = "config";
+ private final SharedPreferences sharedPreferences;
+
+ public DatabaseHelper(Context context) {
+ super(context, DATABASE_FILENAME, null, DATABASE_VERSION);
+ sharedPreferences = context.getSharedPreferences(
+ PREFERENCES_FILENAME, Context.MODE_PRIVATE);
+ }
+
+ private String getConfigSignature(Configuration config) {
+ return "mmc=" + Integer.toString(config.mcc)
+ + "-mnc=" + Integer.toString(config.mnc)
+ + "-loc=" + config.locale.toString();
+ }
+
+ public synchronized void prepareForConfiguration(Configuration config) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ String newSignature = getConfigSignature(config);
+ String activeSignature =
+ sharedPreferences.getString(ACTIVE_CONFIGURATION_PREFNAME, null);
+ if (activeSignature == null || !activeSignature.equals(newSignature)) {
+ db.delete(TABLE_BOOKMARKS, null, null);
+ if (!createDefaultBookmarks(db)) {
+ // Failure to read/insert bookmarks should be treated as "no bookmarks"
+ db.delete(TABLE_BOOKMARKS, null, null);
+ }
+ }
+ }
+
+ private void setActiveConfiguration(Configuration config) {
+ Editor editor = sharedPreferences.edit();
+ editor.putString(ACTIVE_CONFIGURATION_PREFNAME, getConfigSignature(config));
+ editor.apply();
+ }
+
+ private void createTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_BOOKMARKS + "(" +
+ PartnerBookmarksContract.Bookmarks.ID +
+ " INTEGER NOT NULL DEFAULT 0," +
+ PartnerBookmarksContract.Bookmarks.TITLE +
+ " TEXT," +
+ PartnerBookmarksContract.Bookmarks.URL +
+ " TEXT," +
+ PartnerBookmarksContract.Bookmarks.TYPE +
+ " INTEGER NOT NULL DEFAULT 0," +
+ PartnerBookmarksContract.Bookmarks.PARENT +
+ " INTEGER," +
+ PartnerBookmarksContract.Bookmarks.FAVICON +
+ " BLOB," +
+ PartnerBookmarksContract.Bookmarks.TOUCHICON +
+ " BLOB" + ");");
+ }
+
+ private void dropTable(SQLiteDatabase db) {
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_BOOKMARKS);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ synchronized (this) {
+ createTable(db);
+ if (!createDefaultBookmarks(db)) {
+ // Failure to read/insert bookmarks should be treated as "no bookmarks"
+ dropTable(db);
+ createTable(db);
+ }
+ }
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ dropTable(db);
+ onCreate(db);
+ }
+
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ dropTable(db);
+ onCreate(db);
+ }
+
+ private boolean createDefaultBookmarks(SQLiteDatabase db) {
+ Resources res = getContext().getResources();
+ try {
+ CharSequence bookmarksFolderName = res.getText(R.string.bookmarks_folder_name);
+ final CharSequence[] bookmarks = res.getTextArray(R.array.bookmarks);
+ if (bookmarks.length >= 1) {
+ if (bookmarksFolderName.length() < 1) {
+ Log.i(TAG, "bookmarks_folder_name was not specified; bailing out");
+ return false;
+ }
+ if (!addRootFolder(db,
+ FIXED_ID_PARTNER_BOOKMARKS_ROOT, bookmarksFolderName.toString())) {
+ Log.i(TAG, "failed to insert root folder; bailing out");
+ return false;
+ }
+ if (!addDefaultBookmarks(db,
+ FIXED_ID_PARTNER_BOOKMARKS_ROOT, FIXED_ID_PARTNER_BOOKMARKS_ROOT + 1)) {
+ Log.i(TAG, "failed to insert bookmarks; bailing out");
+ return false;
+ }
+ }
+ setActiveConfiguration(res.getConfiguration());
+ } catch (android.content.res.Resources.NotFoundException e) {
+ Log.i(TAG, "failed to fetch resources; bailing out");
+ return false;
+ }
+ return true;
+ }
+
+ private boolean addRootFolder(SQLiteDatabase db, long id, String bookmarksFolderName) {
+ ContentValues values = new ContentValues();
+ values.put(PartnerBookmarksContract.Bookmarks.ID, id);
+ values.put(PartnerBookmarksContract.Bookmarks.TITLE,
+ bookmarksFolderName);
+ values.put(PartnerBookmarksContract.Bookmarks.PARENT,
+ PartnerBookmarksContract.Bookmarks.BOOKMARK_PARENT_ROOT_ID);
+ values.put(PartnerBookmarksContract.Bookmarks.TYPE,
+ PartnerBookmarksContract.Bookmarks.BOOKMARK_TYPE_FOLDER);
+ return db.insertOrThrow(TABLE_BOOKMARKS, null, values) != -1;
+ }
+
+ private boolean addDefaultBookmarks(SQLiteDatabase db, long parentId, long firstBookmarkId) {
+ long bookmarkId = firstBookmarkId;
+ Resources res = getContext().getResources();
+ final CharSequence[] bookmarks = res.getTextArray(R.array.bookmarks);
+ int size = bookmarks.length;
+ TypedArray preloads = res.obtainTypedArray(R.array.bookmark_preloads);
+ DatabaseUtils.InsertHelper insertHelper = null;
+ try {
+ insertHelper = new DatabaseUtils.InsertHelper(db, TABLE_BOOKMARKS);
+ final int idColumn = insertHelper.getColumnIndex(
+ PartnerBookmarksContract.Bookmarks.ID);
+ final int titleColumn = insertHelper.getColumnIndex(
+ PartnerBookmarksContract.Bookmarks.TITLE);
+ final int urlColumn = insertHelper.getColumnIndex(
+ PartnerBookmarksContract.Bookmarks.URL);
+ final int typeColumn = insertHelper.getColumnIndex(
+ PartnerBookmarksContract.Bookmarks.TYPE);
+ final int parentColumn = insertHelper.getColumnIndex(
+ PartnerBookmarksContract.Bookmarks.PARENT);
+ final int faviconColumn = insertHelper.getColumnIndex(
+ PartnerBookmarksContract.Bookmarks.FAVICON);
+ final int touchiconColumn = insertHelper.getColumnIndex(
+ PartnerBookmarksContract.Bookmarks.TOUCHICON);
+
+ for (int i = 0; i + 1 < size; i = i + 2) {
+ CharSequence bookmarkDestination = bookmarks[i + 1];
+
+ String bookmarkTitle = bookmarks[i].toString();
+ String bookmarkUrl = bookmarkDestination.toString();
+ byte[] favicon = null;
+ if (i < preloads.length()) {
+ int faviconId = preloads.getResourceId(i, 0);
+ try {
+ favicon = readRaw(res, faviconId);
+ } catch (IOException e) {
+ Log.i(TAG, "Failed to read favicon for " + bookmarkTitle, e);
+ }
+ }
+ byte[] touchicon = null;
+ if (i + 1 < preloads.length()) {
+ int touchiconId = preloads.getResourceId(i + 1, 0);
+ try {
+ touchicon = readRaw(res, touchiconId);
+ } catch (IOException e) {
+ Log.i(TAG, "Failed to read touchicon for " + bookmarkTitle, e);
+ }
+ }
+ insertHelper.prepareForInsert();
+ insertHelper.bind(idColumn, bookmarkId);
+ insertHelper.bind(titleColumn, bookmarkTitle);
+ insertHelper.bind(urlColumn, bookmarkUrl);
+ insertHelper.bind(typeColumn,
+ PartnerBookmarksContract.Bookmarks.BOOKMARK_TYPE_BOOKMARK);
+ insertHelper.bind(parentColumn, parentId);
+ if (favicon != null) {
+ insertHelper.bind(faviconColumn, favicon);
+ }
+ if (touchicon != null) {
+ insertHelper.bind(touchiconColumn, touchicon);
+ }
+ bookmarkId++;
+ if (insertHelper.execute() == -1) {
+ Log.i(TAG, "Failed to insert bookmark " + bookmarkTitle);
+ return false;
+ }
+ }
+ } finally {
+ preloads.recycle();
+ insertHelper.close();
+ }
+ return true;
+ }
+
+ private byte[] readRaw(Resources res, int id) throws IOException {
+ if (id == 0) return null;
+ InputStream is = res.openRawResource(id);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try {
+ byte[] buf = new byte[4096];
+ int read;
+ while ((read = is.read(buf)) > 0) {
+ bos.write(buf, 0, read);
+ }
+ bos.flush();
+ return bos.toByteArray();
+ } finally {
+ is.close();
+ bos.close();
+ }
+ }
+ }
+
+ private DatabaseHelper mOpenHelper;
+
+ @Override
+ public boolean onCreate() {
+ mOpenHelper = new DatabaseHelper(getContext());
+ return true;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ mOpenHelper.prepareForConfiguration(getContext().getResources().getConfiguration());
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder) {
+ final int match = URI_MATCHER.match(uri);
+ mOpenHelper.prepareForConfiguration(getContext().getResources().getConfiguration());
+ final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+ String limit = uri.getQueryParameter(PartnerBookmarksContract.PARAM_LIMIT);
+ String groupBy = uri.getQueryParameter(PartnerBookmarksContract.PARAM_GROUP_BY);
+ switch (match) {
+ case URI_MATCH_BOOKMARKS_FOLDER_ID:
+ case URI_MATCH_BOOKMARKS_ID:
+ case URI_MATCH_BOOKMARKS: {
+ if (match == URI_MATCH_BOOKMARKS_ID) {
+ // Tack on the ID of the specific bookmark requested
+ selection = DatabaseUtils.concatenateWhere(selection,
+ TABLE_BOOKMARKS + "." +
+ PartnerBookmarksContract.Bookmarks.ID + "=?");
+ selectionArgs = DatabaseUtils.appendSelectionArgs(selectionArgs,
+ new String[] { Long.toString(ContentUris.parseId(uri)) });
+ } else if (match == URI_MATCH_BOOKMARKS_FOLDER_ID) {
+ // Tack on the ID of the specific folder requested
+ selection = DatabaseUtils.concatenateWhere(selection,
+ TABLE_BOOKMARKS + "." +
+ PartnerBookmarksContract.Bookmarks.PARENT + "=?");
+ selectionArgs = DatabaseUtils.appendSelectionArgs(selectionArgs,
+ new String[] { Long.toString(ContentUris.parseId(uri)) });
+ }
+ // Set a default sort order if one isn't specified
+ if (TextUtils.isEmpty(sortOrder)) {
+ sortOrder = DEFAULT_BOOKMARKS_SORT_ORDER;
+ }
+ qb.setProjectionMap(BOOKMARKS_PROJECTION_MAP);
+ qb.setTables(TABLE_BOOKMARKS);
+ break;
+ }
+
+ case URI_MATCH_BOOKMARKS_FOLDER: {
+ qb.setTables(TABLE_BOOKMARKS);
+ String[] args;
+ String query;
+ // Set a default sort order if one isn't specified
+ if (TextUtils.isEmpty(sortOrder)) {
+ sortOrder = DEFAULT_BOOKMARKS_SORT_ORDER;
+ }
+ qb.setProjectionMap(BOOKMARKS_PROJECTION_MAP);
+ String where = PartnerBookmarksContract.Bookmarks.PARENT + "=?";
+ where = DatabaseUtils.concatenateWhere(where, selection);
+ args = new String[] { Long.toString(FIXED_ID_PARTNER_BOOKMARKS_ROOT) };
+ if (selectionArgs != null) {
+ args = DatabaseUtils.appendSelectionArgs(args, selectionArgs);
+ }
+ query = qb.buildQuery(projection, where, null, null, sortOrder, null);
+ Cursor cursor = db.rawQuery(query, args);
+ return cursor;
+ }
+
+ case URI_MATCH_BOOKMARKS_PARTNER_BOOKMARKS_FOLDER_ID: {
+ MatrixCursor c = new MatrixCursor(
+ new String[] {PartnerBookmarksContract.Bookmarks.ID});
+ c.newRow().add(FIXED_ID_PARTNER_BOOKMARKS_ROOT);
+ return c;
+ }
+
+ default: {
+ throw new UnsupportedOperationException("Unknown URL " + uri.toString());
+ }
+ }
+
+ return qb.query(db, projection, selection, selectionArgs, groupBy, null, sortOrder, limit);
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ final int match = URI_MATCHER.match(uri);
+ if (match == UriMatcher.NO_MATCH) return null;
+ return PartnerBookmarksContract.Bookmarks.CONTENT_ITEM_TYPE;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+}