/* * Copyright (C) 2007 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.common.content; import android.accounts.Account; import android.content.ContentValues; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.provider.SyncStateContract; /** * Extends the schema of a ContentProvider to include the _sync_state table * and implements query/insert/update/delete to access that table using the * authority "syncstate". This can be used to store the sync state for a * set of accounts. */ public class SyncStateContentProviderHelper { private static final String SELECT_BY_ACCOUNT = SyncStateContract.Columns.ACCOUNT_NAME + "=? AND " + SyncStateContract.Columns.ACCOUNT_TYPE + "=?"; private static final String SYNC_STATE_TABLE = "_sync_state"; private static final String SYNC_STATE_META_TABLE = "_sync_state_metadata"; private static final String SYNC_STATE_META_VERSION_COLUMN = "version"; private static long DB_VERSION = 1; private static final String[] ACCOUNT_PROJECTION = new String[]{SyncStateContract.Columns.ACCOUNT_NAME, SyncStateContract.Columns.ACCOUNT_TYPE}; public static final String PATH = "syncstate"; private static final String QUERY_COUNT_SYNC_STATE_ROWS = "SELECT count(*)" + " FROM " + SYNC_STATE_TABLE + " WHERE " + SyncStateContract.Columns._ID + "=?"; public void createDatabase(SQLiteDatabase db) { db.execSQL("DROP TABLE IF EXISTS " + SYNC_STATE_TABLE); db.execSQL("CREATE TABLE " + SYNC_STATE_TABLE + " (" + SyncStateContract.Columns._ID + " INTEGER PRIMARY KEY," + SyncStateContract.Columns.ACCOUNT_NAME + " TEXT NOT NULL," + SyncStateContract.Columns.ACCOUNT_TYPE + " TEXT NOT NULL," + SyncStateContract.Columns.DATA + " TEXT," + "UNIQUE(" + SyncStateContract.Columns.ACCOUNT_NAME + ", " + SyncStateContract.Columns.ACCOUNT_TYPE + "));"); db.execSQL("DROP TABLE IF EXISTS " + SYNC_STATE_META_TABLE); db.execSQL("CREATE TABLE " + SYNC_STATE_META_TABLE + " (" + SYNC_STATE_META_VERSION_COLUMN + " INTEGER);"); ContentValues values = new ContentValues(); values.put(SYNC_STATE_META_VERSION_COLUMN, DB_VERSION); db.insert(SYNC_STATE_META_TABLE, SYNC_STATE_META_VERSION_COLUMN, values); } public void onDatabaseOpened(SQLiteDatabase db) { long version = DatabaseUtils.longForQuery(db, "SELECT " + SYNC_STATE_META_VERSION_COLUMN + " FROM " + SYNC_STATE_META_TABLE, null); if (version != DB_VERSION) { createDatabase(db); } } public Cursor query(SQLiteDatabase db, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return db.query(SYNC_STATE_TABLE, projection, selection, selectionArgs, null, null, sortOrder); } public long insert(SQLiteDatabase db, ContentValues values) { return db.replace(SYNC_STATE_TABLE, SyncStateContract.Columns.ACCOUNT_NAME, values); } public int delete(SQLiteDatabase db, String userWhere, String[] whereArgs) { return db.delete(SYNC_STATE_TABLE, userWhere, whereArgs); } public int update(SQLiteDatabase db, ContentValues values, String selection, String[] selectionArgs) { return db.update(SYNC_STATE_TABLE, values, selection, selectionArgs); } public int update(SQLiteDatabase db, long rowId, Object data) { if (DatabaseUtils.longForQuery(db, QUERY_COUNT_SYNC_STATE_ROWS, new String[]{Long.toString(rowId)}) < 1) { return 0; } db.execSQL("UPDATE " + SYNC_STATE_TABLE + " SET " + SyncStateContract.Columns.DATA + "=?" + " WHERE " + SyncStateContract.Columns._ID + "=" + rowId, new Object[]{data}); // assume a row was modified since we know it exists return 1; } public void onAccountsChanged(SQLiteDatabase db, Account[] accounts) { Cursor c = db.query(SYNC_STATE_TABLE, ACCOUNT_PROJECTION, null, null, null, null, null); try { while (c.moveToNext()) { final String accountName = c.getString(0); final String accountType = c.getString(1); Account account = new Account(accountName, accountType); if (!contains(accounts, account)) { db.delete(SYNC_STATE_TABLE, SELECT_BY_ACCOUNT, new String[]{accountName, accountType}); } } } finally { c.close(); } } /** * Checks that value is present as at least one of the elements of the array. * @param array the array to check in * @param value the value to check for * @return true if the value is present in the array */ private static boolean contains(T[] array, T value) { for (T element : array) { if (element == null) { if (value == null) return true; } else { if (value != null && element.equals(value)) return true; } } return false; } }