CameraResultCallback takes URI

* Do not compress camera output
* Handle attachments from content providers
pull/189/head
Alex Baker 10 years ago
parent 1cdd34fa63
commit 0a9083d43a

@ -63,27 +63,6 @@ public class AndroidUtilities {
});
}
/** Read a bitmap from the specified file, scaling if necessary
* Returns null if scaling failed after several tries */
private static final int[] SAMPLE_SIZES = { 1, 2, 4, 6, 8, 10 };
private static final int MAX_DIM = 1024;
public static Bitmap readScaledBitmap(String file) {
Bitmap bitmap = null;
int tries = 0;
BitmapFactory.Options opts = new BitmapFactory.Options();
while((bitmap == null || (bitmap.getWidth() > MAX_DIM || bitmap.getHeight() > MAX_DIM)) && tries < SAMPLE_SIZES.length) {
opts.inSampleSize = SAMPLE_SIZES[tries];
try {
bitmap = BitmapFactory.decodeFile(file, opts);
} catch (OutOfMemoryError e) {
log.error(e.getMessage(), e);
}
tries++;
}
return bitmap;
}
/**
* Start the given intent, handling security exceptions if they arise
* @param request request code. if negative, no request.

@ -6,24 +6,18 @@
package com.todoroo.astrid.data;
import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.text.TextUtils;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.utility.DateUtilities;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tasks.files.FileHelper;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* A model that is synchronized to a remote server and has a remote id
@ -91,35 +85,11 @@ abstract public class RemoteModel extends AbstractModel {
public static class PictureHelper {
public static final String PICTURES_DIRECTORY = "pictures"; //$NON-NLS-1$
public static JSONObject savePictureJson(Context context, Bitmap bitmap) {
public static JSONObject savePictureJson(final Uri uri) {
try {
String name = DateUtilities.now() + ".jpg";
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", name);
jsonObject.put("type", "image/jpeg");
File dir = FileHelper.getExternalFilesDir(context, PICTURES_DIRECTORY);
if (dir != null) {
File file = new File(dir + File.separator + DateUtilities.now() + ".jpg");
if (file.exists()) {
return null;
}
try {
FileOutputStream fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.flush();
fos.close();
jsonObject.put("path", file.getAbsolutePath());
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return jsonObject;
} else {
return null;
}
return new JSONObject() {{
put("uri", uri.toString());
}};
} catch (JSONException e) {
log.error(e.getMessage(), e);
}
@ -131,10 +101,13 @@ abstract public class RemoteModel extends AbstractModel {
if (value == null) {
return null;
}
if (value.contains("path")) {
JSONObject pictureJson = new JSONObject(value);
if (pictureJson.has("path")) {
String path = pictureJson.getString("path");
if (value.contains("uri") || value.contains("path")) {
JSONObject json = new JSONObject(value);
if (json.has("uri")) {
return Uri.parse(json.getString("uri"));
}
if (json.has("path")) {
String path = json.getString("path");
return Uri.fromFile(new File(path));
}
}

@ -1,9 +1,17 @@
package org.tasks.files;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
public class FileHelper {
public static File getExternalFilesDir(Context context, String type) {
@ -14,4 +22,26 @@ public class FileHelper {
return null;
}
public static String getPathFromUri(Activity activity, Uri uri) {
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = activity.managedQuery(uri, projection, null, null, null);
if (cursor != null) {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else {
return uri.getPath();
}
}
public static void copyFile(String from, String to) throws IOException {
FileChannel source = new FileInputStream(from).getChannel();
FileChannel destination = new FileOutputStream(to).getChannel();
destination.transferFrom(source, 0, source.size());
destination.close();
source.close();
}
}

@ -0,0 +1,42 @@
package org.tasks.files;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class ImageHelper {
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap sampleBitmap(String path, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}
}

@ -10,15 +10,12 @@ import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.widget.ArrayAdapter;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import org.slf4j.Logger;
@ -29,6 +26,8 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import static org.tasks.files.FileHelper.getPathFromUri;
public class ActFmCameraModule {
private static final Logger log = LoggerFactory.getLogger(ActFmCameraModule.class);
@ -103,57 +102,28 @@ public class ActFmCameraModule {
}
public interface CameraResultCallback {
public void handleCameraResult(Bitmap bitmap);
}
private static Bitmap bitmapFromUri(Activity activity, Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = activity.managedQuery(uri, projection, null, null, null);
String path;
if(cursor != null) {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
path = cursor.getString(column_index);
} else {
path = uri.getPath();
}
return AndroidUtilities.readScaledBitmap(path);
public void handleCameraResult(Uri uri);
}
public static boolean activityResult(Activity activity, int requestCode, int resultCode, Intent data,
CameraResultCallback cameraResult) {
if(requestCode == ActFmCameraModule.REQUEST_CODE_CAMERA && resultCode == Activity.RESULT_OK) {
Bitmap bitmap;
if (data == null) { // large from camera
if (lastTempFile != null) {
bitmap = bitmapFromUri(activity, Uri.fromFile(lastTempFile));
lastTempFile.deleteOnExit();
lastTempFile = null;
}
else {
bitmap = null;
}
} else {
bitmap = data.getParcelableExtra("data"); //$NON-NLS-1$
}
if(bitmap != null) {
if (lastTempFile != null) {
Uri uri = Uri.fromFile(lastTempFile);
lastTempFile = null;
activity.setResult(Activity.RESULT_OK);
cameraResult.handleCameraResult(bitmap);
cameraResult.handleCameraResult(uri);
}
return true;
} else if(requestCode == ActFmCameraModule.REQUEST_CODE_PICTURE && resultCode == Activity.RESULT_OK) {
Uri uri = data.getData();
Bitmap bitmap = bitmapFromUri(activity, uri);
if(bitmap != null) {
String path = getPathFromUri(activity, uri);
if (new File(path).exists()) {
activity.setResult(Activity.RESULT_OK);
cameraResult.handleCameraResult(bitmap);
cameraResult.handleCameraResult(uri);
}
return true;
}
return false;
}
}

@ -8,7 +8,7 @@ package com.todoroo.astrid.actfm;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.text.TextUtils;
@ -229,7 +229,7 @@ public class TagSettingsActivity extends InjectingActionBarActivity {
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
CameraResultCallback callback = new CameraResultCallback() {
@Override
public void handleCameraResult(Bitmap bitmap) {
public void handleCameraResult(Uri uri) {
log.error("Not expecting this");
}
};

@ -12,7 +12,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@ -90,7 +90,6 @@ import org.tasks.notifications.NotificationManager;
import org.tasks.preferences.ActivityPreferences;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -99,6 +98,9 @@ import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
import static org.tasks.files.FileHelper.copyFile;
import static org.tasks.files.FileHelper.getPathFromUri;
/**
* This activity is responsible for creating new tasks and editing existing
* ones. It saves a task when it is paused (screen rotated, back button pressed)
@ -882,18 +884,13 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
createNewFileAttachment(path, name, type);
}
private void attachImage(Bitmap bitmap) {
private void attachImage(String input) {
AtomicReference<String> nameRef = new AtomicReference<>();
String path = FileUtilities.getNewImageAttachmentPath(preferences, getActivity(), nameRef);
try {
FileOutputStream fos = new FileOutputStream(path);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
createNewFileAttachment(path, nameRef.get(), TaskAttachment.FILE_TYPE_IMAGE + "png");
String path = FileUtilities.getNewImageAttachmentPath(preferences, getActivity(), nameRef);
copyFile(input, path);
String extension = path.substring(path.lastIndexOf('.') + 1);
createNewFileAttachment(path, nameRef.get(), TaskAttachment.FILE_TYPE_IMAGE + extension);
} catch (Exception e) {
log.error(e.getMessage(), e);
Toast.makeText(getActivity(), R.string.file_err_copy, Toast.LENGTH_LONG).show();
@ -997,8 +994,8 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
ActFmCameraModule.activityResult(getActivity(), requestCode, resultCode, data, new CameraResultCallback() {
@Override
public void handleCameraResult(Bitmap bitmap) {
attachImage(bitmap);
public void handleCameraResult(Uri uri) {
attachImage(getPathFromUri(getActivity(), uri));
}
});

@ -32,6 +32,9 @@ import com.todoroo.astrid.data.UserActivity;
import org.tasks.R;
import static org.tasks.files.FileHelper.getPathFromUri;
import static org.tasks.files.ImageHelper.sampleBitmap;
/**
* Adapter for displaying a user's activity
*
@ -177,7 +180,8 @@ public class UpdateAdapter extends CursorAdapter {
final Fragment fragment) {
if (updateBitmap != null) { //$NON-NLS-1$
commentPictureView.setVisibility(View.VISIBLE);
commentPictureView.setImageURI(updateBitmap);
String path = getPathFromUri(fragment.getActivity(), updateBitmap);
commentPictureView.setImageBitmap(sampleBitmap(path, commentPictureView.getLayoutParams().width, commentPictureView.getLayoutParams().height));
view.setOnClickListener(new OnClickListener() {
@Override

@ -8,7 +8,6 @@ package com.todoroo.astrid.notes;
import android.app.Activity;
import android.content.Intent;
import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.support.v4.app.Fragment;
@ -64,6 +63,8 @@ import java.util.LinkedList;
import java.util.List;
import static org.tasks.date.DateTimeUtils.newDate;
import static org.tasks.files.FileHelper.getPathFromUri;
import static org.tasks.files.ImageHelper.sampleBitmap;
public class EditNoteActivity extends LinearLayout implements TimerActionListener {
@ -80,7 +81,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
private View commentButton;
private int commentItems = 10;
private ImageButton pictureButton;
private Bitmap pendingCommentPicture = null;
private Uri pendingCommentPicture = null;
private final Fragment fragment;
private final AstridActivity activity;
@ -248,10 +249,10 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
}
if (activity != null) {
Bitmap bitmap = activity.getIntent().getParcelableExtra(TaskEditFragment.TOKEN_PICTURE_IN_PROGRESS);
if (bitmap != null) {
pendingCommentPicture = bitmap;
pictureButton.setImageBitmap(pendingCommentPicture);
String uri = activity.getIntent().getStringExtra(TaskEditFragment.TOKEN_PICTURE_IN_PROGRESS);
if (uri != null) {
pendingCommentPicture = Uri.parse(uri);
setPictureButtonToPendingPicture();
}
}
}
@ -379,7 +380,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
userActivity.setTargetName(title);
userActivity.setCreatedAt(DateUtilities.now());
if (usePicture && pendingCommentPicture != null) {
JSONObject pictureJson = RemoteModel.PictureHelper.savePictureJson(activity, pendingCommentPicture);
JSONObject pictureJson = RemoteModel.PictureHelper.savePictureJson(pendingCommentPicture);
if (pictureJson != null) {
userActivity.setPicture(pictureJson.toString());
}
@ -485,12 +486,12 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
respondToPicture = false;
CameraResultCallback callback = new CameraResultCallback() {
@Override
public void handleCameraResult(Bitmap bitmap) {
public void handleCameraResult(Uri uri) {
if (activity != null) {
activity.getIntent().putExtra(TaskEditFragment.TOKEN_PICTURE_IN_PROGRESS, bitmap);
activity.getIntent().putExtra(TaskEditFragment.TOKEN_PICTURE_IN_PROGRESS, uri.toString());
}
pendingCommentPicture = bitmap;
pictureButton.setImageBitmap(pendingCommentPicture);
pendingCommentPicture = uri;
setPictureButtonToPendingPicture();
commentField.requestFocus();
}
};
@ -502,4 +503,8 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
}
}
private void setPictureButtonToPendingPicture() {
String path = getPathFromUri(activity, pendingCommentPicture);
pictureButton.setImageBitmap(sampleBitmap(path, pictureButton.getWidth(), pictureButton.getHeight()));
}
}

Loading…
Cancel
Save