refactor direct capture

Closes #3516
// FREEBIE
This commit is contained in:
Jake McGinty
2015-06-08 11:07:46 -07:00
committed by Moxie Marlinspike
parent c4a37e38ab
commit 54a37cc658
33 changed files with 1720 additions and 1540 deletions

View File

@@ -20,10 +20,10 @@ import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
@@ -38,9 +38,9 @@ import android.widget.Toast;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.ThumbnailView;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.providers.CaptureProvider;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import java.io.File;
import java.io.IOException;
public class AttachmentManager {
@@ -53,7 +53,7 @@ public class AttachmentManager {
private final SlideDeck slideDeck;
private final AttachmentListener attachmentListener;
private File captureFile;
private Uri captureUri;
public AttachmentManager(Activity view, AttachmentListener listener) {
this.attachmentView = view.findViewById(R.id.attachment_editor);
@@ -92,12 +92,12 @@ public class AttachmentManager {
}
public void cleanup() {
if (captureFile != null) captureFile.delete();
captureFile = null;
if (captureUri != null) CaptureProvider.getInstance(context).delete(captureUri);
captureUri = null;
}
public void setImage(Uri image) throws IOException, BitmapDecodingException {
setMedia(new ImageSlide(context, image));
public void setImage(MasterSecret masterSecret, Uri image) throws IOException, BitmapDecodingException {
setMedia(new ImageSlide(context, masterSecret, image), masterSecret);
}
public void setVideo(Uri video) throws IOException, MediaTooLargeException {
@@ -108,20 +108,11 @@ public class AttachmentManager {
setMedia(new AudioSlide(context, audio));
}
public void setEncryptedImage(Uri uri, MasterSecret masterSecret) throws IOException, BitmapDecodingException {
setMedia(new ImageSlide(context, masterSecret, uri), masterSecret);
}
public void setMedia(final Slide slide) {
setMedia(slide, null);
}
public void setMedia(final Slide slide, @Nullable MasterSecret masterSecret) {
Slide thumbnailSlide = slideDeck.getThumbnailSlide(context);
if (thumbnailSlide != null && thumbnailSlide.isEncrypted()) {
Uri dataUri = slideDeck.getThumbnailSlide(context).getPart().getDataUri();
new File(dataUri.getPath()).delete();
}
slideDeck.clear();
slideDeck.addSlide(slide);
attachmentView.setVisibility(View.VISIBLE);
@@ -137,20 +128,11 @@ public class AttachmentManager {
return slideDeck;
}
public File getCaptureFile() {
return captureFile;
}
public void capturePhoto(Activity activity, int requestCode) {
public void setCaptureImage(MasterSecret masterSecret, Bitmap bitmap) {
try {
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (captureIntent.resolveActivity(activity.getPackageManager()) != null) {
captureFile = File.createTempFile(String.valueOf(System.currentTimeMillis()), ".jpg", activity.getExternalFilesDir(null));
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(captureFile));
activity.startActivityForResult(captureIntent, requestCode);
}
} catch (IOException e) {
captureUri = CaptureProvider.getInstance(context).create(masterSecret, bitmap);
setImage(masterSecret, captureUri);
} catch (IOException | BitmapDecodingException e) {
Log.w(TAG, e);
}
}
@@ -204,6 +186,6 @@ public class AttachmentManager {
}
public interface AttachmentListener {
public void onAttachmentChanged();
void onAttachmentChanged();
}
}

View File

@@ -37,7 +37,6 @@ public class AttachmentTypeSelectorAdapter extends ArrayAdapter<AttachmentTypeSe
public static final int ADD_VIDEO = 2;
public static final int ADD_SOUND = 3;
public static final int ADD_CONTACT_INFO = 4;
public static final int TAKE_PHOTO = 5;
private final Context context;
@@ -72,11 +71,10 @@ public class AttachmentTypeSelectorAdapter extends ArrayAdapter<AttachmentTypeSe
private static List<IconListItem> getItemList(Context context) {
List<IconListItem> data = new ArrayList<>(4);
addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_take_photo), ResUtil.getDrawableRes(context, R.attr.conversation_attach_photo), TAKE_PHOTO);
addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_picture), ResUtil.getDrawableRes(context, R.attr.conversation_attach_image), ADD_IMAGE);
addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_video), ResUtil.getDrawableRes(context, R.attr.conversation_attach_video), ADD_VIDEO);
addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_audio), ResUtil.getDrawableRes(context, R.attr.conversation_attach_sound), ADD_SOUND);
addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_contact), ResUtil.getDrawableRes(context, R.attr.conversation_attach_contact_info), ADD_CONTACT_INFO);
addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_picture), ResUtil.getDrawableRes(context, R.attr.conversation_attach_image), ADD_IMAGE);
addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_video), ResUtil.getDrawableRes(context, R.attr.conversation_attach_video), ADD_VIDEO);
addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_audio), ResUtil.getDrawableRes(context, R.attr.conversation_attach_sound), ADD_SOUND);
addItem(data, context.getString(R.string.AttachmentTypeSelectorAdapter_contact), ResUtil.getDrawableRes(context, R.attr.conversation_attach_contact_info), ADD_CONTACT_INFO);
return data;
}

