Implemented AttachmentProvider, removed ContentAttachment.getUri()

This commit is contained in:
str4d
2014-12-29 10:50:04 +00:00
parent 60615829da
commit 95b5e6684b
8 changed files with 327 additions and 84 deletions

View File

@@ -1,87 +1,92 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest
package="i2p.bote.android" > package="i2p.bote.android"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.NFC"/>
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/Theme.Bote" > android:theme="@style/Theme.Bote">
<service android:name=".service.BoteService" /> <service android:name=".service.BoteService"/>
<activity <activity
android:name=".EmailListActivity" android:name=".EmailListActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTop" > android:launchMode="singleTop">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".intro.IntroActivity" android:name=".intro.IntroActivity"
android:parentActivityName=".EmailListActivity" > android:parentActivityName=".EmailListActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.EmailListActivity" /> android:value="i2p.bote.android.EmailListActivity"/>
</activity> </activity>
<activity <activity
android:name=".intro.SetupActivity" android:name=".intro.SetupActivity"
android:label="@string/title_activity_setup" android:label="@string/title_activity_setup"
android:parentActivityName=".EmailListActivity" > android:parentActivityName=".EmailListActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.EmailListActivity" /> android:value="i2p.bote.android.EmailListActivity"/>
</activity> </activity>
<activity <activity
android:name=".ViewEmailActivity" android:name=".ViewEmailActivity"
android:parentActivityName=".EmailListActivity" > android:parentActivityName=".EmailListActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.EmailListActivity" /> android:value="i2p.bote.android.EmailListActivity"/>
</activity> </activity>
<activity <activity
android:name=".NewEmailActivity" android:name=".NewEmailActivity"
android:label="@string/compose" android:label="@string/compose"
android:parentActivityName=".EmailListActivity" > android:parentActivityName=".EmailListActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.EmailListActivity" /> android:value="i2p.bote.android.EmailListActivity"/>
</activity> </activity>
<activity <activity
android:name=".addressbook.AddressBookActivity" android:name=".addressbook.AddressBookActivity"
android:label="@string/address_book" android:label="@string/address_book"
android:parentActivityName=".EmailListActivity" > android:parentActivityName=".EmailListActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.EmailListActivity" /> android:value="i2p.bote.android.EmailListActivity"/>
</activity> </activity>
<activity <activity
android:name=".addressbook.ViewContactActivity" android:name=".addressbook.ViewContactActivity"
android:parentActivityName=".addressbook.AddressBookActivity" > android:parentActivityName=".addressbook.AddressBookActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.addressbook.AddressBookActivity" /> android:value="i2p.bote.android.addressbook.AddressBookActivity"/>
</activity> </activity>
<activity <activity
android:name=".addressbook.EditContactActivity" android:name=".addressbook.EditContactActivity"
android:label="@string/action_new_contact" android:label="@string/action_new_contact"
android:parentActivityName=".addressbook.ViewContactActivity" > android:parentActivityName=".addressbook.ViewContactActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.addressbook.ViewContactActivity" /> android:value="i2p.bote.android.addressbook.ViewContactActivity"/>
<intent-filter> <intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" /> <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="vnd.android.nfc" <category android:name="android.intent.category.DEFAULT"/>
<data
android:host="ext" android:host="ext"
android:pathPrefix="/i2p.bote:contact"/> android:pathPrefix="/i2p.bote:contact"
android:scheme="vnd.android.nfc"/>
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/> <action android:name="android.nfc.action.TAG_DISCOVERED"/>
@@ -90,49 +95,57 @@
<activity <activity
android:name=".NetworkInfoActivity" android:name=".NetworkInfoActivity"
android:label="@string/network_status" android:label="@string/network_status"
android:parentActivityName=".EmailListActivity" > android:parentActivityName=".EmailListActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.EmailListActivity" /> android:value="i2p.bote.android.EmailListActivity"/>
</activity> </activity>
<activity <activity
android:name=".config.SettingsActivity" android:name=".config.SettingsActivity"
android:label="@string/action_settings" android:label="@string/action_settings"
android:parentActivityName=".EmailListActivity" > android:parentActivityName=".EmailListActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.EmailListActivity" /> android:value="i2p.bote.android.EmailListActivity"/>
</activity> </activity>
<activity <activity
android:name=".config.SetPasswordActivity" android:name=".config.SetPasswordActivity"
android:label="@string/pref_title_change_password" android:label="@string/pref_title_change_password"
android:parentActivityName=".config.SettingsActivity" > android:parentActivityName=".config.SettingsActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.config.SettingsActivity" /> android:value="i2p.bote.android.config.SettingsActivity"/>
</activity> </activity>
<activity <activity
android:name=".config.ViewIdentityActivity" android:name=".config.ViewIdentityActivity"
android:parentActivityName=".config.SettingsActivity" > android:parentActivityName=".config.SettingsActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.config.SettingsActivity" /> android:value="i2p.bote.android.config.SettingsActivity"/>
</activity> </activity>
<activity <activity
android:name=".config.EditIdentityActivity" android:name=".config.EditIdentityActivity"
android:label="@string/title_new_identity" android:label="@string/title_new_identity"
android:parentActivityName=".config.ViewIdentityActivity" > android:parentActivityName=".config.ViewIdentityActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.config.ViewIdentityActivity" /> android:value="i2p.bote.android.config.ViewIdentityActivity"/>
</activity> </activity>
<activity <activity
android:name=".config.IdentityShipActivity" android:name=".config.IdentityShipActivity"
android:parentActivityName=".config.SettingsActivity" > android:parentActivityName=".config.SettingsActivity">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="i2p.bote.android.config.SettingsActivity" /> android:value="i2p.bote.android.config.SettingsActivity"/>
</activity> </activity>
<provider
android:name=".provider.AttachmentProvider"
android:authorities="${applicationId}.attachmentprovider"
android:enabled="true"
android:exported="false"
android:grantUriPermissions="true">
</provider>
</application> </application>
</manifest> </manifest>

