/* * Copyright (C) 2010 Magnusart <http://www.magnusart.com> * * 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.liato.bankdroid.provider; import com.liato.bankdroid.db.DatabaseHelper; import android.content.ContentProvider; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.preference.PreferenceManager; import java.util.HashMap; import java.util.Map; import timber.log.Timber; /** * <p> * This is the implementation of the BankTransactionsProvider. It provides * access to the transaction data for specific banks. * </p> * * @author Magnus Andersson * @see IBankTransactionsProvider * @since 8 jan 2011 */ public class BankTransactionsProvider extends ContentProvider implements IBankTransactionsProvider { private static final String CONTENT_PROVIDER_ENABLED = "content_provider_enabled"; private static final String CONTENT_PROVIDER_API_KEY = "content_provider_api_key"; private final static int TRANSACTIONS = 0; private final static int BANK_ACCOUNTS = 1; private static final String WILD_CARD = "*"; private static final String BANK_TABLE = "banks"; private static final String ACCOUNT_TABLE = "accounts"; private static final String BANK_ACCOUNT_TABLES = BANK_TABLE + " LEFT JOIN " + ACCOUNT_TABLE + " ON banks." + BANK_ID + " = accounts.bankid"; private static final String TRANSACTIONS_TABLE = "transactions"; private final static UriMatcher URI_MATCHER; private final static Map<String, String> BANK_ACCOUNT_PROJECTION_MAP; private final static Map<String, String> TRANS_PROJECTION_MAP; static { URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); URI_MATCHER.addURI(AUTHORITY, TRANSACTIONS_CAT + "/" + WILD_CARD, TRANSACTIONS); URI_MATCHER.addURI(AUTHORITY, BANK_ACCOUNTS_CAT + "/" + WILD_CARD, BANK_ACCOUNTS); // Projections are "Poor mans views" of the data. BANK_ACCOUNT_PROJECTION_MAP = new HashMap<String, String>(); // Must match bankAccountProjection in // IBankTransactionsProvider#bankAccountProjection BANK_ACCOUNT_PROJECTION_MAP.put(BANK_ID, BANK_ID); BANK_ACCOUNT_PROJECTION_MAP.put(BANK_NAME, BANK_NAME); BANK_ACCOUNT_PROJECTION_MAP.put(BANK_TYPE, BANK_TYPE); BANK_ACCOUNT_PROJECTION_MAP.put(BANK_LAST_UPDATED, BANK_LAST_UPDATED); BANK_ACCOUNT_PROJECTION_MAP.put(ACC_ID, ACC_ID); BANK_ACCOUNT_PROJECTION_MAP.put(ACC_NAME, ACC_NAME); // Table name has to be explicitly included here since Banks also have a column named balance. BANK_ACCOUNT_PROJECTION_MAP.put(ACC_BALANCE, ACCOUNT_TABLE + "." + ACC_BALANCE); BANK_ACCOUNT_PROJECTION_MAP.put(ACC_TYPE, ACC_TYPE); TRANS_PROJECTION_MAP = new HashMap<String, String>(); // Must match transactionProjection in // IBankTransactionsProvider#transactionProjection TRANS_PROJECTION_MAP.put(TRANS_ID, TRANS_ID); TRANS_PROJECTION_MAP.put(TRANS_DATE, TRANS_DATE); TRANS_PROJECTION_MAP.put(TRANS_DESC, TRANS_DESC); TRANS_PROJECTION_MAP.put(TRANS_AMT, TRANS_AMT); TRANS_PROJECTION_MAP.put(TRANS_CUR, TRANS_CUR); TRANS_PROJECTION_MAP.put(TRANS_ACCNT, TRANS_ACCNT); } private DatabaseHelper dbHelper; public static String getApiKey(final Context ctx) { final SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(ctx); if (!prefs.getBoolean(CONTENT_PROVIDER_ENABLED, false)) { throw new IllegalStateException( "Access to Content Provider is not enabled."); } final String apiKey = prefs.getString(CONTENT_PROVIDER_API_KEY, ""); if (apiKey.equals("")) { throw new IllegalArgumentException("The API-Key must be set."); } return apiKey; } /** * {@inheritDoc} */ @Override public int delete(final Uri uri, final String selection, final String[] selectionArgs) { throw new UnsupportedOperationException( "This provider does not implement the delete method"); } /** * {@inheritDoc} */ @Override public String getType(final Uri uri) { Timber.d("Got URI: %s", uri.toString()); switch (URI_MATCHER.match(uri)) { case BANK_ACCOUNTS: return BANK_ACCOUNTS_MIME; case TRANSACTIONS: return TRANSACTIONS_MIME; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } /** * {@inheritDoc} */ @Override public Uri insert(final Uri uri, final ContentValues values) { throw new UnsupportedOperationException( "This provider does not implement the insert method"); } /** * {@inheritDoc} */ @Override public boolean onCreate() { dbHelper = DatabaseHelper.getHelper(getContext()); return true; } /** * {@inheritDoc} */ @Override public Cursor query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) { if (!isApiKeyEnabled(getContext())) { return null; } final String apiKey = uri.getPathSegments().get(1); Timber.v("Trying to access database with %s", apiKey); if (!apiKey.startsWith(API_KEY, 0)) { return null; // throw new IllegalArgumentException(API_KEY + // "<API-KEY> must be a part of the URI!"); } final String key = apiKey.replace(API_KEY, ""); if (!key.equals(getApiKey(getContext()))) { return null; // throw new // IllegalAccessError("The supplied API_KEY does not exist"); } final SQLiteDatabase db = dbHelper.getReadableDatabase(); SQLiteQueryBuilder qb; if (BANK_ACCOUNTS_MIME.equals(getType(uri))) { qb = new SQLiteQueryBuilder(); qb.setTables(BANK_ACCOUNT_TABLES); qb.setProjectionMap(BANK_ACCOUNT_PROJECTION_MAP); qb.setDistinct(true); } else if (TRANSACTIONS_MIME.equals(getType(uri))) { qb = new SQLiteQueryBuilder(); qb.setTables(TRANSACTIONS_TABLE); qb.setProjectionMap(TRANS_PROJECTION_MAP); } else { throw new IllegalArgumentException("Unsupported URI: " + uri); } final Cursor cur = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); cur.setNotificationUri(getContext().getContentResolver(), uri); return cur; } /** * {@inheritDoc} */ @Override public int update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) { throw new UnsupportedOperationException( "This provider does not implement the update method"); } private boolean isApiKeyEnabled(final Context ctx) { final SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(ctx); return prefs.getBoolean(CONTENT_PROVIDER_ENABLED, false); } }