View File

@@ -20,36 +20,25 @@ import android.content.Context;
import android.content.res.Resources.Theme;
import android.net.Uri;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.Util;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import ws.com.google.android.mms.ContentType;
import ws.com.google.android.mms.pdu.PduPart;
public class ImageSlide extends Slide {
private static final String TAG = ImageSlide.class.getSimpleName();
private boolean encrypted = false;
public ImageSlide(Context context, MasterSecret masterSecret, PduPart part) {
super(context, masterSecret, part);
}
public ImageSlide(Context context, Uri uri) throws IOException, BitmapDecodingException {
this(context, null, uri);
}
public ImageSlide(Context context, MasterSecret masterSecret, Uri uri) throws IOException, BitmapDecodingException {
super(context, masterSecret, constructPartFromByteArrayAndUri(uri, decryptContent(uri, masterSecret), masterSecret != null));
encrypted = masterSecret != null;
super(context, masterSecret, constructPartFromUri(uri));
}
@Override
@@ -73,32 +62,12 @@ public class ImageSlide extends Slide {
return true;
}
@Override
public boolean isEncrypted() {
return encrypted;
}
private static byte[] decryptContent(Uri uri, MasterSecret masterSecret) {
try {
if (masterSecret != null) {
InputStream inputStream = new DecryptingPartInputStream(new File(uri.getPath()), masterSecret);
return Util.readFully(inputStream);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static PduPart constructPartFromByteArrayAndUri(Uri uri, @Nullable byte[] data, boolean encrypted)
private static PduPart constructPartFromUri(Uri uri)
throws IOException, BitmapDecodingException
{
PduPart part = new PduPart();
part.setDataUri(uri);
if (data != null)
part.setData(data);
part.setEncrypted(encrypted);
part.setContentType(ContentType.IMAGE_JPEG.getBytes());
part.setContentId((System.currentTimeMillis()+"").getBytes());
part.setName(("Image" + System.currentTimeMillis()).getBytes());

View File

@@ -5,13 +5,12 @@ import android.content.Context;
import android.content.UriMatcher;
import android.net.Uri;
import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.PartDatabase;
import org.thoughtcrime.securesms.providers.CaptureProvider;
import org.thoughtcrime.securesms.providers.PartProvider;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -22,8 +21,9 @@ public class PartAuthority {
private static final Uri PART_CONTENT_URI = Uri.parse(PART_URI_STRING);
private static final Uri THUMB_CONTENT_URI = Uri.parse(THUMB_URI_STRING);
private static final int PART_ROW = 1;
private static final int THUMB_ROW = 2;
private static final int PART_ROW = 1;
private static final int THUMB_ROW = 2;
private static final int CAPTURE_ROW = 3;
private static final UriMatcher uriMatcher;
@@ -31,28 +31,25 @@ public class PartAuthority {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("org.thoughtcrime.securesms", "part/*/#", PART_ROW);
uriMatcher.addURI("org.thoughtcrime.securesms", "thumb/*/#", THUMB_ROW);
uriMatcher.addURI(CaptureProvider.AUTHORITY, CaptureProvider.EXPECTED_PATH, CAPTURE_ROW);
}
public static InputStream getPartStream(Context context, MasterSecret masterSecret, Uri uri)
throws IOException
{
PartDatabase partDatabase = DatabaseFactory.getPartDatabase(context);
int match = uriMatcher.match(uri);
int match = uriMatcher.match(uri);
try {
switch (match) {
case PART_ROW:
PartUriParser partUri = new PartUriParser(uri);
return partDatabase.getPartStream(masterSecret, partUri.getPartId());
return DatabaseFactory.getPartDatabase(context).getPartStream(masterSecret, partUri.getPartId());
case THUMB_ROW:
partUri = new PartUriParser(uri);
return partDatabase.getThumbnailStream(masterSecret, partUri.getPartId());
return DatabaseFactory.getPartDatabase(context).getThumbnailStream(masterSecret, partUri.getPartId());
case CAPTURE_ROW:
return CaptureProvider.getInstance(context).getStream(masterSecret, ContentUris.parseId(uri));
default:
String tempMediaDir = context.getDir("media", Context.MODE_PRIVATE).getPath();
if (uri.getPath().startsWith(tempMediaDir))
return new DecryptingPartInputStream(new File(uri.getPath()), masterSecret);
else
return context.getContentResolver().openInputStream(uri);
return context.getContentResolver().openInputStream(uri);
}
} catch (SecurityException se) {
throw new IOException(se);

View File

@@ -66,10 +66,6 @@ public abstract class Slide {
return false;
}
public boolean isEncrypted() {
return false;
}
public PduPart getPart() {
return part;
}