Skip to content

Commit

Permalink
Get the data handle for the Image Picker. MOSYNC-2547
Browse files Browse the repository at this point in the history
  • Loading branch information
emmaTresanszki committed Dec 20, 2012
1 parent ea2690a commit 203384a
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 57 deletions.
18 changes: 18 additions & 0 deletions runtimes/cpp/platforms/android/IOCtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,24 @@ namespace Base
return (int)ret;
}

int _maImagePickerOpenWithEventReturnType(int eventReturnType, JNIEnv* jNIEnv, jobject jThis)
{
Base::gSyscall->VM_Yield();

jclass cls = jNIEnv->GetObjectClass(jThis);

jmethodID methodID = jNIEnv->GetMethodID(cls, "maImagePickerOpenWithEventReturnType", "(I)I");

jint ret = -1;

if (methodID != 0)
ret = jNIEnv->CallIntMethod(jThis, methodID, eventReturnType);

jNIEnv->DeleteLocalRef(cls);

return (int)ret;
}

int _maOptionsBox(const wchar* title, const wchar* destructiveText, const wchar* cancelText, int bufPointer, int bufSize,
JNIEnv* jNIEnv, jobject jThis)
{
Expand Down
2 changes: 2 additions & 0 deletions runtimes/cpp/platforms/android/IOCtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ namespace Base

int _maImagePickerOpen(JNIEnv* jNIEnv, jobject jThis);

int _maImagePickerOpenWithEventReturnType(int eventReturnType, JNIEnv* jNIEnv, jobject jThis);

int _maOptionsBox(const wchar* title, const wchar* destructiveText, const wchar* cancelText, int bufPointer, int bufSize,
JNIEnv* jNIEnv, jobject jThis);

Expand Down
1 change: 1 addition & 0 deletions runtimes/cpp/platforms/android/MoSyncBridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ static void nativePostEvent(JNIEnv* env, jobject jthis, jintArray eventBuffer)
{
event.imagePickerState = intArray[1];
event.imagePickerItem = intArray[2];
event.imagePickerEncodingType = intArray[3];
}
else if (event.type == EVENT_TYPE_SMS)
{
Expand Down
7 changes: 7 additions & 0 deletions runtimes/cpp/platforms/android/SyscallImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1964,6 +1964,13 @@ namespace Base
mJNIEnv,
mJThis);

case maIOCtl_maImagePickerOpenWithEventReturnType:
SYSLOG("maIOCtl_maImagePickerOpenWithEventReturnType");
return _maImagePickerOpenWithEventReturnType(
a,
mJNIEnv,
mJThis);

case maIOCtl_maOptionsBox:
{
SYSLOG("maIOCtl_maOptionsBox");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,19 @@
package com.mosync.internal.android;

import static com.mosync.internal.generated.MAAPI_consts.EVENT_TYPE_IMAGE_PICKER;
import static com.mosync.internal.generated.MAAPI_consts.MA_IMAGE_PICKER_EVENT_RETURN_TYPE_IMAGE_HANDLE;
import static com.mosync.internal.generated.MAAPI_consts.MA_IMAGE_PICKER_EVENT_RETURN_TYPE_IMAGE_DATA;
import static com.mosync.internal.generated.MAAPI_consts.MA_IMAGE_PICKER_ITEM_ENCODING_JPEG;
import static com.mosync.internal.generated.MAAPI_consts.MA_IMAGE_PICKER_ITEM_ENCODING_PNG;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Hashtable;

import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.Bitmap;
Expand All @@ -43,17 +52,33 @@ public class MoSyncImagePicker {
final static int PICKER_CANCELED = 0;
final static int PICKER_READY = 1;

// The user can choose what kind of data the PICKER_READY event will contain.
/**
* The default type: The event will contain a handle to the image object.
* Use this approach if you wish to handle the image object locally on the device.
* Note that the image is downsampled due to memory issues on bitmap objects.
*/
final static int EVENT_TYPE_IMAGE_HANDLE = MA_IMAGE_PICKER_EVENT_RETURN_TYPE_IMAGE_HANDLE;
/**
* The event will contain a handle to a data object.
* Use this approach if you want to handle the raw data on a machine with high-performance.
* Note that on Android devices, attempting to create an image object from the data object
* (by calling maCreateImageFromData) might cause OutOfMemory exceptions.
*/
final static int EVENT_TYPE_DATA_HANDLE = MA_IMAGE_PICKER_EVENT_RETURN_TYPE_IMAGE_DATA;

//-------------------------- IMPLEMENTATION --------------------------//

/**
* Constructor.
* @param thread The MoSync thread.
* @param imageTable The bitmap table.
*/
public MoSyncImagePicker(MoSyncThread thread,Hashtable<Integer, ImageCache> imageTable)
public MoSyncImagePicker(MoSyncThread thread,Hashtable<Integer, ImageCache> imageTable, int eventType)
{
mMoSyncThread = thread;
mImageTable = imageTable;
mEventReturnType = eventType;
}

/**
Expand Down Expand Up @@ -87,59 +112,141 @@ public static void handleSelectedPicture(Intent data)
ContentResolver cr = mMoSyncThread.getActivity()
.getContentResolver();

try {
/**
* Decoding options used for bitmaps. First get the image
* dimensions. Based on the image size perform a scaling.
*/
BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inJustDecodeBounds = true;
bfo.inDither = false;
bfo.inPreferredConfig = Bitmap.Config.RGB_565;

BitmapFactory.decodeStream(cr.openInputStream(pictureUri),
null, bfo);

// Calculate sample size to keep image under maxFileSize.
int maxFileSize = 1572864; // in bytes
int sampleSize = 1;
long fileSize = 2 * (bfo.outWidth / sampleSize) * (bfo.outHeight / sampleSize);
while (fileSize > maxFileSize)
if ( mEventReturnType == EVENT_TYPE_IMAGE_HANDLE )
{
try {
/**
* Decoding options used for bitmaps. First get the image
* dimensions. Based on the image size perform a scaling.
*/
BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inJustDecodeBounds = true;
bfo.inDither = false;
bfo.inPreferredConfig = Bitmap.Config.RGB_565;

BitmapFactory.decodeStream(cr.openInputStream(pictureUri),
null, bfo);

// Calculate sample size to keep image under maxFileSize.
int maxFileSize = 1572864; // in bytes
int sampleSize = 1;
long fileSize = 2 * (bfo.outWidth / sampleSize) * (bfo.outHeight / sampleSize);
while (fileSize > maxFileSize)
{
sampleSize++;
fileSize = 4 * (bfo.outWidth / sampleSize)* (bfo.outHeight / sampleSize);
}

/**
* Decode to a smaller image to save memory and run faster.
* Decode image using calculated sample size.
*/
bfo.inSampleSize = sampleSize;
bfo.inJustDecodeBounds = false;
Bitmap imageBitmap = BitmapFactory.decodeStream(
cr.openInputStream(pictureUri), null, bfo);

if (imageBitmap != null)
{
String mimeType = bfo.outMimeType;
int encodingType = -1;
if ( mimeType.equalsIgnoreCase("image/jpeg") )
encodingType = MA_IMAGE_PICKER_ITEM_ENCODING_JPEG;
else if( mimeType.equalsIgnoreCase("image/png") )
encodingType = MA_IMAGE_PICKER_ITEM_ENCODING_PNG;

// Get the handle of the selected item and post event.
postImagePickerReady(getSelectedImageHandle(imageBitmap), encodingType);
}
else
{
Log.i("@@MoSync",
"maImagePickerOpen Error: cannot decode bitmap");
return;
}

} catch (FileNotFoundException e)
{
sampleSize++;
fileSize = 2 * (bfo.outWidth / sampleSize)* (bfo.outHeight / sampleSize);
e.printStackTrace();
Log.i("@@MoSync",
"maImagePickerOpen Error: cannot find bitmap");
}

/**
* Decode to a smaller image to save memory and run faster.
* Decode image using calculated sample size.
*/
bfo.inSampleSize = sampleSize;
}
else if( mEventReturnType == EVENT_TYPE_DATA_HANDLE )
{
BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inJustDecodeBounds = false;
Bitmap imageBitmap = BitmapFactory.decodeStream(
cr.openInputStream(pictureUri), null, bfo);

if (imageBitmap != null)
{
// Get the handle of the selected item and post event.
postImagePickerReady(getSelectedImageHandle(imageBitmap));
}
else
bfo.inDither = false;
bfo.inPreferredConfig = Bitmap.Config.ARGB_8888;

try{
Bitmap imageBitmap = BitmapFactory.decodeStream(
cr.openInputStream(pictureUri), null, bfo);

int bytes = imageBitmap.getWidth()*imageBitmap.getHeight()*4;
// Calculate how many bytes our image consists of. Use a different value than 4 if you don't use 32bit images.

int imageData = mMoSyncThread.createDataObject(0, readBytes(pictureUri, bytes));
// Second option would be: ( keep it until final commit)
/**
// Create a new buffer
ByteBuffer buffer = ByteBuffer.allocate(bytes);//400000);
// Move the byte data to the buffer
imageBitmap.copyPixelsToBuffer(buffer);
// Get the underlying array containing the data.
byte[] array = buffer.array(); */

String mimeType = bfo.outMimeType;
int encodingType = -1;
if ( mimeType.equalsIgnoreCase("image/jpeg") )
encodingType = MA_IMAGE_PICKER_ITEM_ENCODING_JPEG;
else if( mimeType.equalsIgnoreCase("image/png") )
encodingType = MA_IMAGE_PICKER_ITEM_ENCODING_PNG;

postImagePickerReady(imageData, encodingType);

} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
} catch (IOException e)
{
Log.i("@@MoSync",
"maImagePickerOpen Error: cannot decode bitmap");
// // TODO Auto-generated catch block
e.printStackTrace();
return;
}

} catch (FileNotFoundException e)
{
e.printStackTrace();
Log.i("@@MoSync",
"maImagePickerOpen Error: cannot find bitmap");
}
}
}

