package com.mehmetakiftutuncu.eshotroid.provider; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.text.TextUtils; import android.util.Log; /** * A ContentProvider for Eshotroid which provides access to all bus and Kent Kart * information in a URI based, unified way * * @author mehmetakiftutuncu */ public class EshotroidProvider extends ContentProvider { /** Name of the Eshotroid database */ private static final String DATABASE_NAME = "eshotroid.db"; /** Version of the Eshotroid database */ private static final int DATABASE_VERSION = 1; /** Authority of the provider */ public static final String AUTHORITY = "com.mehmetakiftutuncu.eshotroid"; /** Contains constants related to busses */ public static class Busses { /** Table name for the busses */ public static final String TABLE_NAME = "busses"; /** URI to use for the busses */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME); /** Type of the single bus provided by EshotroidProvider */ public static final String CONTENT_ITEM_TYPE = "bus"; /** Type of the multiple busses provided by EshotroidProvider */ public static final String CONTENT_DIR_TYPE = "busses"; /** Column name for the number of a bus which is the id column */ public static final String COLUMN_NUMBER = "_id"; /** Column name for the source of a bus */ public static final String COLUMN_SOURCE = "source"; /** Column name for the destination of a bus */ public static final String COLUMN_DESTINATION = "destination"; /** Column name for the route of a bus */ public static final String COLUMN_ROUTE = "route"; /** Column name for the favorited flag of a bus */ public static final String COLUMN_ISFAVORITED = "is_favorited"; /** Column name for the weekday times of a bus */ public static final String COLUMN_TIMESH = "times_h"; /** Column name for the saturday times of a bus */ public static final String COLUMN_TIMESC = "times_c"; /** Column name for the sunday times of a bus */ public static final String COLUMN_TIMESP = "times_p"; /** Column name for the flag if weekday times of a bus exists */ public static final String COLUMN_TIMESH_EXISTS = "times_h_exists"; /** Column name for the flag if saturday times of a bus exists */ public static final String COLUMN_TIMESC_EXISTS = "times_c_exists"; /** Column name for the flag if sunday times of a bus exists */ public static final String COLUMN_TIMESP_EXISTS = "times_p_exists"; /** SQL string for creating busses table */ private static final String CREATE_SQL = "CREATE TABLE " + TABLE_NAME + " (" + COLUMN_NUMBER + " INTEGER PRIMARY KEY NOT NULL, " + COLUMN_SOURCE + " TEXT NOT NULL, " + COLUMN_DESTINATION + " TEXT NOT NULL, " + COLUMN_ROUTE + " TEXT, " + COLUMN_ISFAVORITED + " INTEGER NOT NULL, " + COLUMN_TIMESH + " TEXT, " + COLUMN_TIMESC + " TEXT, " + COLUMN_TIMESP + " TEXT," + COLUMN_TIMESH_EXISTS + " INTEGER NOT NULL," + COLUMN_TIMESC_EXISTS + " INTEGER NOT NULL," + COLUMN_TIMESP_EXISTS + " INTEGER NOT NULL);"; /** Array of all column names for simplicity */ public static final String[] ALL_COLUMNS = new String[] { COLUMN_NUMBER, COLUMN_SOURCE, COLUMN_DESTINATION, COLUMN_ROUTE, COLUMN_ISFAVORITED, COLUMN_TIMESH, COLUMN_TIMESC, COLUMN_TIMESP, COLUMN_TIMESH_EXISTS, COLUMN_TIMESC_EXISTS, COLUMN_TIMESP_EXISTS }; } /** Contains constants related to Kent Karts */ public static class KentKarts { /** Table name for the Kent Karts */ public static final String TABLE_NAME = "kentkarts"; /** URI to use for the Kent Karts */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME); /** Type of the single Kent Kart provided by EshotroidProvider */ public static final String CONTENT_ITEM_TYPE = "kentkart"; /** Type of the multiple Kent Karts provided by EshotroidProvider */ public static final String CONTENT_DIR_TYPE = "kentkarts"; /** Column name for the id of a Kent Kart (This is row id in database) */ public static final String COLUMN_ID = "_id"; /** Column name for the name of a Kent Kart */ public static final String COLUMN_NAME = "name"; /** Column name for the alias no 1 of a Kent Kart */ public static final String COLUMN_ALIAS1 = "alias_no1"; /** Column name for the alias no 2 of a Kent Kart */ public static final String COLUMN_ALIAS2 = "alias_no2"; /** Column name for the alias no 3 of a Kent Kart */ public static final String COLUMN_ALIAS3 = "alias_no3"; /** SQL string for creating Kent Karts table */ private static final String CREATE_SQL = "CREATE TABLE " + TABLE_NAME + " (" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + COLUMN_NAME + " TEXT NOT NULL, " + COLUMN_ALIAS1 + " TEXT NOT NULL, " + COLUMN_ALIAS2 + " TEXT NOT NULL, " + COLUMN_ALIAS3 + " TEXT NOT NULL);"; /** Array of all column names for simplicity */ public static final String[] ALL_COLUMNS = new String[] { COLUMN_ID, COLUMN_NAME, COLUMN_ALIAS1, COLUMN_ALIAS2, COLUMN_ALIAS3 }; } /** URI match code for a single bus */ private static final int SINGLE_BUS = 1; /** URI match code for multiple busses */ private static final int MULTIPLE_BUSSES = 2; /** URI match code for a single Kent Kart */ private static final int SINGLE_KENTKART = 3; /** URI match code for multiple Kent Karts */ private static final int MULTIPLE_KENTKARTS = 4; /** UriMatcher for matching the query URI to the correct type */ private static final UriMatcher uriMatcher; // Static initialization of the UriMatcher static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, Busses.TABLE_NAME + "#", SINGLE_BUS); uriMatcher.addURI(AUTHORITY, Busses.TABLE_NAME, MULTIPLE_BUSSES); uriMatcher.addURI(AUTHORITY, KentKarts.TABLE_NAME + "#", SINGLE_KENTKART); uriMatcher.addURI(AUTHORITY, KentKarts.TABLE_NAME, MULTIPLE_KENTKARTS); } /** Tag for debugging */ public static final String LOG_TAG = "Eshotroid_EshotroidProvider"; /** An SQLiteOpenHelper class to provide a database access */ public class EshotroidDBOpenHelper extends SQLiteOpenHelper { /** SQL statement that creates Eshotroid database */ private static final String CREATE_SQL = Busses.CREATE_SQL + KentKarts.CREATE_SQL; public EshotroidDBOpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_SQL); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(LOG_TAG, "Upgrading Eshotroid database from version " + oldVersion + " to " + newVersion + " which will destroy all data..."); db.execSQL("DROP TABLE IF EXISTS " + Busses.TABLE_NAME); db.execSQL("DROP TABLE IF EXISTS " + KentKarts.TABLE_NAME); onCreate(db); } } /** SQLiteOpenHelper to provide access to the actual database */ private EshotroidDBOpenHelper dbOpenHelper; @Override public boolean onCreate() { dbOpenHelper = new EshotroidDBOpenHelper(getContext()); return true; } @Override public String getType(Uri uri) { switch(uriMatcher.match(uri)) { case SINGLE_BUS: return ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + Busses.CONTENT_ITEM_TYPE; case MULTIPLE_BUSSES: return ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + Busses.CONTENT_DIR_TYPE; case SINGLE_KENTKART: return ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + KentKarts.CONTENT_ITEM_TYPE; case MULTIPLE_KENTKARTS: return ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + KentKarts.CONTENT_DIR_TYPE; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); switch(uriMatcher.match(uri)) { case SINGLE_BUS: String busNumber = uri.getPathSegments().get(1); selection = getAppendedSelection(selection, Busses.COLUMN_NUMBER + "=?"); selectionArgs = getAppendedSelectionArgs(selectionArgs, busNumber); Cursor singleBus = db.query(Busses.TABLE_NAME, Busses.ALL_COLUMNS, selection, selectionArgs, null, null, null); singleBus.setNotificationUri(getContext().getContentResolver(), uri); return singleBus; case MULTIPLE_BUSSES: Cursor multipleBusses = db.query(Busses.TABLE_NAME, Busses.ALL_COLUMNS, selection, selectionArgs, null, null, null); multipleBusses.setNotificationUri(getContext().getContentResolver(), uri); return multipleBusses; case SINGLE_KENTKART: String kentKartId = uri.getPathSegments().get(1); selection = getAppendedSelection(selection, KentKarts.COLUMN_ID + "=?"); selectionArgs = getAppendedSelectionArgs(selectionArgs, kentKartId); Cursor singleKentKart = db.query(KentKarts.TABLE_NAME, KentKarts.ALL_COLUMNS, selection, selectionArgs, null, null, null); singleKentKart.setNotificationUri(getContext().getContentResolver(), uri); return singleKentKart; case MULTIPLE_KENTKARTS: Cursor multipleKentKarts = db.query(KentKarts.TABLE_NAME, KentKarts.ALL_COLUMNS, selection, selectionArgs, null, null, null); multipleKentKarts.setNotificationUri(getContext().getContentResolver(), uri); return multipleKentKarts; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); switch(uriMatcher.match(uri)) { case MULTIPLE_BUSSES: long busNumber = db.insert(Busses.TABLE_NAME, null, values); if(busNumber > -1) { getContext().getContentResolver().notifyChange(uri, null, false); return ContentUris.withAppendedId(Busses.CONTENT_URI, busNumber); } else { return null; } case MULTIPLE_KENTKARTS: long kentKartId = db.insert(KentKarts.TABLE_NAME, null, values); if(kentKartId > -1) { getContext().getContentResolver().notifyChange(uri, null, false); return ContentUris.withAppendedId(KentKarts.CONTENT_URI, kentKartId); } else { return null; } default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); switch(uriMatcher.match(uri)) { case SINGLE_BUS: String busNumber = uri.getPathSegments().get(1); selection = getAppendedSelection(selection, Busses.COLUMN_NUMBER + "=?"); selectionArgs = getAppendedSelectionArgs(selectionArgs, busNumber); int updatedBusCount = db.update(Busses.TABLE_NAME, values, selection, selectionArgs); getContext().getContentResolver().notifyChange(uri, null); return updatedBusCount; case SINGLE_KENTKART: String kentKartId = uri.getPathSegments().get(1); selection = getAppendedSelection(selection, KentKarts.COLUMN_ID + "=?"); selectionArgs = getAppendedSelectionArgs(selectionArgs, kentKartId); int updatedKentKartCount = db.update(KentKarts.TABLE_NAME, values, selection, selectionArgs); getContext().getContentResolver().notifyChange(uri, null); return updatedKentKartCount; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); int deletedCount = 0; switch(uriMatcher.match(uri)) { case SINGLE_BUS: String busNumber = uri.getPathSegments().get(1); selection = getAppendedSelection(selection, Busses.COLUMN_NUMBER + "=?"); selectionArgs = getAppendedSelectionArgs(selectionArgs, busNumber); deletedCount = db.delete(Busses.TABLE_NAME, selection, selectionArgs); break; case MULTIPLE_BUSSES: deletedCount = db.delete(Busses.TABLE_NAME, selection, selectionArgs); break; case SINGLE_KENTKART: String kentKartId = uri.getPathSegments().get(1); selection = getAppendedSelection(selection, KentKarts.COLUMN_ID + "=?"); selectionArgs = getAppendedSelectionArgs(selectionArgs, kentKartId); deletedCount = db.delete(KentKarts.TABLE_NAME, selection, selectionArgs); break; case MULTIPLE_KENTKARTS: deletedCount = db.delete(KentKarts.TABLE_NAME, selection, selectionArgs); break; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } return deletedCount; } /** * Generates an SQL selection clause by appending a new predicate * * @param selection Initial clause * @param newPredicate New predicate to append * * @return A new clause with newPredicate appended to selection, * or newPredicate itself if selection is empty */ private String getAppendedSelection(String selection, String newPredicate) { return !TextUtils.isEmpty(selection) ? selection + " AND (" + newPredicate + ")" : newPredicate; } /** * Generates an array of selection arguments by appending a selection argument * * @param selectionArgs Initial selection arguments * @param newArg New selection argument to append * * @return A new array of selection arguments with newArg appended to selectionArgs, * or newArg itself as array if selectionArgs is empty */ private String[] getAppendedSelectionArgs(String[] selectionArgs, String newArg) { if(selectionArgs != null) { String[] newSelectionArgs = new String[selectionArgs.length]; for(int i = 0; i < selectionArgs.length; i++) { newSelectionArgs[i] = selectionArgs[i]; } newSelectionArgs[newSelectionArgs.length - 1] = newArg; return newSelectionArgs; } else { return new String[] {newArg}; } } }