1 // Copyright 2011 Google Inc.
2 // All Rights Reserved.
3 
4 package com.android.mms;
5 
6 import java.io.File;
7 import java.io.FileNotFoundException;
8 
9 import android.content.ContentProvider;
10 import android.content.ContentValues;
11 import android.content.Context;
12 import android.content.UriMatcher;
13 import android.database.Cursor;
14 import android.net.Uri;
15 import android.os.ParcelFileDescriptor;
16 import 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  */
22 public 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
onCreate()37     public boolean onCreate() {
38         return true;
39     }
40 
41     @Override
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)42     public Cursor query(Uri uri, String[] projection,
43             String selection, String[] selectionArgs, String sortOrder) {
44         return null;
45     }
46 
47     @Override
insert(Uri uri, ContentValues values)48     public Uri insert(Uri uri, ContentValues values) {
49         return null;
50     }
51 
52     @Override
delete(Uri uri, String selection, String[] selectionArgs)53     public int delete(Uri uri, String selection, String[] selectionArgs) {
54         return 0;
55     }
56 
57     @Override
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)58     public int update(Uri uri, ContentValues values,
59             String selection, String[] selectionArgs) {
60         return 0;
61     }
62 
getTempStoreFd(String mode)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
getType(Uri uri)95     public String getType(Uri uri) {
96         return "*/*";
97     }
98 
99     @Override
openFile(Uri uri, String mode)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      */
getScrapPath(Context context, String fileName)127     public static String getScrapPath(Context context, String fileName) {
128         return context.getExternalCacheDir().getAbsolutePath() + "/" + fileName;
129     }
130 
getScrapPath(Context context)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      */
renameScrapFile(String fileExtension, String uniqueIdentifier, Context context)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      */
isTempFile(String path)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