/**
* Get the array of bytes from an image object.
* @param uri The initial uri object.
* @return The array of bytes.
* @throws IOException
*/
public static byte[] readBytes(Uri uri, int maxSize)
throws IOException
{
ContentResolver cr = mMoSyncThread.getActivity().getContentResolver();
// This dynamically extends to take the bytes we read.
InputStream inputStream = cr.openInputStream(uri);
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();

// This is storage overwritten on each iteration with bytes.
// int bufferSize = 1024;
byte[] buffer = new byte[maxSize];

// We need to know how may bytes were read to write them to the byteBuffer.
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
byteBuffer.write(buffer, 0, len);
}

// and then we can return the byte array.
return byteBuffer.toByteArray();
}

/**
* Get the handle of the selected item.
* Further, post it in a EVENT_TYPE_IMAGE_PICKER event.
Expand Down Expand Up @@ -168,13 +275,14 @@ public static void handleCancelSelectPicture()
* Post event to MoSync queue.
* @param imageHandle The image handle of the selected image.
*/
private static void postImagePickerReady(int imageHandle)
private static void postImagePickerReady(int imageHandle, int mimeType)
{
int[] event = new int[3];
int[] event = new int[4];
event[0] = EVENT_TYPE_IMAGE_PICKER;
event[1] = PICKER_READY;
// If Cancel is clicked, the handle is -1.
event[2] = imageHandle;
event[3] = mimeType;

mMoSyncThread.postEvent(event);
}
Expand Down Expand Up @@ -204,4 +312,9 @@ private static void postImagePickerCanceled()
* It has access to the image resource table.
*/
private static Hashtable<Integer, ImageCache> mImageTable;

