// ******************************************************************* // // ** Chapter 7 Code Listings ** // // ** Professional Android 2 Application Development ** // // ** Reto Meier ** // // ** (c)2010 Wrox ** // // ******************************************************************* // // ** SQLite Databases ******************************************** // // ******************************************************************* // ** Listing 7-1: Skeleton code for a standard database adapter implementation import android.content.Context; import android.database.*; import android.database.sqlite.*; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.util.Log; public class MyDBAdapter { private static final String DATABASE_NAME = "myDatabase.db"; private static final String DATABASE_TABLE = "mainTable"; private static final int DATABASE_VERSION = 1; // The index (key) column name for use in where clauses. public static final String KEY_ID="_id"; // The name and column index of each column in your database. public static final String KEY_NAME="name"; public static final int NAME_COLUMN = 1; // TODO: Create public field for each column in your table. // SQL Statement to create a new database. private static final String DATABASE_CREATE = "create table " + DATABASE_TABLE + " (" + KEY_ID + " integer primary key autoincrement, " + KEY_NAME + " text not null);"; // Variable to hold the database instance private SQLiteDatabase db; // Context of the application using the database. private final Context context; // Database open/upgrade helper private myDbHelper dbHelper; public MyDBAdapter(Context _context) { context = _context; dbHelper = new myDbHelper(context, DATABASE_NAME, null, DATABASE_VERSION); } public MyDBAdapter open() throws SQLException { db = dbHelper.getWritableDatabase(); return this; } public void close() { db.close(); } public int insertEntry(MyObject _myObject) { // TODO: Create a new ContentValues to represent my row // and insert it into the database. return index; } public boolean removeEntry(long _rowIndex) { return db.delete(DATABASE_TABLE, KEY_ID + "=" + _rowIndex, null) > 0; } public Cursor getAllEntries () { return db.query(DATABASE_TABLE, new String[] {KEY_ID, KEY_NAME}, null, null, null, null, null); } public MyObject getEntry(long _rowIndex) { // TODO: Return a cursor to a row from the database and // use the values to populate an instance of MyObject return objectInstance; } public boolean updateEntry(long _rowIndex, MyObject _myObject) { // TODO: Create a new ContentValues based on the new object // and use it to update a row in the database. return true; } private static class myDbHelper extends SQLiteOpenHelper { public myDbHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } // Called when no database exists in disk and the helper class needs // to create a new one. @Override public void onCreate(SQLiteDatabase _db) { _db.execSQL(DATABASE_CREATE); } // Called when there is a database version mismatch meaning that the version // of the database on disk needs to be upgraded to the current version. @Override public void onUpgrade(SQLiteDatabase _db, int _oldVersion, int _newVersion) { // Log the version upgrade. Log.w("TaskDBAdapter", "Upgrading from version " + _oldVersion + " to " + _newVersion + ", which will destroy all old data"); // Upgrade the existing database to conform to the new version. Multiple // previous versions can be handled by comparing _oldVersion and _newVersion // values. // The simplest case is to drop the old table and create a new one. _db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE); // Create a new one. onCreate(_db); } } } // ******************************************************************* // ** Listing 7-2: Using the SQLiteOpenHelper to access a database dbHelper = new myDbHelper(context, DATABASE_NAME, null, DATABASE_VERSION); SQLiteDatabase db; try { db = dbHelper.getWritableDatabase(); } catch (SQLiteException ex){ db = dbHelper.getReadableDatabase(); } // ******************************************************************* // ** Listing 7-3: Creating a new database private static final String DATABASE_NAME = "myDatabase.db"; private static final String DATABASE_TABLE = "mainTable"; private static final String DATABASE_CREATE = "create table " + DATABASE_TABLE + " ( _id integer primary key autoincrement," + "column_one text not null);"; SQLiteDatabase myDatabase; private void createDatabase() { myDatabase = openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null); myDatabase.execSQL(DATABASE_CREATE); } // ******************************************************************* // ** Listing 7-4: Querying a database // Return all rows for columns one and three, no duplicates String[] result_columns = new String[] {KEY_ID, KEY_COL1, KEY_COL3}; Cursor allRows = myDatabase.query(true, DATABASE_TABLE, result_columns, null, null, null, null, null, null); // Return all columns for rows where column 3 equals a set value // and the rows are ordered by column 5. String where = KEY_COL3 + "=" + requiredValue; String order = KEY_COL5; Cursor myResult = myDatabase.query(DATABASE_TABLE, null, where, null, null, null, order); // ******************************************************************* // ** Listing 7-5: Extracting values from a Cursor int GOLD_HOARDED_COLUMN = 2; Cursor myGold = myDatabase.query("GoldHoards", null, null, null, null, null, null); float totalHoard = 0f; // Make sure there is at least one row. if (myGold.moveToFirst()) { // Iterate over each cursor. do { float hoard = myGold.getFloat(GOLD_HOARDED_COLUMN); totalHoard += hoard; } while(myGold.moveToNext()); } Float averageHoard = totalHoard / myGold.getCount(); // ******************************************************************* // ** Listing 7-6: Inserting new rows into a database // Create a new row of values to insert. ContentValues newValues = new ContentValues(); // Assign values for each row. newValues.put(COLUMN_NAME, newValue); [ ... Repeat for each column ... ] // Insert the row into your table myDatabase.insert(DATABASE_TABLE, null, newValues); // ******************************************************************* // ** Listing 7-7: Updating a database row // Define the updated row content. ContentValues updatedValues = new ContentValues(); // Assign values for each row. newValues.put(COLUMN_NAME, newValue); [ ... Repeat for each column ... ] String where = KEY_ID + "=" + rowId; // Update the row with the specified index with the new values. myDatabase.update(DATABASE_TABLE, newValues, where, null); // ******************************************************************* // ** Listing 7-8: Deleting a database row myDatabase.delete(DATABASE_TABLE, KEY_ID + "=" + rowId, null); // ** Content Providers ******************************************* // // ******************************************************************* // ** Listing 7-9: Creating a new Content Provider import android.content.*; import android.database.Cursor; import android.net.Uri; import android.database.SQLException; public class MyProvider extends ContentProvider { @Override public boolean onCreate() { // TODO Construct the underlying database. return true; } } // ******************************************************************* // ** Listing 7-10: Using the UriMatcher to handle single or multiple query requests public class MyProvider extends ContentProvider { private static final String myURI = "content://com.paad.provider.myapp/items"; public static final Uri CONTENT_URI = Uri.parse(myURI); @Override public boolean onCreate() { // TODO: Construct the underlying database. return true; } // Create the constants used to differentiate between the different URI // requests. private static final int ALLROWS = 1; private static final int SINGLE_ROW = 2; private static final UriMatcher uriMatcher; // Populate the UriMatcher object, where a URI ending in 'items' will // correspond to a request for all items, and 'items/[rowID]' // represents a single row. static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("com.paad.provider.myApp", "items", ALLROWS); uriMatcher.addURI("com.paad.provider.myApp", "items/#", SINGLE_ROW); } } // ******************************************************************* // ** Listing 7-11: Implementing queries and transactions within a Content Provider @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sort) { // If this is a row query, limit the result set to the passed in row. switch (uriMatcher.match(uri)) { case SINGLE_ROW : // TODO: Modify selection based on row id, where: // rowNumber = uri.getPathSegments().get(1)); } return null; } @Override public Uri insert(Uri _uri, ContentValues _initialValues) { long rowID = [ ... Add a new item ... ] // Return a URI to the newly added item. if (rowID > 0) { return ContentUris.withAppendedId(CONTENT_URI, rowID); } throw new SQLException("Failed to add new item into " + _uri); } @Override public int delete(Uri uri, String where, String[] whereArgs) { switch (uriMatcher.match(uri)) { case ALLROWS: case SINGLE_ROW: default: throw new IllegalArgumentException("Unsupported URI:" + uri); } } @Override public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { switch (uriMatcher.match(uri)) { case ALLROWS: case SINGLE_ROW: default: throw new IllegalArgumentException("Unsupported URI:" + uri); } } // ******************************************************************* // ** Listing 7-12: Defining a Content Provider MIME type @Override public String getType(Uri _uri) { switch (uriMatcher.match(_uri)) { case ALLROWS: return "vnd.paad.cursor.dir/myprovidercontent"; case SINGLE_ROW: return "vnd.paad.cursor.item/myprovidercontent"; default: throw new IllegalArgumentException("Unsupported URI: " + _uri); } } // ******************************************************************* // ** Listing 7-13: Querying a Content Provider with a Content Resolver ContentResolver cr = getContentResolver(); // Return all rows Cursor allRows = cr.query(MyProvider.CONTENT_URI, null, null, null, null); // Return all columns for rows where column 3 equals a set value // and the rows are ordered by column 5. String where = KEY_COL3 + "=" + requiredValue; String order = KEY_COL5; Cursor someRows = cr.query(MyProvider.CONTENT_URI, null, where, null, order); // ******************************************************************* // ** Listing 7-14: Inserting new rows into a Content Provider // Get the Content Resolver ContentResolver cr = getContentResolver(); // Create a new row of values to insert. ContentValues newValues = new ContentValues(); // Assign values for each row. newValues.put(COLUMN_NAME, newValue); [ ... Repeat for each column ... ] Uri myRowUri = cr.insert(MyProvider.CONTENT_URI, newValues); // Create a new row of values to insert. ContentValues[] valueArray = new ContentValues[5]; // TODO: Create an array of new rows int count = cr.bulkInsert(MyProvider.CONTENT_URI, valueArray); // ******************************************************************* // ** Listing 7-15: Deleting records from a Content Provider ContentResolver cr = getContentResolver(); // Remove a specific row. cr.delete(myRowUri, null, null); // Remove the first five rows. String where = "_id < 5"; cr.delete(MyProvider.CONTENT_URI, where, null); // ******************************************************************* // ** Listing 7-16: Updating records in a Content Provider // Create a new row of values to insert. ContentValues newValues = new ContentValues(); // Create a replacement map, specifying which columns you want to // update, and what values to assign to each of them. newValues.put(COLUMN_NAME, newValue); // Apply to the first 5 rows. String where = "_id < 5"; getContentResolver().update(MyProvider.CONTENT_URI, newValues, where, null); // ******************************************************************* // ** Listing 7-17: Adding files to Content Providers // Insert a new row into your provider, returning its unique URI. Uri uri = getContentResolver().insert(MyProvider.CONTENT_URI, newValues); try { // Open an output stream using the new row's URI. OutputStream outStream = getContentResolver().openOutputStream(uri); // Compress your bitmap and save it into your provider. sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream); } catch (FileNotFoundException e) { } // ** Media Store ************************************************* // // ******************************************************************* // ** Listing 7-18: Accessing the Media Store Content Provider // Get a cursor over every piece of audio on the external volume. Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, null); // Let the activity manage the cursor lifecycle. startManagingCursor(cursor); // Use the convenience properties to get the index of the columns int albumIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM); int titleIdx = cursor. getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE); String[] result = new String[cursor.getCount()]; if (cursor.moveToFirst()) do { // Extract the song title. String title = cursor.getString(titleIdx); // Extract the album name. String album = cursor.getString(albumIdx); result[cursor.getPosition()] = title + " (" + album + ")"; } while(cursor.moveToNext()); // ** Contacts Content Provider *********************************** // // ******************************************************************* // ** Listing 7-19: Accessing the Contact Content Provider // Get a cursor over every aggregated contact. Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); // Let the activity manage the cursor lifecycle. startManagingCursor(cursor); // Use the convenience properties to get the index of the columns int nameIdx = cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME); int idIdx = cursor. getColumnIndexOrThrow(ContactsContract.Contacts._ID); String[] result = new String[cursor.getCount()]; if (cursor.moveToFirst()) do { // Extract the name. String name = cursor.getString(nameIdx); // Extract the phone number. String id = cursor.getString(idIdx); result[cursor.getPosition()] = name + " (" + id + ")"; } while(cursor.moveToNext()); stopManagingCursor(cursor); // ******************************************************************* // ** Listing 7-20: Finding contact details after finding a contact // Find a contact using a partial name match Uri lookupUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI, "kristy"); Cursor idCursor = getContentResolver().query(lookupUri, null, null, null, null); String id = null; if (idCursor.moveToFirst()) { int idIdx = idCursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID); id = idCursor.getString(idIdx); } idCursor.close(); if (id != null) { // Return all the contact details of type PHONE for the contact we found String where = ContactsContract.Data.CONTACT_ID + " = " + id + " AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "'"; Cursor dataCursor = getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, where, null, null); // Use the convenience properties to get the index of the columns int nameIdx = dataCursor.getColumnIndexOrThrow(ContactsContract.Data.DISPLAY_NAME); int phoneIdx = dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER); String[] result = new String[dataCursor.getCount()]; if (dataCursor.moveToFirst()) do { // Extract the name. String name = dataCursor.getString(nameIdx); // Extract the phone number. String number = dataCursor.getString(phoneIdx); result[dataCursor.getPosition()] = name + " (" + number + ")"; } while(dataCursor.moveToNext()); dataCursor.close(); } // ******************************************************************* // ** Listing 7-21: Performing a caller-ID lookup String incomingNumber = "5551234"; Uri lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, incomingNumber); Cursor idCursor = getContentResolver().query(lookupUri, null, null, null, null); if (idCursor.moveToFirst()) { int nameIdx = idCursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME); String caller = idCursor.getString(nameIdx); Toast.makeText(getApplicationContext(), caller, Toast.LENGTH_LONG).show(); } idCursor.close(); // ******************************************************************* //