2009-03-04 03:32:22 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package com.android.email.provider;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import android.content.ContentProvider;
|
|
|
|
import android.content.ContentValues;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.database.MatrixCursor;
|
|
|
|
import android.database.sqlite.SQLiteDatabase;
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import android.graphics.BitmapFactory;
|
|
|
|
import android.net.Uri;
|
|
|
|
import android.os.ParcelFileDescriptor;
|
|
|
|
import android.provider.OpenableColumns;
|
|
|
|
import android.util.Config;
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
import com.android.email.Account;
|
|
|
|
import com.android.email.Email;
|
|
|
|
import com.android.email.Utility;
|
|
|
|
import com.android.email.mail.internet.MimeUtility;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A simple ContentProvider that allows file access to Email's attachments.
|
|
|
|
*/
|
|
|
|
public class AttachmentProvider extends ContentProvider {
|
|
|
|
public static final Uri CONTENT_URI = Uri.parse( "content://com.android.email.attachmentprovider");
|
|
|
|
|
|
|
|
private static final String FORMAT_RAW = "RAW";
|
|
|
|
private static final String FORMAT_THUMBNAIL = "THUMBNAIL";
|
|
|
|
|
|
|
|
public static class AttachmentProviderColumns {
|
|
|
|
public static final String _ID = "_id";
|
|
|
|
public static final String DATA = "_data";
|
|
|
|
public static final String DISPLAY_NAME = "_display_name";
|
|
|
|
public static final String SIZE = "_size";
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Uri getAttachmentUri(Account account, long id) {
|
|
|
|
return CONTENT_URI.buildUpon()
|
|
|
|
.appendPath(account.getUuid() + ".db")
|
|
|
|
.appendPath(Long.toString(id))
|
|
|
|
.appendPath(FORMAT_RAW)
|
|
|
|
.build();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Uri getAttachmentThumbnailUri(Account account, long id, int width, int height) {
|
|
|
|
return CONTENT_URI.buildUpon()
|
|
|
|
.appendPath(account.getUuid() + ".db")
|
|
|
|
.appendPath(Long.toString(id))
|
|
|
|
.appendPath(FORMAT_THUMBNAIL)
|
|
|
|
.appendPath(Integer.toString(width))
|
|
|
|
.appendPath(Integer.toString(height))
|
|
|
|
.build();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Uri getAttachmentUri(String db, long id) {
|
|
|
|
return CONTENT_URI.buildUpon()
|
|
|
|
.appendPath(db)
|
|
|
|
.appendPath(Long.toString(id))
|
|
|
|
.appendPath(FORMAT_RAW)
|
|
|
|
.build();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onCreate() {
|
|
|
|
/*
|
|
|
|
* We use the cache dir as a temporary directory (since Android doesn't give us one) so
|
|
|
|
* on startup we'll clean up any .tmp files from the last run.
|
|
|
|
*/
|
|
|
|
File[] files = getContext().getCacheDir().listFiles();
|
|
|
|
for (File file : files) {
|
|
|
|
if (file.getName().endsWith(".tmp")) {
|
|
|
|
file.delete();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getType(Uri uri) {
|
|
|
|
List<String> segments = uri.getPathSegments();
|
|
|
|
String dbName = segments.get(0);
|
|
|
|
String id = segments.get(1);
|
|
|
|
String format = segments.get(2);
|
|
|
|
if (FORMAT_THUMBNAIL.equals(format)) {
|
|
|
|
return "image/png";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
String path = getContext().getDatabasePath(dbName).getAbsolutePath();
|
|
|
|
SQLiteDatabase db = null;
|
|
|
|
Cursor cursor = null;
|
|
|
|
try {
|
|
|
|
db = SQLiteDatabase.openDatabase(path, null, 0);
|
|
|
|
cursor = db.query(
|
|
|
|
"attachments",
|
|
|
|
new String[] { "mime_type" },
|
|
|
|
"id = ?",
|
|
|
|
new String[] { id },
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
null);
|
|
|
|
cursor.moveToFirst();
|
|
|
|
String type = cursor.getString(0);
|
|
|
|
cursor.close();
|
|
|
|
db.close();
|
|
|
|
return type;
|
|
|
|
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
if (cursor != null) {
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
if (db != null) {
|
|
|
|
db.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
|
|
|
|
List<String> segments = uri.getPathSegments();
|
|
|
|
String dbName = segments.get(0);
|
|
|
|
String id = segments.get(1);
|
|
|
|
String format = segments.get(2);
|
|
|
|
if (FORMAT_THUMBNAIL.equals(format)) {
|
|
|
|
int width = Integer.parseInt(segments.get(3));
|
|
|
|
int height = Integer.parseInt(segments.get(4));
|
|
|
|
String filename = "thmb_" + dbName + "_" + id;
|
|
|
|
File dir = getContext().getCacheDir();
|
|
|
|
File file = new File(dir, filename);
|
|
|
|
if (!file.exists()) {
|
|
|
|
Uri attachmentUri = getAttachmentUri(dbName, Long.parseLong(id));
|
2009-06-01 18:28:33 +00:00
|
|
|
Cursor c = query(attachmentUri,
|
|
|
|
new String[] { AttachmentProviderColumns.DATA }, null, null, null);
|
|
|
|
if (c != null) {
|
|
|
|
try {
|
|
|
|
if (c.moveToFirst()) {
|
|
|
|
attachmentUri = Uri.parse(c.getString(0));
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
c.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
String type = getContext().getContentResolver().getType(attachmentUri);
|
2009-03-04 03:32:22 +00:00
|
|
|
try {
|
2009-06-01 18:28:33 +00:00
|
|
|
InputStream in =
|
|
|
|
getContext().getContentResolver().openInputStream(attachmentUri);
|
2009-03-04 03:32:22 +00:00
|
|
|
Bitmap thumbnail = createThumbnail(type, in);
|
2009-06-01 18:28:33 +00:00
|
|
|
thumbnail = Bitmap.createScaledBitmap(thumbnail, width, height, true);
|
2009-03-04 03:32:22 +00:00
|
|
|
FileOutputStream out = new FileOutputStream(file);
|
|
|
|
thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out);
|
|
|
|
out.close();
|
|
|
|
in.close();
|
|
|
|
}
|
|
|
|
catch (IOException ioe) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return ParcelFileDescriptor.open(
|
|
|
|
new File(getContext().getDatabasePath(dbName + "_att"), id),
|
|
|
|
ParcelFileDescriptor.MODE_READ_ONLY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int delete(Uri uri, String arg1, String[] arg2) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Uri insert(Uri uri, ContentValues values) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
|
|
|
|
String sortOrder) {
|
|
|
|
if (projection == null) {
|
|
|
|
projection =
|
|
|
|
new String[] {
|
|
|
|
AttachmentProviderColumns._ID,
|
|
|
|
AttachmentProviderColumns.DATA,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
List<String> segments = uri.getPathSegments();
|
|
|
|
String dbName = segments.get(0);
|
|
|
|
String id = segments.get(1);
|
|
|
|
String format = segments.get(2);
|
|
|
|
String path = getContext().getDatabasePath(dbName).getAbsolutePath();
|
|
|
|
String name = null;
|
|
|
|
int size = -1;
|
2009-06-01 18:28:33 +00:00
|
|
|
String contentUri = null;
|
2009-03-04 03:32:22 +00:00
|
|
|
SQLiteDatabase db = null;
|
|
|
|
Cursor cursor = null;
|
|
|
|
try {
|
|
|
|
db = SQLiteDatabase.openDatabase(path, null, 0);
|
|
|
|
cursor = db.query(
|
|
|
|
"attachments",
|
2009-06-01 18:28:33 +00:00
|
|
|
new String[] { "name", "size", "content_uri" },
|
2009-03-04 03:32:22 +00:00
|
|
|
"id = ?",
|
|
|
|
new String[] { id },
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
null);
|
|
|
|
if (!cursor.moveToFirst()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
name = cursor.getString(0);
|
|
|
|
size = cursor.getInt(1);
|
2009-06-01 18:28:33 +00:00
|
|
|
contentUri = cursor.getString(2);
|
2009-03-04 03:32:22 +00:00
|
|
|
}
|
|
|
|
finally {
|
|
|
|
if (cursor != null) {
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
if (db != null) {
|
|
|
|
db.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MatrixCursor ret = new MatrixCursor(projection);
|
|
|
|
Object[] values = new Object[projection.length];
|
|
|
|
for (int i = 0, count = projection.length; i < count; i++) {
|
|
|
|
String column = projection[i];
|
|
|
|
if (AttachmentProviderColumns._ID.equals(column)) {
|
|
|
|
values[i] = id;
|
|
|
|
}
|
|
|
|
else if (AttachmentProviderColumns.DATA.equals(column)) {
|
2009-06-01 18:28:33 +00:00
|
|
|
values[i] = contentUri;
|
2009-03-04 03:32:22 +00:00
|
|
|
}
|
|
|
|
else if (AttachmentProviderColumns.DISPLAY_NAME.equals(column)) {
|
|
|
|
values[i] = name;
|
|
|
|
}
|
|
|
|
else if (AttachmentProviderColumns.SIZE.equals(column)) {
|
|
|
|
values[i] = size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret.addRow(values);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Bitmap createThumbnail(String type, InputStream data) {
|
|
|
|
if(MimeUtility.mimeTypeMatches(type, "image/*")) {
|
|
|
|
return createImageThumbnail(data);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Bitmap createImageThumbnail(InputStream data) {
|
|
|
|
try {
|
|
|
|
Bitmap bitmap = BitmapFactory.decodeStream(data);
|
|
|
|
return bitmap;
|
|
|
|
}
|
|
|
|
catch (OutOfMemoryError oome) {
|
|
|
|
/*
|
|
|
|
* Improperly downloaded images, corrupt bitmaps and the like can commonly
|
|
|
|
* cause OOME due to invalid allocation sizes. We're happy with a null bitmap in
|
|
|
|
* that case. If the system is really out of memory we'll know about it soon
|
|
|
|
* enough.
|
|
|
|
*/
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
catch (Exception e) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|