1// Copyright 2011 Google Inc.
2// All Rights Reserved.
3
4package com.android.mms;
5
6import java.io.File;
7import java.io.FileNotFoundException;
8
9import android.content.ContentProvider;
10import android.content.ContentValues;
11import android.content.Context;
12import android.content.UriMatcher;
13import android.database.Cursor;
14import android.net.Uri;
15import android.os.ParcelFileDescriptor;
16import android.util.Log;
17
18/**
19 * The TempFileProvider manages a uri, backed by a file, for passing to the camera app for
20 * capturing pictures and videos and storing the data in a file in the messaging app.
21 */
22public class TempFileProvider extends ContentProvider {
23    private static String TAG = LogTag.TAG;
24
25    /**
26     * The content:// style URL for this table
27     */
28    public static final Uri SCRAP_CONTENT_URI = Uri.parse("content://mms_temp_file/scrapSpace");
29
30    private static final int MMS_SCRAP_SPACE = 1;
31    private static final UriMatcher sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH);
32    static {
33        sURLMatcher.addURI("mms_temp_file", "scrapSpace", MMS_SCRAP_SPACE);
34    }
35
36    @Override
37    public boolean onCreate() {
38        return true;
39    }
40
41    @Override
42    public Cursor query(Uri uri, String[] projection,
43            String selection, String[] selectionArgs, String sortOrder) {
44        return null;
45    }
46
47    @Override
48    public Uri insert(Uri uri, ContentValues values) {
49        return null;
50    }
51
52    @Override
53    public int delete(Uri uri, String selection, String[] selectionArgs) {
54        return 0;
55    }
56
57    @Override
58    public int update(Uri uri, ContentValues values,
59            String selection, String[] selectionArgs) {
60        return 0;
61    }
62
63    private ParcelFileDescriptor getTempStoreFd(String mode) {
64        String fileName = getScrapPath(getContext());
65        ParcelFileDescriptor pfd = null;
66
67        try {
68            File file = new File(fileName);
69
70            // make sure the path is valid and directories created for this file.
71            File parentFile = file.getParentFile();
72            if (!parentFile.exists() && !parentFile.mkdirs()) {
73                Log.e(TAG, "[TempFileProvider] tempStoreFd: " + parentFile.getPath() +
74                        "does not exist!");
75                return null;
76            }
77
78            int modeFlags;
79            if (mode.equals("r")) {
80                modeFlags = ParcelFileDescriptor.MODE_READ_ONLY;
81            } else {
82                modeFlags = ParcelFileDescriptor.MODE_READ_WRITE
83                            | ParcelFileDescriptor.MODE_CREATE
84                            | ParcelFileDescriptor.MODE_TRUNCATE;
85            }
86            pfd = ParcelFileDescriptor.open(file, modeFlags);
87        } catch (Exception ex) {
88            Log.e(TAG, "getTempStoreFd: error creating pfd for " + fileName, ex);
89        }
90
91        return pfd;
92    }
93
94    @Override
95    public String getType(Uri uri) {
96        return "*/*";
97    }
98
99    @Override
100    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
101        // if the url is "content://mms/takePictureTempStore", then it means the requester
102        // wants a file descriptor to write image data to.
103
104        ParcelFileDescriptor fd = null;
105        int match = sURLMatcher.match(uri);
106
107        if (Log.isLoggable(TAG, Log.VERBOSE)) {
108            Log.d(TAG, "openFile: uri=" + uri + ", mode=" + mode);
109        }
110
111        switch (match) {
112            case MMS_SCRAP_SPACE:
113                fd = getTempStoreFd(mode);
114                break;
115        }
116
117        return fd;
118    }
119
120
121    /**
122     * This is the scrap file we use to store the media attachment when the user
123     * chooses to capture a photo to be attached . We pass {#link@Uri} to the Camera app,
124     * which streams the captured image to the uri. Internally we write the media content
125     * to this file. It's named '.temp.jpg' so Gallery won't pick it up.
126     */
127    public static String getScrapPath(Context context, String fileName) {
128        return context.getExternalCacheDir().getAbsolutePath() + "/" + fileName;
129    }
130
131    public static String getScrapPath(Context context) {
132        return getScrapPath(context, ".temp.jpg");
133    }
134
135    /**
136     * renameScrapFile renames the single scrap file to a new name so newer uses of the scrap
137     * file won't overwrite the previously captured data.
138     * @param fileExtension file extension for the temp file, typically ".jpg" or ".3gp"
139     * @param uniqueIdentifier a separator to add to the file to make it unique,
140     *        such as the slide number. This parameter can be empty or null.
141     * @return uri of renamed file. If there's an error renaming, null will be returned
142     */
143    public static Uri renameScrapFile(String fileExtension, String uniqueIdentifier,
144            Context context) {
145        String filePath = getScrapPath(context);
146        // There's only a single scrap file, but there can be several slides. We rename
147        // the scrap file to a new scrap file with the slide number as part of the filename.
148
149        // Replace the filename ".temp.jpg" with ".temp#.[jpg | 3gp]" where # is the unique
150        // identifier. The content of the file may be a picture or a .3gp video.
151        if (uniqueIdentifier == null) {
152            uniqueIdentifier = "";
153        }
154        File newTempFile = new File(getScrapPath(context, ".temp" + uniqueIdentifier +
155                fileExtension));
156        File oldTempFile = new File(filePath);
157        // remove any existing file before rename
158        boolean deleted = newTempFile.delete();
159        if (!oldTempFile.renameTo(newTempFile)) {
160            return null;
161        }
162        return Uri.fromFile(newTempFile);
163    }
164
165    /**
166     * Pass in a path to a file and this function will return true if it thinks the path
167     * points to one of its scrap files.
168     * @param path full path of a file
169     * @return true if path is a scrap file path
170     */
171    public static boolean isTempFile(String path) {
172        // An admittedly weak determination of a temp file, but sufficient for current needs.
173        // For now, the penalty of returning true for a file that isn't a temp file is simply
174        // not storing the file's thumbnail in an on-disk thumbnail cache.
175        return path.contains(".temp");
176    }
177}
178