View File

@@ -117,8 +117,7 @@ public class EmailListAdapter extends ArrayAdapter<Email> {
List<Part> parts = email.getParts(); List<Part> parts = email.getParts();
for (Part part : parts) { for (Part part : parts) {
if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) { if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
((ImageView) v.findViewById( v.findViewById(R.id.email_attachment).setVisibility(View.VISIBLE);
R.id.email_attachment)).setVisibility(View.VISIBLE);
break; break;
} }
} }

View File

@@ -339,6 +339,10 @@ public class EmailListFragment extends AuthenticatedListFragment implements
for (int i = (toDelete.size() - 1); i >= 0; i--) { for (int i = (toDelete.size() - 1); i >= 0; i--) {
if (toDelete.valueAt(i)) { if (toDelete.valueAt(i)) {
Email email = (Email) listView.getItemAtPosition(toDelete.keyAt(i)); Email email = (Email) listView.getItemAtPosition(toDelete.keyAt(i));
BoteHelper.revokeAttachmentUriPermissions(
getActivity(),
mFolder.getName(),
email);
// The Loader will update mAdapter // The Loader will update mAdapter
I2PBote.getInstance().deleteEmail(mFolder, email.getMessageID()); I2PBote.getInstance().deleteEmail(mFolder, email.getMessageID());
} }

View File

@@ -444,11 +444,11 @@ public class NewEmailFragment extends Fragment {
private void addAttachment(Uri uri) { private void addAttachment(Uri uri) {
// Try to create a ContentAttachment using the provided Uri. // Try to create a ContentAttachment using the provided Uri.
try { try {
final ContentAttachment attachment = new ContentAttachment(getActivity().getContentResolver(), uri); final ContentAttachment attachment = new ContentAttachment(getActivity(), uri);
final View v = getActivity().getLayoutInflater().inflate(R.layout.listitem_attachment, mAttachments, false); final View v = getActivity().getLayoutInflater().inflate(R.layout.listitem_attachment, mAttachments, false);
v.setTag(attachment); v.setTag(attachment);
((TextView) v.findViewById(R.id.filename)).setText(attachment.getFileName()); ((TextView) v.findViewById(R.id.filename)).setText(attachment.getFileName());
((TextView) v.findViewById(R.id.size)).setText(attachment.getHumanReadableSize(getActivity())); ((TextView) v.findViewById(R.id.size)).setText(attachment.getHumanReadableSize());
v.findViewById(R.id.remove_attachment).setOnClickListener(new View.OnClickListener() { v.findViewById(R.id.remove_attachment).setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {

View File

@@ -26,6 +26,7 @@ import javax.mail.Address;
import javax.mail.MessagingException; import javax.mail.MessagingException;
import javax.mail.Part; import javax.mail.Part;
import i2p.bote.android.provider.AttachmentProvider;
import i2p.bote.android.util.BoteHelper; import i2p.bote.android.util.BoteHelper;
import i2p.bote.android.util.ContentAttachment; import i2p.bote.android.util.ContentAttachment;
import i2p.bote.email.Email; import i2p.bote.email.Email;
@@ -168,15 +169,17 @@ public class ViewEmailFragment extends Fragment {
for (int partIndex=0; partIndex < parts.size(); partIndex++) { for (int partIndex=0; partIndex < parts.size(); partIndex++) {
Part part = parts.get(partIndex); Part part = parts.get(partIndex);
if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) { if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
ContentAttachment attachment = new ContentAttachment(part); ContentAttachment attachment = new ContentAttachment(getActivity(), part);
View a = getActivity().getLayoutInflater().inflate(R.layout.listitem_attachment, attachments, false); View a = getActivity().getLayoutInflater().inflate(R.layout.listitem_attachment, attachments, false);
((TextView)a.findViewById(R.id.filename)).setText(attachment.getFileName()); ((TextView)a.findViewById(R.id.filename)).setText(attachment.getFileName());
((TextView)a.findViewById(R.id.size)).setText(attachment.getHumanReadableSize(getActivity())); ((TextView)a.findViewById(R.id.size)).setText(attachment.getHumanReadableSize());
a.findViewById(R.id.remove_attachment).setVisibility(View.GONE); a.findViewById(R.id.remove_attachment).setVisibility(View.GONE);
final Intent i = new Intent(Intent.ACTION_VIEW); final Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(attachment.getUri()); i.setData(AttachmentProvider.getUriForAttachment(mFolderName, mMessageId, partIndex));
i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
a.setOnClickListener(new View.OnClickListener() { a.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {

View File

@@ -0,0 +1,208 @@
package i2p.bote.android.provider;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns;
import android.util.Log;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import javax.mail.MessagingException;
import javax.mail.Part;
import i2p.bote.Util;
import i2p.bote.android.BuildConfig;
import i2p.bote.android.util.BoteHelper;
import i2p.bote.email.Email;
import i2p.bote.fileencryption.PasswordException;
public class AttachmentProvider extends ContentProvider {
public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".attachmentprovider";
private static final int RAW_ATTACHMENT = 1;
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sUriMatcher.addURI(AUTHORITY, "*/*/#/RAW", RAW_ATTACHMENT);
}
private final static String[] OPENABLE_PROJECTION = {
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
public static Uri getUriForAttachment(String folderName, String messageId, int partNum) {
return new Uri.Builder()
.scheme("content")
.authority(AUTHORITY)
.appendPath(folderName)
.appendPath(messageId)
.appendPath(Integer.toString(partNum))
.appendPath("RAW")
.build();
}
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
if (sUriMatcher.match(uri) == UriMatcher.NO_MATCH)
throw new IllegalArgumentException("Invalid URI: " + uri);
if (projection == null) {
projection = OPENABLE_PROJECTION;
}
final MatrixCursor cursor = new MatrixCursor(projection, 1);
MatrixCursor.RowBuilder b = cursor.newRow();
try {
Part attachment = getAttachment(uri);
if (attachment != null) {
for (String col : projection) {
switch (col) {
case OpenableColumns.DISPLAY_NAME:
b.add(attachment.getFileName());
break;
case OpenableColumns.SIZE:
b.add(Util.getPartSize(attachment));
break;
default:
b.add(null);
break;
}
}
}
} catch (PasswordException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
}
return cursor;
}
@Override
public String getType(Uri uri) {
System.out.println("getType(): URI: " + uri);
System.out.println("Match: " + sUriMatcher.match(uri));
if (sUriMatcher.match(uri) != UriMatcher.NO_MATCH) {
try {
Part attachment = getAttachment(uri);
if (attachment != null) {
System.out.println("Content type: " + attachment.getContentType());
return attachment.getContentType();
}
} catch (PasswordException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
if (sUriMatcher.match(uri) == UriMatcher.NO_MATCH)
throw new FileNotFoundException("Invalid URI: " + uri);
if (!"r".equals(mode))
throw new FileNotFoundException("Attachments can only be read");
ParcelFileDescriptor[] pipe;
try {
pipe = ParcelFileDescriptor.createPipe();
} catch (IOException e) {
Log.e(getClass().getSimpleName(), "Exception opening pipe", e);
throw new FileNotFoundException("Could not open pipe for: "
+ uri.toString());
}
try {
Part attachment = getAttachment(uri);
if (attachment == null)
throw new FileNotFoundException("Unknown email or attachment for URI " + uri);
new TransferThread(attachment.getInputStream(),
new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1])).start();
} catch (Exception e) {
Log.e(getClass().getSimpleName(), "Exception accessing attachment", e);
throw new FileNotFoundException("Exception accessing attachment: " + e.getLocalizedMessage());
}
return pipe[0];
}
static class TransferThread extends Thread {
InputStream in;
OutputStream out;
TransferThread(InputStream in, OutputStream out) {
this.in = in;
this.out = out;
}
@Override
public void run() {
byte[] buf = new byte[8192];
int len;
try {
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.flush();
out.close();
} catch (IOException e) {
Log.e(getClass().getSimpleName(), "Exception transferring file", e);
}
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// Copied from ContentProvider
return uri.buildUpon().appendPath("0").build();
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
private Part getAttachment(Uri uri) throws PasswordException, IOException, MessagingException {
List<String> segments = uri.getPathSegments();
String folderName = segments.get(0);
String messageId = segments.get(1);
int partNum = Integer.valueOf(segments.get(2));
Email email = BoteHelper.getEmail(folderName, messageId);
if (email != null) {
if (partNum >= 0 && partNum < email.getParts().size())
return email.getParts().get(partNum);
}
return null;
}
}

View File

@@ -4,12 +4,14 @@ import android.app.AlertDialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat; import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -29,8 +31,10 @@ import java.util.List;
import javax.mail.Address; import javax.mail.Address;
import javax.mail.MessagingException; import javax.mail.MessagingException;
import javax.mail.Part;
import i2p.bote.android.R; import i2p.bote.android.R;
import i2p.bote.android.provider.AttachmentProvider;
import i2p.bote.email.Email; import i2p.bote.email.Email;
import i2p.bote.email.EmailDestination; import i2p.bote.email.EmailDestination;
import i2p.bote.email.EmailIdentity; import i2p.bote.email.EmailIdentity;
@@ -415,4 +419,36 @@ public class BoteHelper extends GeneralHelper {
} }
return builder.toString(); return builder.toString();
} }
/**
* Attempt to revoke any URI permissions that were granted on an Email's attachments.
* This is best-effort; exceptions are silently ignored.
*
* @param context the Context in which permissions were granted
* @param folderName where the Email is
* @param email the Email to revoke permissions for
*/
public static void revokeAttachmentUriPermissions(Context context, String folderName, Email email) {
List<Part> parts;
try {
parts = email.getParts();
} catch (Exception e) {
// Nothing we can do, abort
return;
}
for (Part part : parts) {
try {
if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
Uri uri = AttachmentProvider.getUriForAttachment(folderName,
email.getMessageID(), parts.indexOf(part));
context.revokeUriPermission(uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
} catch (MessagingException e) {
// Ignore and carry on
}
}
}
} }

View File

@@ -4,12 +4,8 @@ import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns; import android.provider.OpenableColumns;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -23,22 +19,19 @@ import javax.mail.MessagingException;
import javax.mail.Part; import javax.mail.Part;
import i2p.bote.Util; import i2p.bote.Util;
import i2p.bote.android.Constants;
import i2p.bote.android.R; import i2p.bote.android.R;
import i2p.bote.email.Attachment; import i2p.bote.email.Attachment;
public class ContentAttachment implements Attachment { public class ContentAttachment implements Attachment {
private ParcelFileDescriptor mAttachmentPFD; private Context mCtx;
private String mFileName; private String mFileName;
private long mSize; private long mSize;
private DataHandler mDataHandler; private DataHandler mDataHandler;
private Uri mUri;
public ContentAttachment(ContentResolver cr, Uri uri) throws FileNotFoundException { public ContentAttachment(Context context, final Uri uri) throws FileNotFoundException {
// Get the content resolver instance for this context, and use it mCtx = context;
// to get a ParcelFileDescriptor for the file. // Get the content resolver instance for this context
mAttachmentPFD = cr.openFileDescriptor(uri, "r"); ContentResolver cr = context.getContentResolver();
// If we get to here, the file exists
Cursor returnCursor = cr.query( Cursor returnCursor = cr.query(
uri, uri,
@@ -46,18 +39,19 @@ public class ContentAttachment implements Attachment {
null, null, null); null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE); int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
if (!returnCursor.moveToFirst())
throw new FileNotFoundException();
mFileName = returnCursor.getString(nameIndex); mFileName = returnCursor.getString(nameIndex);
mSize = returnCursor.getLong(sizeIndex); mSize = returnCursor.getLong(sizeIndex);
returnCursor.close(); returnCursor.close();
// Get a regular file descriptor for the file
final FileDescriptor fd = mAttachmentPFD.getFileDescriptor();
final String mimeType = cr.getType(uri); final String mimeType = cr.getType(uri);
mDataHandler = new DataHandler(new DataSource() { mDataHandler = new DataHandler(new DataSource() {
@Override @Override
public InputStream getInputStream() throws IOException { public InputStream getInputStream() throws IOException {
return new FileInputStream(fd); return mCtx.getContentResolver().openInputStream(uri);
} }
@Override @Override
@@ -75,15 +69,14 @@ public class ContentAttachment implements Attachment {
return mFileName; return mFileName;
} }
}); });
// mUri is not set here because uri is only usable by us.
// Viewing attachments is only allowed once the email has been created.
} }
public ContentAttachment(final Part part) throws IOException, MessagingException { public ContentAttachment(Context context, Part part)
throws IOException, MessagingException {
mCtx = context;
mFileName = part.getFileName(); mFileName = part.getFileName();
mSize = Util.getPartSize(part); mSize = Util.getPartSize(part);
mDataHandler = part.getDataHandler(); mDataHandler = part.getDataHandler();
// TODO: Set mUri
} }
@Override @Override
@@ -95,7 +88,7 @@ public class ContentAttachment implements Attachment {
return mSize; return mSize;
} }
public String getHumanReadableSize(Context context) { public String getHumanReadableSize() {
int unit = (63-Long.numberOfLeadingZeros(mSize)) / 10; // 0 if totalBytes<1K, 1 if 1K<=totalBytes<1M, etc. int unit = (63-Long.numberOfLeadingZeros(mSize)) / 10; // 0 if totalBytes<1K, 1 if 1K<=totalBytes<1M, etc.
double value = (double)mSize / (1<<(10*unit)); double value = (double)mSize / (1<<(10*unit));
int formatStr; int formatStr;
@@ -109,7 +102,7 @@ public class ContentAttachment implements Attachment {
formatter.setMaximumFractionDigits(1); formatter.setMaximumFractionDigits(1);
else else
formatter.setMaximumFractionDigits(0); formatter.setMaximumFractionDigits(0);
return context.getString(formatStr, formatter.format(value)); return mCtx.getString(formatStr, formatter.format(value));
} }
@Override @Override
@@ -117,21 +110,8 @@ public class ContentAttachment implements Attachment {
return mDataHandler; return mDataHandler;
} }
public Uri getUri() {
return mUri;
}
@Override @Override
public boolean clean() { public boolean clean() {
if (mAttachmentPFD == null) return true;
return true;
try {
mAttachmentPFD.close();
return true;
} catch (IOException e) {
Log.e(Constants.ANDROID_LOG_TAG, "Can't close ParcelFileDescriptor: <" + mFileName + ">", e);
return false;
}
} }
} }