Skip to content

Commit

Permalink
Finalized move to TouchDB, returned images to attachments, and remove…
Browse files Browse the repository at this point in the history
…d ASYNC Tasks that were causing issues with proper communication of EktorpAsyncTask. Live updating of View Queries is hence disabled, but also deemed unnecessary since activities are destroyed and recreated constantly, and communication with TouchDB is very fast
  • Loading branch information
Deepwinter committed Jun 1, 2012
1 parent e4abffa commit 85ba28c
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 64 deletions.
2 changes: 1 addition & 1 deletion project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
# project structure.

# Project target.
target=Google Inc.:Google APIs:15
target=Google Inc.:Google APIs:10
android.library.reference.1=../../../software-development/WildflowersOfDetroit/experiment/TouchDB-Android/TouchDB-Android
android.library.reference.2=../../../software-development/WildflowersOfDetroit/experiment/TouchDB-Android/TouchDB-Android-Ektorp
23 changes: 19 additions & 4 deletions src/net/winterroot/android/rhus/RhusDocumentDetailActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
import org.codehaus.jackson.map.ObjectMapper;

import android.app.Activity;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
Expand Down Expand Up @@ -71,10 +73,23 @@ public void onClick(View arg0) {


ImageView detailImage = (ImageView) findViewById(R.id.detailImage);
if(document != null && document.medium != null){
ByteArrayInputStream is = new ByteArrayInputStream(document.medium);
Drawable drw = Drawable.createFromStream(is, "mediumImage");
detailImage.setImageDrawable(drw);
if(document != null){
Uri imageUri = RhusDocument.DOCUMENT_IMAGE_URI.buildUpon().appendPath(document.getId()).build();

Cursor imageCursor = managedQuery(imageUri, null, null, null, null);
if(imageCursor != null && imageCursor.getCount() != 0){
imageCursor.moveToFirst();
byte[] mediumData = imageCursor.getBlob(imageCursor.getColumnIndexOrThrow("image"));
if(mediumData != null){
ByteArrayInputStream is = new ByteArrayInputStream(mediumData );
Drawable drw = Drawable.createFromStream(is, "mediumImage");
detailImage.setImageDrawable(drw);
}
}




}

}
Expand Down
96 changes: 84 additions & 12 deletions src/net/winterroot/android/rhus/RhusMapActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,19 @@ public void onTap(GeoPoint geoPoint, RhusOverlayItem rhusOverlayItem) {
Cursor thumbCursor = managedQuery(thumbUri, null, null, null, null);


boolean thumbSet = false;
if(thumbCursor != null && thumbCursor.getCount() != 0){
thumbCursor.moveToFirst();
ByteArrayInputStream is = new ByteArrayInputStream( thumbCursor.getBlob(thumbCursor.getColumnIndexOrThrow("image")));
Drawable drw = Drawable.createFromStream(is, "thumbnailImage");
thumbnail.setImageDrawable(drw);
} else {
byte[] thumbData = thumbCursor.getBlob(thumbCursor.getColumnIndexOrThrow("image"));
if(thumbData != null){
ByteArrayInputStream is = new ByteArrayInputStream(thumbData );
Drawable drw = Drawable.createFromStream(is, "thumbnailImage");
thumbnail.setImageDrawable(drw);
thumbSet = true;
}
}

if(thumbSet == false) {
thumbnail.setImageDrawable(null);
}

Expand All @@ -163,6 +170,9 @@ public void onClick(View arg0) {
}
}



/*
private class QueryMapPointsTask extends AsyncTask<RhusMapActivity, Void, Void> {
Expand Down Expand Up @@ -201,6 +211,7 @@ protected void onPostExecute(Void result) {
}
}
*/

private class MapDataObserver extends DataSetObserver {

Expand Down Expand Up @@ -379,14 +390,74 @@ private void inflateLayouts(){
private void updateMapPoints(){

if(!updatingMapPoints){
QueryMapPointsTask queryMapPointsTask = new QueryMapPointsTask();
queryMapPointsTask.execute(this);
//QueryMapPointsTask queryMapPointsTask = new QueryMapPointsTask();
//queryMapPointsTask.execute(this);
queryMapPoints();
updatingMapPoints = true;
Log.v(TAG, "updatingMapPoints TRUE");

}
}

private Thread worker;

private void queryMapPoints() {
worker = new Thread(new Runnable(){

private void updateUI(final boolean done)
{
if(worker.isInterrupted()){
return;
}
runOnUiThread(new Runnable(){

public void run()
{
// Update view and remove loading spinner etc...
clearMapPoints();

try {
updateOverlays();
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.v(TAG, "updatingMapPoints ");
updatingMapPoints = false;
}
});
}

public void run()
{
Log.d(TAG, "Thread run()");
updateUI(getMapPoints());
}

private boolean getMapPoints() {
Log.v(TAG, "Setting document cursor asynchronously");
//RhusMapActivity mapActivity = mapActivities[0];

Uri workingSetUri = ((RhusApplication) getApplicationContext()).rhusDataSet.getQueryUri();

documentsCursor = managedQuery(workingSetUri, null, null, null, null);

if(documentsCursor != null){
documentsCursor.setNotificationUri(getBaseContext().getContentResolver(), workingSetUri);
documentsCursor.registerDataSetObserver(new MapDataObserver());
}

return true;
}

});
worker.start();

}

private void clearMapPoints(){
itemizedOverlay.removeAllOverlays();
loadedMapPoints.clear();
Expand All @@ -399,10 +470,10 @@ protected void onStart() {
Log.i(TAG, "onStart");

mapOverlays = mapView.getOverlays();
QueryMapPointsTask queryMapPointsTask = new QueryMapPointsTask();
queryMapPointsTask.execute(this);

}
// QueryMapPointsTask queryMapPointsTask = new QueryMapPointsTask();
// queryMapPointsTask.execute(this);
queryMapPoints();
}

protected void updateOverlays() throws JsonProcessingException, IOException{
Log.v(TAG, "Updating Overlays");
Expand All @@ -420,15 +491,15 @@ protected void updateOverlays() throws JsonProcessingException, IOException{

do {
String id = documentsCursor.getString(0);
Log.v(TAG, "Loading geopoint from cursor: "+id);
//Log.v(TAG, "Loading geopoint from cursor: "+id);

String documentJson = documentsCursor.getString(1);
// JsonNode documentObject = mapper.readTree(document);
RhusDocument document = mapper.readValue(documentJson, RhusDocument.class);


if(!loadedMapPoints.containsKey(id) && document.latitude != null ){
Log.v(TAG, "Adding geopoint from cursor");
//Log.v(TAG, "Adding geopoint from cursor");
int latitude = (int) (new Double(document.latitude) *1000000);
int longitude = (int) ( new Double(document.longitude) *1000000);
if(latitude == 0 && longitude == 0){
Expand Down Expand Up @@ -689,6 +760,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {

ByteArrayOutputStream stream = new ByteArrayOutputStream() ;
thumb.compress(Bitmap.CompressFormat.JPEG, 100, stream);
long len = stream.size();
byte[] thumbData = stream.toByteArray();

ByteArrayOutputStream stream2 = new ByteArrayOutputStream() ;
Expand Down
2 changes: 1 addition & 1 deletion src/net/winterroot/android/rhus/provider/RhusDocument.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class RhusDocument implements Parcelable {
AUTHORITY + "/" + RhusDocument.USER_DOCUMENTS);
public static final Uri DOCUMENT_THUMB_URI = Uri.parse("content://" +
AUTHORITY + "/" + RhusDocument.THUMB);
public static final Uri DOCUMENT_MEDIUM_URI = Uri.parse("content://" +
public static final Uri DOCUMENT_IMAGE_URI = Uri.parse("content://" +
AUTHORITY + "/" + RhusDocument.MEDIUM);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,11 @@ public class RhusDocumentContentProvider extends TouchDBContentProvider {
sUriMatcher.addURI(RhusDocument.AUTHORITY,
RhusDocument.MEDIUM + "/*",
DOCUMENT_IMAGE_ID);

sUriMatcher.addURI(RhusDocument.AUTHORITY,
RhusDocument.USER_DOCUMENTS,
USER_DOCUMENTS);

sUriMatcher.addURI(RhusProject.AUTHORITY,
RhusProject.PROJECTS,
PROJECTS);
Expand Down Expand Up @@ -146,7 +148,7 @@ public Uri insert(Uri uri, ContentValues values) {

//Skip matching the URI for the moment

//Doing this synchronously - caller should call this content provider aynchronously.
//Doing this synchronously - caller should call this content provider asynchronously.
Log.v(TAG, "Adding Document "+ documentNode.toString());
try {
couchDbConnector.create(documentNode);
Expand All @@ -159,14 +161,13 @@ public Uri insert(Uri uri, ContentValues values) {
String id = documentNode.get("_id").getTextValue();

byte[] thumb = values.getAsByteArray("thumb");
int lns = thumb.length;
//byte[] thumb = new byte[] {'a','b'};
ByteArrayInputStream thumbStream = new ByteArrayInputStream(thumb);
AttachmentInputStream a = new AttachmentInputStream("thumb.jpg",
thumbStream,
"image/jpeg");

String _rev =couchDbConnector.createAttachment(id, documentNode.get("_rev").getTextValue(), a);
couchDbConnector.createAttachment(_rev, a);

byte[] medium = values.getAsByteArray("medium");
int ln = medium.length;
Expand Down Expand Up @@ -246,8 +247,6 @@ public void map(Map<String, Object> document,
//TODO: break out the below into a function for reuse
Map<String, String> value = new HashMap<String, String>();
value.put("id", (String) document.get("_id"));
value.put("thumb", (String) document.get("thumb"));
//value.put("medium", (String) document.get("medium"));
value.put("latitude", (String) document.get("latitude"));
value.put("longitude", (String) document.get("longitude"));
value.put("reporter", (String) document.get("reporter"));
Expand Down Expand Up @@ -283,8 +282,6 @@ public void map(Map<String, Object> document,

Map<String, String> value = new HashMap<String, String>();
value.put("id", (String) document.get("_id"));
value.put("thumb", (String) document.get("thumb"));
//value.put("medium", (String) document.get("medium"));
value.put("latitude", (String) document.get("latitude"));
value.put("longitude", (String) document.get("longitude"));
value.put("reporter", (String) document.get("reporter"));
Expand Down Expand Up @@ -326,6 +323,14 @@ public Object reduce(List<Object> keys, List<Object> values,
Log.v(TAG, "Finished RHUS initialization");
}


//Stuff to write about
//Following changes seems really unnecessary because of android activity life cycle, unless you are doing this WITHIN a content provider
//ASYNC tasks vs. Thread, the whole thing with lossing connections
//Couchbase Mobile also had this problem, loosing connections to EKTorp
//Work toward a CouchCursor.. interesting but has lots of issues
//Async tasks get leaked..
//Android Cursor implementation is too restrictive, way too geared towards SQLite


@Override
Expand All @@ -338,7 +343,8 @@ public Cursor query(Uri uri, String[] projection, String selection,

Cursor queryCursor = null;
ViewQuery viewQuery;

String documentId;

int match = sUriMatcher.match(uri);
switch (match) {
case DOCUMENTS:
Expand Down Expand Up @@ -385,46 +391,17 @@ public Cursor query(Uri uri, String[] projection, String selection,
break;

case DOCUMENT_THUMB_ID:
//String documentId = uri.getQueryParameter("id");
String documentId = uri.getLastPathSegment();
AttachmentInputStream data;
try {
data = couchDbConnector.getAttachment(documentId,
"thumb.jpg");

} catch (DocumentNotFoundException e) {
return null;
}

/*
byte[] dataBytes = null;
try {
dataBytes = IOUtils.toByteArray(data);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
*/
documentId = uri.getLastPathSegment();
queryCursor = this.getBlobCursorForAttachment(documentId, "medium.jpg");
//break; TODO: understand how to return different types of cursors
break;

byte[] dataBytes = {'a','a'};
case DOCUMENT_IMAGE_ID:
documentId = uri.getLastPathSegment();
queryCursor = this.getBlobCursorForAttachment(documentId, "medium.jpg");


if(dataBytes != null){
//need to read data into a byteArray.
//and then return that byte array.
//BlobCursor blobCursor = new BlobCursor(new String[] {"image"});
//blobCursor.addRow(new Object[] { dataBytes } );

//TODO: this is a terrible dirty hack, because I can't understand how to just
//pass back a blob from the content provider without jumping through tons of hoops
//AbstractCursor doesn't implement getBlob, so MatrixCursor won't grant access to an assigned blob
BlobCursor blobCursor = new BlobCursor();
blobCursor.setBlob(dataBytes);
queryCursor = blobCursor;
}


//break; TODO: understand how to return different types of cursors
break;
}

if(queryCursor == null){
Expand All @@ -434,6 +411,37 @@ public Cursor query(Uri uri, String[] projection, String selection,
return queryCursor;

}

private Cursor getBlobCursorForAttachment(String documentId, String attachmentName){
AttachmentInputStream data;
try {
data = couchDbConnector.getAttachment(documentId,
attachmentName);
Log.v(TAG, data.toString());

} catch (DocumentNotFoundException e) {
return null;
}

byte[] dataBytes = null;
//String dataBytes = null;
try {
dataBytes = IOUtils.toByteArray(data);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

if(dataBytes != null){
//TODO: this is a terrible dirty hack, because I can't understand how to just
//pass back a blob from the content provider without jumping through tons of hoops
//AbstractCursor doesn't implement getBlob, so MatrixCursor won't grant access to an assigned blob
BlobCursor blobCursor = new BlobCursor();
blobCursor.setBlob(dataBytes);
return blobCursor;
}
return null;
}

@Override
public int update(Uri uri, ContentValues values, String selection,
Expand Down
3 changes: 2 additions & 1 deletion src/net/winterroot/android/touchdb/provider/CouchCursor.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public CouchCursor(CouchDbConnector setDbConnector, ViewQuery setViewQuery) {
super(new String[] {"id","document"});
this.dbConnector = setDbConnector;
this.viewQuery = setViewQuery;
followChanges = true;
followChanges = false; //These ASYNC tasks are really a big problem.
//Since activities get destroyed all the time on Android, following changes seems unnecessary.
updateListItems();
}

Expand Down

0 comments on commit 85ba28c

Please sign in to comment.