AttachmentProvider.java revision 301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10
196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/*
296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * you may not use this file except in compliance with the License.
696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * You may obtain a copy of the License at
796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * See the License for the specific language governing permissions and
1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * limitations under the License.
1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
1796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpackage com.android.email.provider;
1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
19c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport com.android.email.mail.internet.MimeUtility;
2096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
2196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.content.ContentProvider;
227436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Predaimport android.content.ContentResolver;
2396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.content.ContentValues;
2496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.database.Cursor;
2596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.database.MatrixCursor;
2696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase;
2796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.graphics.Bitmap;
2896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.graphics.BitmapFactory;
2996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.net.Uri;
3096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.os.ParcelFileDescriptor;
3196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
32c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.io.File;
33c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.io.FileNotFoundException;
34c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.io.FileOutputStream;
35c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.io.IOException;
36c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.io.InputStream;
37c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadlerimport java.util.List;
3896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
3996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/*
4096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * A simple ContentProvider that allows file access to Email's attachments.
4196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
4296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpublic class AttachmentProvider extends ContentProvider {
43301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler
44301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler    public static final String AUTHORITY = "com.android.email.attachmentprovider";
45301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler    public static final Uri CONTENT_URI = Uri.parse( "content://" + AUTHORITY);
4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
4796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private static final String FORMAT_RAW = "RAW";
4896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private static final String FORMAT_THUMBNAIL = "THUMBNAIL";
4996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
5096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public static class AttachmentProviderColumns {
5196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public static final String _ID = "_id";
5296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public static final String DATA = "_data";
5396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public static final String DISPLAY_NAME = "_display_name";
5496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        public static final String SIZE = "_size";
5596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
5696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
57a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    public static Uri getAttachmentUri(EmailContent.Account account, long id) {
5896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return CONTENT_URI.buildUpon()
5996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(account.getUuid() + ".db")
6096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(Long.toString(id))
6196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(FORMAT_RAW)
6296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .build();
6396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
6496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
65a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank    public static Uri getAttachmentThumbnailUri(EmailContent.Account account, long id,
66c0033f24a26a08c47aa38d957f42cf63cfa3c345Andrew Stadler            int width, int height) {
6796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return CONTENT_URI.buildUpon()
6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(account.getUuid() + ".db")
6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(Long.toString(id))
7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(FORMAT_THUMBNAIL)
7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(Integer.toString(width))
7296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(Integer.toString(height))
7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .build();
7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public static Uri getAttachmentUri(String db, long id) {
7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return CONTENT_URI.buildUpon()
7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(db)
7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(Long.toString(id))
8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .appendPath(FORMAT_RAW)
8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                .build();
8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
8496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
8596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public boolean onCreate() {
8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        /*
8796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project         * We use the cache dir as a temporary directory (since Android doesn't give us one) so
8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project         * on startup we'll clean up any .tmp files from the last run.
8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project         */
9096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        File[] files = getContext().getCacheDir().listFiles();
9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        for (File file : files) {
92aeeefedb43c40e887850654ac88270755f5631c1Mihai Preda            String filename = file.getName();
93aeeefedb43c40e887850654ac88270755f5631c1Mihai Preda            if (filename.endsWith(".tmp") || filename.startsWith("thmb_")) {
9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                file.delete();
9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return true;
9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
9996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
100301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler    /**
101301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * Returns the mime type for a given attachment.  There are three possible results:
102301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     *  - If thumbnail Uri, always returns "image/png" (even if there's no attachment)
103301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     *  - If the attachment does not exist, returns null
104301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     *  - Returns the mime type of the attachment
105301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     */
10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public String getType(Uri uri) {
10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        List<String> segments = uri.getPathSegments();
10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String dbName = segments.get(0);
11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String id = segments.get(1);
11196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String format = segments.get(2);
11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (FORMAT_THUMBNAIL.equals(format)) {
11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return "image/png";
11496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        else {
11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            String path = getContext().getDatabasePath(dbName).getAbsolutePath();
11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            SQLiteDatabase db = null;
11896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            Cursor cursor = null;
11996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            try {
12096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                db = SQLiteDatabase.openDatabase(path, null, 0);
12196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                cursor = db.query(
12296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                        "attachments",
12396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                        new String[] { "mime_type" },
12496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                        "id = ?",
12596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                        new String[] { id },
12696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                        null,
12796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                        null,
12896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                        null);
12996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                cursor.moveToFirst();
13096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                String type = cursor.getString(0);
13196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                cursor.close();
13296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                db.close();
13396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                return type;
13496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
13596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
13696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            finally {
13796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                if (cursor != null) {
13896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    cursor.close();
13996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                }
14096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                if (db != null) {
14196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    db.close();
14296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                }
14396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
14496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
14596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
14696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
14796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
148301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler    /**
149301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * Open an attachment file.  There are two "modes" - "raw", which returns an actual file,
150301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * and "thumbnail", which attempts to generate a thumbnail image.
151301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     *
152301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * Thumbnails are cached for easy space recovery and cleanup.
153301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     *
154301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * TODO:  The thumbnail mode returns null for its failure cases, instead of throwing
155301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * FileNotFoundException, and should be fixed for consistency.
156301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     *
157301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     *  @throws FileNotFoundException
158301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     */
15996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
16096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
16196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        List<String> segments = uri.getPathSegments();
16296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String dbName = segments.get(0);
16396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String id = segments.get(1);
16496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String format = segments.get(2);
16596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (FORMAT_THUMBNAIL.equals(format)) {
16696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            int width = Integer.parseInt(segments.get(3));
16796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            int height = Integer.parseInt(segments.get(4));
16896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            String filename = "thmb_" + dbName + "_" + id;
16996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            File dir = getContext().getCacheDir();
17096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            File file = new File(dir, filename);
17196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (!file.exists()) {
17296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                Uri attachmentUri = getAttachmentUri(dbName, Long.parseLong(id));
1735182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                Cursor c = query(attachmentUri,
1745182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                        new String[] { AttachmentProviderColumns.DATA }, null, null, null);
1755182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                if (c != null) {
1765182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                    try {
1775182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                        if (c.moveToFirst()) {
1785182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                            attachmentUri = Uri.parse(c.getString(0));
1795182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                        }
1805182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                    } finally {
1815182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                        c.close();
1825182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                    }
1835182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                }
1845182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                String type = getContext().getContentResolver().getType(attachmentUri);
18596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                try {
1865182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                    InputStream in =
1875182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                        getContext().getContentResolver().openInputStream(attachmentUri);
18896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    Bitmap thumbnail = createThumbnail(type, in);
1895182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                    thumbnail = Bitmap.createScaledBitmap(thumbnail, width, height, true);
19096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    FileOutputStream out = new FileOutputStream(file);
19196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out);
19296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    out.close();
19396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    in.close();
19496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                }
19596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                catch (IOException ioe) {
19696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    return null;
19796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                }
19896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
19996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
20096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
20196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        else {
20296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return ParcelFileDescriptor.open(
20396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    new File(getContext().getDatabasePath(dbName + "_att"), id),
20496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    ParcelFileDescriptor.MODE_READ_ONLY);
20596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
20696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
20796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
20896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
20996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public int delete(Uri uri, String arg1, String[] arg2) {
21096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return 0;
21196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
21296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
21396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
21496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public Uri insert(Uri uri, ContentValues values) {
21596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return null;
21696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
21796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
218301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler    /**
219301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * Returns a cursor based on the data in the attachments table, or null if the attachment
220301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * is not recorded in the table.
221301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     *
222301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * Supports REST Uri only, for a single row - selection, selection args, and sortOrder are
223301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * ignored (non-null values should probably throw an exception....)
224301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     *
225301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * TODO:  Throws an SQLite exception on a missing DB file (e.g. unknown URI) instead of just
226301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * returning null, as it should.
227301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     */
22896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
22996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
23096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            String sortOrder) {
23196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (projection == null) {
23296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            projection =
23396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                new String[] {
23496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    AttachmentProviderColumns._ID,
23596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    AttachmentProviderColumns.DATA,
23696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    };
23796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
23896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
23996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        List<String> segments = uri.getPathSegments();
24096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String dbName = segments.get(0);
24196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String id = segments.get(1);
24296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String format = segments.get(2);
24396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String path = getContext().getDatabasePath(dbName).getAbsolutePath();
24496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        String name = null;
24596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        int size = -1;
2465182d80674a1ef90586f52355a21a82e8265c10aMihai Preda        String contentUri = null;
24796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        SQLiteDatabase db = null;
24896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Cursor cursor = null;
24996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        try {
25096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            db = SQLiteDatabase.openDatabase(path, null, 0);
25196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            cursor = db.query(
25296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    "attachments",
2535182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                    new String[] { "name", "size", "content_uri" },
25496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    "id = ?",
25596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    new String[] { id },
25696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    null,
25796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    null,
25896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    null);
25996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (!cursor.moveToFirst()) {
26096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                return null;
26196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
26296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            name = cursor.getString(0);
26396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            size = cursor.getInt(1);
2645182d80674a1ef90586f52355a21a82e8265c10aMihai Preda            contentUri = cursor.getString(2);
26596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
26696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        finally {
26796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (cursor != null) {
26896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                cursor.close();
26996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
27096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (db != null) {
27196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                db.close();
27296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
27396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
27496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
27596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MatrixCursor ret = new MatrixCursor(projection);
27696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Object[] values = new Object[projection.length];
27796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        for (int i = 0, count = projection.length; i < count; i++) {
27896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            String column = projection[i];
27996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (AttachmentProviderColumns._ID.equals(column)) {
28096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                values[i] = id;
28196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
28296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            else if (AttachmentProviderColumns.DATA.equals(column)) {
2835182d80674a1ef90586f52355a21a82e8265c10aMihai Preda                values[i] = contentUri;
28496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
28596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            else if (AttachmentProviderColumns.DISPLAY_NAME.equals(column)) {
28696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                values[i] = name;
28796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
28896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            else if (AttachmentProviderColumns.SIZE.equals(column)) {
28996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                values[i] = size;
29096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
29196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
29296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        ret.addRow(values);
29396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return ret;
29496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
29596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
29696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
29796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
29896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return 0;
29996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
30096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
30196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private Bitmap createThumbnail(String type, InputStream data) {
30296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if(MimeUtility.mimeTypeMatches(type, "image/*")) {
30396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return createImageThumbnail(data);
30496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
30596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return null;
30696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
30796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
30896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private Bitmap createImageThumbnail(InputStream data) {
30996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        try {
31096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            Bitmap bitmap = BitmapFactory.decodeStream(data);
31196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return bitmap;
31296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
31396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        catch (OutOfMemoryError oome) {
31496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            /*
31596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project             * Improperly downloaded images, corrupt bitmaps and the like can commonly
31696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project             * cause OOME due to invalid allocation sizes. We're happy with a null bitmap in
31796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project             * that case. If the system is really out of memory we'll know about it soon
31896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project             * enough.
31996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project             */
32096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return null;
32196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
32296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        catch (Exception e) {
32396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return null;
32496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
32596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
3267436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda    /**
327301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * Resolve attachment id to content URI.  Returns the resolved content URI (from the attachment
328301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * DB) or, if not found, simply returns the incoming value.
3297436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda     *
3307436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda     * @param attachmentUri
3317436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda     * @return resolved content URI
332301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     *
333301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * TODO:  Throws an SQLite exception on a missing DB file (e.g. unknown URI) instead of just
334301ac18bb7f211b473c4f6fa6ec9bb276bbc6c10Andrew Stadler     * returning the incoming uri, as it should.
3357436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda     */
3367436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda    public static Uri resolveAttachmentIdToContentUri(ContentResolver resolver, Uri attachmentUri) {
3377436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda        Cursor c = resolver.query(attachmentUri,
3387436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda                new String[] { AttachmentProvider.AttachmentProviderColumns.DATA },
3397436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda                null, null, null);
3407436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda        if (c != null) {
3417436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda            try {
3427436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda                if (c.moveToFirst()) {
3437436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda                    return Uri.parse(c.getString(0));
3447436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda                }
3457436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda            } finally {
3467436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda                c.close();
3477436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda            }
3487436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda        }
3497436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda        return attachmentUri;
3507436601fae756e8bc1f916560a1c2d1f8ce576fcMihai Preda    }
35196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project}
352