Finish my SQLite Provider.
authorgumartinm <gu.martinm@gmail.com>
Wed, 8 Feb 2012 06:33:40 +0000 (07:33 +0100)
committergumartinm <gu.martinm@gmail.com>
Wed, 8 Feb 2012 06:33:40 +0000 (07:33 +0100)
Next step: to test it. I did not have time to run my code
probably it is not working right now.

Android/Testing/Test3/src/de/android/test3/Indexer.java [new file with mode: 0644]
Android/Testing/Test3/src/de/android/test3/IndexerOpenHelper.java
Android/Testing/Test3/src/de/android/test3/IndexerProvider.java

diff --git a/Android/Testing/Test3/src/de/android/test3/Indexer.java b/Android/Testing/Test3/src/de/android/test3/Indexer.java
new file mode 100644 (file)
index 0000000..05791f9
--- /dev/null
@@ -0,0 +1,61 @@
+package de.android.test3;
+
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+public final class Indexer {
+       public static final String AUTHORITY = "de.android.test3.provider.IndexerProvider";
+
+       // This class cannot be instantiated
+    private Indexer() {
+    }
+    
+    /**
+     * Indexer table contract
+     */
+    public static final class Index implements BaseColumns {
+       
+       // This class cannot be instantiated
+        private Index() {}
+        
+        /**
+         * The table name offered by this provider
+         */
+        public static final String TABLE_NAME = "indexer";
+        
+        /**
+         * Column name for the path of the file
+         * <P>Type: TEXT</P>
+         */
+        public static final String COLUMN_NAME_PATH = "path";
+        
+        /**
+         * Column name for the ad unique identifier number
+         * <P>Type: REAL</P>
+         */
+        public static final String COLUMN_NAME_ID_AD = "idad";
+        
+        /**
+         * The default sort order for this table
+         */
+        public static final String DEFAULT_SORT_ORDER = "by " + Index._ID;
+        
+        /**
+         * The MIME type of {@link #CONTENT_URI} providing a directory of notes.
+         */
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.index";
+        
+        /**
+         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
+         * note.
+         */
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.index";
+        
+        /**
+         * The content URI base for a single note. Callers must
+         * append a numeric note id to this Uri to retrieve a note
+         */
+        public static final Uri CONTENT_ID_URI_BASE
+            = Uri.parse("content://com.google.provider.NotePad/notes/");
+    }
+}
index e62eb23..55a4e0d 100644 (file)
@@ -9,17 +9,12 @@ public class IndexerOpenHelper extends SQLiteOpenHelper {
        // Used for debugging and logging
     private static final String TAG = "IndexerOpenHelper";
        
-       private static final String DBNAME = "mobiads";
+       private static final String DATABASE_NAME = "mobiads.db";
        private static final int DATABASE_VERSION = 1;
-    private static final String TABLE_NAME = "indexer";
-    private static final String TABLE_CREATE = "CREATE TABLE " + TABLE_NAME + 
-                                                                                                       "(_ID INTEGER NOT NULL, " +
-                                                                                                       "PATH TEXT(15) NOT NULL, " + 
-                                                                                                       "PRIMARY KEY (_ID), " +
-                                                                                                       "UNIQUE (PATH), " + ")";
+
 
     IndexerOpenHelper(Context context) {
-        super(context, DBNAME, null, DATABASE_VERSION);
+        super(context, DATABASE_NAME, null, DATABASE_VERSION);
     }
 
 
@@ -30,7 +25,11 @@ public class IndexerOpenHelper extends SQLiteOpenHelper {
      */
     @Override
        public void onCreate(SQLiteDatabase db) {
-               db.execSQL(TABLE_CREATE);
+               db.execSQL("CREATE TABLE " + Indexer.Index.TABLE_NAME + " ("
+                               + Indexer.Index._ID + "  INTEGER PRIMARY KEY, "
+                               + Indexer.Index.COLUMN_NAME_ID_AD + " REAL" + " UNIQUE" + "NOT NULL"
+                               + Indexer.Index.COLUMN_NAME_PATH + " TEXT(15)" + " UNIQUE" + " NOT NULL"
+                               + ");");
        }
 
 
@@ -48,7 +47,7 @@ public class IndexerOpenHelper extends SQLiteOpenHelper {
                 + newVersion + ", which will destroy all old data");
 
         // Kills the table and existing data
-        db.execSQL("DROP TABLE IF EXISTS indexer");
+        db.execSQL("DROP TABLE IF EXISTS " + Indexer.Index.TABLE_NAME);
 
         // Recreates the database with a new version
         onCreate(db);
index 52b1a74..3f456f3 100644 (file)
@@ -1,14 +1,16 @@
-/**
- * 
- */
 package de.android.test3;
 
+import java.util.HashMap;
 import android.content.ContentProvider;
+import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.UriMatcher;
 import android.database.Cursor;
+import android.database.SQLException;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
+import android.text.TextUtils;
 
 /**
  *
@@ -17,6 +19,11 @@ public class IndexerProvider extends ContentProvider {
     // Creates a UriMatcher object.
     private static final UriMatcher sUriMatcher;
     
+    /**
+     * A projection map used to select columns from the database
+     */
+    private static HashMap<String, String> sIndexerProjectionMap;
+    
     // Handle to a new DatabaseHelper.
     private IndexerOpenHelper mOpenHelper;
     
@@ -35,11 +42,11 @@ public class IndexerProvider extends ContentProvider {
         sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
         
         // Add a pattern that routes URIs terminated with "notes" to a NOTES operation
-        sUriMatcher.addURI("de.android.test3.provider", "indexer", INDEXER);
+        sUriMatcher.addURI("de.android.test3.provider", Indexer.Index.TABLE_NAME, INDEXER);
         
         // Add a pattern that routes URIs terminated with "notes" plus an integer
         // to a note ID operation
-        sUriMatcher.addURI("de.android.test3.provider", "indexer/#", INDEXER_ID);
+        sUriMatcher.addURI("de.android.test3.provider", Indexer.Index.TABLE_NAME + "/#", INDEXER_ID);
     }
  
     
@@ -86,82 +93,301 @@ public class IndexerProvider extends ContentProvider {
 
         // Does the delete based on the incoming URI pattern.
         switch (sUriMatcher.match(uri)) {
-        case INDEXER_ID:
-               /*
-             * Starts a final WHERE clause by restricting it to the
-             * desired note ID.
-             */
-            finalWhere =
-                    NotePad.Notes._ID +                              // The ID column name
-                    " = " +                                          // test for equality
-                    uri.getPathSegments().                           // the incoming note ID
-                        get(NotePad.Notes.NOTE_ID_PATH_POSITION)
-            ;
-
-            // If there were additional selection criteria, append them to the final
-            // WHERE clause
-            if (where != null) {
-                finalWhere = finalWhere + " AND " + where;
-            }
-
-            // Performs the delete.
-            count = db.delete(
-                NotePad.Notes.TABLE_NAME,  // The database table name.
-                finalWhere,                // The final WHERE clause
-                whereArgs                  // The incoming where clause values.
-            );
-            break;
-
-        default:
-            throw new IllegalArgumentException("Unknown URI " + uri);
+               case INDEXER:
+                       // If the incoming pattern matches the general pattern for notes, does a delete
+                       // based on the incoming "where" columns and arguments.
+                count = db.delete(
+                       Indexer.Index.TABLE_NAME,  // The database table name
+                       selection,                 // The incoming where clause column names
+                       selectionArgs              // The incoming where clause values
+                );
+                break;
+               case INDEXER_ID:
+                       /*
+                        * Starts a final WHERE clause by restricting it to the
+                        * desired note ID.
+                        */
+                       finalWhere =
+                    Indexer.Index._ID +                // The ID column name
+                    " = " +                                    // test for equality
+                    uri.getPathSegments().get(1);      // the incoming note ID
+                        
+
+                       // If there were additional selection criteria, append them to the final
+                       // WHERE clause
+                       if (selection != null) {
+                               finalWhere = finalWhere + " AND " + selection;
+                       }
+
+                       // Performs the delete.
+                       count = db.delete(
+                                       Indexer.Index.TABLE_NAME,  // The database table name.
+                                       finalWhere,                // The final WHERE clause
+                                       selectionArgs                  // The incoming where clause values.
+                       );
+                       break;
+
+               default:
+                       throw new IllegalArgumentException("Unknown URI " + uri);
         }
        
-               return 0;
+               return count;
        }
 
-       /* (non-Javadoc)
-        * @see android.content.ContentProvider#getType(android.net.Uri)
-        */
+    /**
+     * This is called when a client calls {@link android.content.ContentResolver#getType(Uri)}.
+     * Returns the MIME data type of the URI given as a parameter.
+     *
+     * @param uri The URI whose MIME type is desired.
+     * @return The MIME type of the URI.
+     * @throws IllegalArgumentException if the incoming URI pattern is invalid.
+     */
        @Override
        public String getType(Uri uri) {
-               // TODO Auto-generated method stub
-               return null;
+               /**
+                * Chooses the MIME type based on the incoming URI pattern
+            */
+               switch (sUriMatcher.match(uri)) {
+                       // If the pattern is for notes or live folders, returns the general content type.
+               case INDEXER:
+                       return Indexer.Index.CONTENT_TYPE;
+                       
+               // If the pattern is for note IDs, returns the note ID content type.
+               case INDEXER_ID:
+                       return Indexer.Index.CONTENT_ITEM_TYPE;
+
+               // If the URI pattern doesn't match any permitted patterns, throws an exception.
+               default:
+                       throw new IllegalArgumentException("Unknown URI " + uri);
+               }
        }
 
-       /* (non-Javadoc)
-        * @see android.content.ContentProvider#insert(android.net.Uri, android.content.ContentValues)
-        */
+       
+    /**
+     * This is called when a client calls
+     * {@link android.content.ContentResolver#insert(Uri, ContentValues)}.
+     * Inserts a new row into the database. This method sets up default values for any
+     * columns that are not included in the incoming map.
+     * If rows were inserted, then listeners are notified of the change.
+     * @return The row ID of the inserted row.
+     * @throws SQLException if the insertion fails.
+     */
        @Override
-       public Uri insert(Uri uri, ContentValues values) {
-               /*
-         * Gets a writeable database. This will trigger its creation if it doesn't already exist.
-         *
-         */
-        db = mOpenHelper.getWritableDatabase();
+       public Uri insert(Uri uri, ContentValues initialValues) {
+               // A map to hold the new record's values.
+        ContentValues values;
+                               
+               // If the incoming values map is not null, uses it for the new values.
+        if (initialValues != null) {
+            values = new ContentValues(initialValues);
+
+        } else {
+            // Otherwise, create a new value map
+            values = new ContentValues();
+        }
+               
+        // If the values map doesn't contain the path or ad identifier number.
+        if ((values.containsKey(Indexer.Index.COLUMN_NAME_PATH) == false) || 
+               (values.containsKey(Indexer.Index.COLUMN_NAME_ID_AD) == false)){
+               throw new SQLException("Missed parameter. Failed to insert row into " + uri);
+        }      
+        
+        // Opens the database object in "write" mode.
+        // This will trigger its creation if it doesn't already exist.
+               SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+               
+               // Performs the insert and returns the ID of the new note.
+        long rowId = db.insert(
+               Indexer.Index.COLUMN_NAME_ID_AD, // The table to insert into.
+            Indexer.Index.COLUMN_NAME_PATH,  // A hack, SQLite sets this column value to null
+                                             // if values is empty.
+            values                           // A map of column names, and the values to insert
+                                             // into the columns.
+        );
+               
+        // If the insert succeeded, the row ID exists.
+        if (rowId > 0) {
+            // Creates a URI with the note ID pattern and the new row ID appended to it.
+            Uri noteUri = ContentUris.withAppendedId(Indexer.Index.CONTENT_ID_URI_BASE, rowId);
 
-               return null;
+            // Notifies observers registered against this provider that the data changed.
+            getContext().getContentResolver().notifyChange(noteUri, null);
+            return noteUri;
+        }
+
+        // If the insert didn't succeed, then the rowID is <= 0. Throws an exception.
+        throw new SQLException("Failed to insert row into " + uri);
        }
        
        
-
-       /* (non-Javadoc)
-        * @see android.content.ContentProvider#query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String)
+       /**
+        * This method is called when a client calls
+        * {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)}.
+        * Queries the database and returns a cursor containing the results.
+        *
+        * @return A cursor containing the results of the query. The cursor exists but is empty if
+        * the query returns no results or an exception occurs.
+        * @throws IllegalArgumentException if the incoming URI pattern is invalid.
         */
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
-               // TODO Auto-generated method stub
-               return null;
+               
+               // Constructs a new query builder and sets its table name
+           SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+           qb.setTables(Indexer.Index.TABLE_NAME);
+               
+           /**
+            * Choose the projection and adjust the "where" clause based on URI pattern-matching.
+            */
+           switch (sUriMatcher.match(uri)) {
+               // If the incoming URI is for notes, chooses the Indexer projection
+               case INDEXER:
+                       qb.setProjectionMap(sIndexerProjectionMap);
+                      
+                       break;
+
+               /* If the incoming URI is for a single note identified by its ID, chooses the
+                * note ID projection, and appends "_ID = <noteID>" to the where clause, so that
+                * it selects that single note
+                */
+               case INDEXER_ID:
+                       qb.setProjectionMap(sIndexerProjectionMap);
+                       qb.appendWhere(
+                       Indexer.Index._ID +             // the name of the ID column
+                          "=" +
+                          // the position of the note ID itself in the incoming URI
+                          uri.getPathSegments().get(1));
+                   break;
+
+               default:
+                   // If the URI doesn't match any of the known patterns, throw an exception.
+                   throw new IllegalArgumentException("Unknown URI " + uri);
+           }
+           
+           String orderBy;
+           // If no sort order is specified, uses the default
+           if (TextUtils.isEmpty(sortOrder)) {
+               orderBy = Indexer.Index.DEFAULT_SORT_ORDER;
+           } else {
+               // otherwise, uses the incoming sort order
+               orderBy = sortOrder;
+           }
+
+           // Opens the database object in "read" mode, since no writes need to be done.
+           SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+
+           /*
+            * Performs the query. If no problems occur trying to read the database, then a Cursor
+            * object is returned; otherwise, the cursor variable contains null. If no records were
+            * selected, then the Cursor object is empty, and Cursor.getCount() returns 0.
+            */
+           Cursor c = qb.query(
+                       db,            // The database to query
+                       projection,    // The columns to return from the query
+                       selection,     // The columns for the where clause
+                       selectionArgs, // The values for the where clause
+                       null,          // don't group the rows
+                       null,          // don't filter by row groups
+                       orderBy        // The sort order
+           );
+           
+           // Tells the Cursor what URI to watch, so it knows when its source data changes
+           c.setNotificationUri(getContext().getContentResolver(), uri);
+           return c;
        }
 
-       /* (non-Javadoc)
-        * @see android.content.ContentProvider#update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[])
-        */
+    /**
+     * This is called when a client calls
+     * {@link android.content.ContentResolver#update(Uri,ContentValues,String,String[])}
+     * Updates records in the database. The column names specified by the keys in the values map
+     * are updated with new data specified by the values in the map. If the incoming URI matches the
+     * note ID URI pattern, then the method updates the one record specified by the ID in the URI;
+     * otherwise, it updates a set of records. The record or records must match the input
+     * selection criteria specified by where and whereArgs.
+     * If rows were updated, then listeners are notified of the change.
+     *
+     * @param uri The URI pattern to match and update.
+     * @param values A map of column names (keys) and new values (values).
+     * @param where An SQL "WHERE" clause that selects records based on their column values. If this
+     * is null, then all records that match the URI pattern are selected.
+     * @param whereArgs An array of selection criteria. If the "where" param contains value
+     * placeholders ("?"), then each placeholder is replaced by the corresponding element in the
+     * array.
+     * @return The number of rows updated.
+     * @throws IllegalArgumentException if the incoming URI pattern is invalid.
+     */
        @Override
-       public int update(Uri uri, ContentValues values, String selection,
-                       String[] selectionArgs) {
-               // TODO Auto-generated method stub
-               return 0;
+       public int update(Uri uri, ContentValues values, String where,
+                       String[] whereArgs) {
+               
+               // Opens the database object in "write" mode.
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        int count;
+        String finalWhere;
+
+        // Does the update based on the incoming URI pattern
+        switch (sUriMatcher.match(uri)) {
+        
+               // If the incoming URI matches the general notes pattern, does the update based on
+               // the incoming data.
+               case INDEXER:
+                       
+                       // Does the update and returns the number of rows updated.
+                count = db.update(
+                    Indexer.Index.TABLE_NAME, // The database table name.
+                    values,                   // A map of column names and new values to use.
+                    where,                    // The where clause column names.
+                    whereArgs                 // The where clause column values to select on.
+                );
+                break;
+            
+            // If the incoming URI matches a single note ID, does the update based on the incoming
+            // data, but modifies the where clause to restrict it to the particular note ID.
+               case INDEXER_ID:
+                       
+                       // From the incoming URI, get the note ID
+                String noteId = uri.getPathSegments().get(1);
+
+                /*
+                 * Starts creating the final WHERE clause by restricting it to the incoming
+                 * note ID.
+                 */
+                finalWhere =
+                                       Indexer.Index._ID +         // The ID column name
+                                       " = " +                         // test for equality
+                                       noteId;                     // the incoming note ID
+
+                // If there were additional selection criteria, append them to the final WHERE
+                // clause
+                if (where !=null) {
+                    finalWhere = finalWhere + " AND " + where;
+                }
+
+
+                // Does the update and returns the number of rows updated.
+                count = db.update(
+                       Indexer.Index.TABLE_NAME, // The database table name.
+                    values,                   // A map of column names and new values to use.
+                    finalWhere,               // The final WHERE clause to use
+                                              // placeholders for whereArgs
+                    whereArgs                 // The where clause column values to select on, or
+                                              // null if the values are in the where argument.
+                );
+                break;
+                       
+               default:
+                       throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+               
+        /*Gets a handle to the content resolver object for the current context, and notifies it
+         * that the incoming URI changed. The object passes this along to the resolver framework,
+         * and observers that have registered themselves for the provider are notified.
+         */
+        getContext().getContentResolver().notifyChange(uri, null);
+
+        // Returns the number of rows updated.
+        return count;
        }
 
 }