/**
* The user can choose what kind of data the PICKER_READY event will contain.
*/
private static int mEventReturnType = EVENT_TYPE_IMAGE_HANDLE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,10 @@ public void setCurrentScreen(int handle)
* Internal wrapper for maImagePickerOpen that runs
* the call in the UI thread.
*/
public int maImagePickerOpen()
public int maImagePickerOpen(int eventType)
{
final MoSyncImagePicker imagePicker = new MoSyncImagePicker(mMoSyncThread, mNativeUI.getImageTable());
final MoSyncImagePicker imagePicker = new MoSyncImagePicker(
mMoSyncThread, mNativeUI.getImageTable(), eventType);
getActivity().runOnUiThread(new Runnable() {
public void run()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import static com.mosync.internal.generated.MAAPI_consts.TRANS_ROT270;
import static com.mosync.internal.generated.MAAPI_consts.TRANS_ROT90;
import static com.mosync.internal.generated.MAAPI_consts.EVENT_TYPE_ALERT;
import static com.mosync.internal.generated.MAAPI_consts.MA_IMAGE_PICKER_EVENT_RETURN_TYPE_IMAGE_HANDLE;

import static com.mosync.internal.generated.MAAPI_consts.MA_RESOURCE_OPEN;
import static com.mosync.internal.generated.MAAPI_consts.MA_RESOURCE_CLOSE;
Expand Down Expand Up @@ -3282,7 +3283,18 @@ private void postAlertEvent(int index)
*/
int maImagePickerOpen()
{
return mMoSyncNativeUI.maImagePickerOpen();
return mMoSyncNativeUI.maImagePickerOpen(MA_IMAGE_PICKER_EVENT_RETURN_TYPE_IMAGE_HANDLE);
}

/**
* Displays an image picker to the user and sets the event return type.
* @param eventReturnType One of the next constants:
* - #MA_IMAGE_PICKER_EVENT_RETURN_TYPE_IMAGE_HANDLE
* - #MA_IMAGE_PICKER_EVENT_RETURN_TYPE_IMAGE_DATA
*/
int maImagePickerOpenWithEventReturnType(int eventReturnType)
{
return mMoSyncNativeUI.maImagePickerOpen(eventReturnType);
}

/**
Expand Down
6 changes: 6 additions & 0 deletions testPrograms/ImagePickerTest/.mosyncproject
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
<property key="build.prefs:extra.res.sw/Release" value=""/>
<property key="build.prefs:gcc.warnings/Debug" value="0"/>
<property key="build.prefs:gcc.warnings/Release" value="0"/>
<property key="build.prefs:memory.data/Debug" value="4096"/>
<property key="build.prefs:memory.data/Release" value="4096"/>
<property key="build.prefs:memory.heap/Debug" value="3072"/>
<property key="build.prefs:memory.heap/Release" value="3072"/>
<property key="build.prefs:memory.stack/Debug" value="512"/>
<property key="build.prefs:memory.stack/Release" value="512"/>
<property key="build.prefs:project.type" value=""/>
<property key="dependency.strategy" value="0"/>
<property key="excludes/Debug" value=""/>
Expand Down
Loading

0 comments on commit 203384a

Please sign in to comment.