Cosc 5/4730 Android Content Providers and Intents
Content Providers Any Uri that begins with content:// is retrieved with a content provider. – The data is encapsulated using a Uri instance – You don't know where it is, nor care actually – Could be a SQLite database, files, or retrieved from off the device With a Uri, you perform basic CRUD operations using the content provider – CRUD = create, read, update, delete
URI Examples: content://media/internal/images – return the list of all internal images on the device. content://contacts/people/ – return the list of all contact names on the device. content://contacts/people/45 – return the single result row, the contact with ID=45. content://mms – returns a list of the mms messages (content://mms/part/ gets the message) content://constants/5 – return the constant number 5 content://edu.cs4730.provider.csteach/csteach – a custom content provider covered later in the lecture.
URI (2) android.providers package provide some ready made URIs, example: – ContactsContract.Contacts.CONTENT_URI – MediaStore.Images.Media.INTERNAL_CONTENT_ URI Otherwise, use Uri.parse(String); Uri CONTENT_URI = Uri.parse("content://"+ PROVIDER_NAME + "/test");
Contacts Example Simple code to read the contacts Note, need at least these permissions – Uri CONTENT_URI = ContactsContract.Contacts.CONTENT_URI; String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME }; Cursor c = managedQuery(CONTENT_URI, projection, null, null, null); if (c.moveToFirst()) { do { String str = "Id: " + c.getString(0); str += "Name: " + c.getString(1); } while (c.moveToNext()); }
Custom Content Providers SQLite databases are private only to the application that created it. While custom content providers are way to make them accessible to other app's.
Custom Content Providers (2) Extend the ContentProvider class and implement the required methods. – getType(): Returns the MIME type of the data at the given URI. – onCreate(): Called when the provider is being started. – query(): Receives a request from a client. The result is returned as a Cursor object. – insert(): Inserts a new record into the content provider. – delete(): Deletes an existing record from the content provider. – update(): Updates an existing record from the content provider.
Custom Content Providers (3) With our content provider we can choose how to store the data: – file system, xml, database, or on the internet For this lecture example, we use a database, based of the sqlite lecture previously. – The example code for sqlite is on the website as well as this example.
Creating a Custom Content Provider create a class that extends ContentProvider – Using eclipse you can also have to create the necessary methods. – In our case: public class cpProvider extends ContentProvider { – Most of the methods inside, we implement as a pass through allowing the user to access the database. They maybe a security risk and for sensitive info, a really bad idea and probably not public anyway. – We also need the some constants the database and the DatabaseHelper (not shown in these slides) for database.
Constants we need public static final String PROVIDER_NAME = "edu.cs4730.provider.csteach"; public static final Uri CONTENT_URI = Uri.parse("content://"+ PROVIDER_NAME + "/csteach"); public static final String _ID = "_id"; public static final String NAME = "name"; public static final String IP = "ip"; public static final String OWNER = "owner";
UriMatcher private static final int CSTEACH = 1; private static final int CSTEACH_ID = 2; private static final UriMatcher uriMatcher; static{ uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(PROVIDER_NAME, "csteach", CSTEACH); uriMatcher.addURI(PROVIDER_NAME, "csteach/#", CSTEACH_ID); } Observe from the code above that you use a UriMatcher object to parse the content URI that is passed to the content provider through a Content Resolver. For example, the following content URI represents a request for all rows in the content provider: content://edu.cs4730.provider.csteach/csteach In contrast, the following represents a request for a particular row with _id=5: content://edu.cs4730.provider.csteach/csteach/5
override getType() You'll need to override the getType() method so it uniquely describes the data type for your content provider. Using the UriMatcher object, you will return "vnd.android.cursor.item/vnd.cs4730.csteach" for a single row, and "vnd.android.cursor.dir/vnd.cs4730.csteach" for multiple public String getType(Uri uri) { switch (uriMatcher.match(uri)) { // get all rows case CSTEACH: return "vnd.android.cursor.dir/vnd.cs4730.csteach "; // get a particular row case CSTEACH_ID: return "vnd.android.cursor.item/vnd.csc4730.csteach "; default: throw new IllegalArgumentException("Unsupported URI: " + uri); }
The public boolean onCreate() { Context context = getContext(); dbHelper = new DatabaseHelper(context); db = dbHelper.getWritableDatabase(); return db != null; public Uri insert(Uri uri, ContentValues values) { //add a new entry long rowID = db.insert(DATABASE_TABLE, "", values); //check for success if (rowID>0){ Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID); getContext().getContentResolver().notifyChange(_uri, null); return _uri; } throw new SQLException("Failed to insert row into " + uri); }
The Rest public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder(); sqlBuilder.setTables(DATABASE_TABLE); if (uriMatcher.match(uri) == CSTEACH_ID) //if a particular row sqlBuilder.appendWhere( _ID + " = " + uri.getPathSegments().get(1)); if (sortOrder==null || sortOrder=="") //set a default sort order if none is provided. sortOrder = NAME; //then pass everything to the query builder. Cursor c = sqlBuilder.query( db, projection, selection, selectionArgs, null, null, sortOrder); //---register to watch a content URI for changes--- c.setNotificationUri(getContext().getContentResolver(), uri); return c; }
The Rest public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0; switch (uriMatcher.match(uri)){ case CSTEACH: count = db.update(DATABASE_TABLE, values, selection, selectionArgs); break; case CSTEACH_ID: count = db.update(DATABASE_TABLE, values, _ID + " = " + uri.getPathSegments().get(1) + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs); break; default: throw new IllegalArgumentException( "Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; }
The Rest public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0; switch (uriMatcher.match(uri)) { case CSTEACH: count = db.delete(DATABASE_TABLE, selection, selectionArgs); break; case CSTEACH_ID: String id = uri.getPathSegments().get(1); count = db.delete(DATABASE_TABLE, _ID + " = "+ id + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; }
Register the provider In the AndroidManifest.xml file – add the class the is the provider and register the content string <activity android:name=".cpDemo" … <provider android:name="cpProvider" android:authorities="edu.cs4730.provider.csteach" />
Activity class Now in the activity class we can use it. The example code has more examples, but two to give you a favor //add a value ContentValues values = new ContentValues(); values.put("name", "k2"); values.put("ip", " "); values.put("owner", "cosc"); Uri uri = getContentResolver().insert(Uri.parse("content:// edu.cs4730. provider.csteach/csteach"), values); // list all the entries Uri allrows = Uri.parse("content:// edu.cs4730. provider.csteach/csteach"); Cursor c = managedQuery(allrows, null, null, null, null); if (c.moveToFirst()) { do { output.append("\n" + c.getString(0) + ", " + c.getString(1) + ", " + c.getString(2) + ", " + c.getString(3)); } while (c.moveToNext()); }
References Android developer pages – CN/reference/android/provider/package- summary.html Using and Implementing Content Providers in Android – 3/page/1
INTENTS android
Intents As we saw in the Android GUI lecture intents can be used for message passing between activities. – Used to launch an Activity as well. – Also used to launch services and broadcast receives too. An Intent is a message object holding passive data about an operation to be performed – Or with broadcast receives about something that has already happened.
Making a call example The intent is pretty simple Intent dialIntent = new Intent( "android.intent.action.CALL", Uri.parse("tel: ")); – Use “android.intent.action.DIAL” To just bring up the dialer, but not call. startActivity(dialIntent); Needs – In the manifest.xml file.
Web browser intent To start up the browser with a page location you specify – Intent dialIntent = new Intent( "android.intent.action.VIEW", Uri.parse(" – startActivity(dialIntent);
Other “standard” intents You can start up the maps with an intent – intent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo: , ?z=19")); Should show Laramie on the map, but force closes on the simulator. Launch the camera – intent = new Intent("android.media.action.IMAGE_CAPTURE"); – Show contacts – intent = new Intent(Intent.ACTION_VIEW, Uri.parse("content://contacts/people/")); –
Returning data. Instead of startActivity, use – startActivityForResult(intent, resultCode); resultCode is a number you pick, that you can identify the callback with. Override onActivityResult(int requestCode, int resultCode, Intent data) method.
Passing data to a new activity. Create an intent – Intent i = new Intent(this, ActivityTwo.class); – i.putExtra(“key1”, “Some data”); – i.putExtra(“key2”, “more data”); Where key1, key2 are names both activities know. – startActivityForResult(i, REQUEST_CODE); Assumes we want return data, otherwise use startActivity.
Passing data to a new activity. (2) ActivityTwo – In the onCreate method Bundle extras = getIntent().getExtras(); //Make sure the activity was called correctly. if (extras == null) {return;} String value1 = extras.getString(“key1"); String value2 = extras.getString(“key2"); Like others, many getX methods, like getInt(String key)
Return data. When activityTwo finishes, it can return an Intent with data. In the finish() public void finish() { Intent data = new Intent(); data.putExtra("returnKey1", “some data "); data.putExtra("returnKey2", “more data"); setResult(RESULT_OK, data); super.finish(); } Result: constants are RESULT_OK, RESULT_CANCELED, but you can also use any custom result with an int. – When an activity fails, crashes, the result will be RESULT_CANCELED.
Return data (2) In the Calling protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) { //remember if RESULT_CANCELED, likely no data in the intent! if (data.hasExtra("returnKey1")) { Toast.makeText(this, data.getExtras().getString("returnKey1"), Toast.LENGTH_SHORT).show(); } } else if (resultCode == RESULT_CANCELED && requestCode == REQUEST_CODE} Toast.makeText(this, “ActivityTwo canceled!”, Toast.LENGTH_SHORT).show(); }
Finally. You can see these intents working in the code provided with the lecture. For more of google applications intents see – app-intents.html
Q A &