| 14792 |
manas |
1 |
/**
|
|
|
2 |
* Copyright 2010-present Facebook.
|
|
|
3 |
*
|
|
|
4 |
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
5 |
* you may not use this file except in compliance with the License.
|
|
|
6 |
* You may obtain a copy of the License at
|
|
|
7 |
*
|
|
|
8 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
9 |
*
|
|
|
10 |
* Unless required by applicable law or agreed to in writing, software
|
|
|
11 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
12 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13 |
* See the License for the specific language governing permissions and
|
|
|
14 |
* limitations under the License.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
package com.facebook;
|
|
|
18 |
|
|
|
19 |
import android.content.Context;
|
|
|
20 |
import android.graphics.Bitmap;
|
|
|
21 |
import android.util.Log;
|
|
|
22 |
import com.facebook.internal.Utility;
|
|
|
23 |
import com.facebook.internal.Validate;
|
|
|
24 |
|
|
|
25 |
import java.io.*;
|
|
|
26 |
import java.net.URLEncoder;
|
|
|
27 |
import java.util.ArrayList;
|
|
|
28 |
import java.util.List;
|
|
|
29 |
import java.util.Map;
|
|
|
30 |
import java.util.UUID;
|
|
|
31 |
|
|
|
32 |
/**
|
|
|
33 |
* <p>This class works in conjunction with {@link NativeAppCallContentProvider} to allow apps to attach binary
|
|
|
34 |
* attachments (e.g., images) to native dialogs launched via the {@link com.facebook.widget.FacebookDialog}
|
|
|
35 |
* class. It stores attachments in temporary files and allows the Facebook application to retrieve them via
|
|
|
36 |
* the content provider.</p>
|
|
|
37 |
*
|
|
|
38 |
* <p>Callers are generally not expected to need to use this class directly;
|
|
|
39 |
* see {@link com.facebook.widget.FacebookDialog.OpenGraphActionDialogBuilder#setImageAttachmentsForObject(String,
|
|
|
40 |
* java.util.List) OpenGraphActionDialogBuilder.setImageAttachmentsForObject} for an example of a function
|
|
|
41 |
* that will accept attachments, attach them to the native dialog call, and add them to the content provider
|
|
|
42 |
* automatically.</p>
|
|
|
43 |
**/
|
|
|
44 |
public final class NativeAppCallAttachmentStore implements NativeAppCallContentProvider.AttachmentDataSource {
|
|
|
45 |
private static final String TAG = NativeAppCallAttachmentStore.class.getName();
|
|
|
46 |
static final String ATTACHMENTS_DIR_NAME = "com.facebook.NativeAppCallAttachmentStore.files";
|
|
|
47 |
private static File attachmentsDirectory;
|
|
|
48 |
|
|
|
49 |
/**
|
|
|
50 |
* Adds a number of bitmap attachments associated with a native app call. The attachments will be
|
|
|
51 |
* served via {@link NativeAppCallContentProvider#openFile(android.net.Uri, String) openFile}.
|
|
|
52 |
*
|
|
|
53 |
* @param context the Context the call is being made from
|
|
|
54 |
* @param callId the unique ID of the call
|
|
|
55 |
* @param imageAttachments a Map of attachment names to Bitmaps; the attachment names will be part of
|
|
|
56 |
* the URI processed by openFile
|
|
|
57 |
* @throws java.io.IOException
|
|
|
58 |
*/
|
|
|
59 |
public void addAttachmentsForCall(Context context, UUID callId, Map<String, Bitmap> imageAttachments) {
|
|
|
60 |
Validate.notNull(context, "context");
|
|
|
61 |
Validate.notNull(callId, "callId");
|
|
|
62 |
Validate.containsNoNulls(imageAttachments.values(), "imageAttachments");
|
|
|
63 |
Validate.containsNoNullOrEmpty(imageAttachments.keySet(), "imageAttachments");
|
|
|
64 |
|
|
|
65 |
addAttachments(context, callId, imageAttachments, new ProcessAttachment<Bitmap>() {
|
|
|
66 |
@Override
|
|
|
67 |
public void processAttachment(Bitmap attachment, File outputFile) throws IOException {
|
|
|
68 |
FileOutputStream outputStream = new FileOutputStream(outputFile);
|
|
|
69 |
try {
|
|
|
70 |
attachment.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
|
|
|
71 |
} finally {
|
|
|
72 |
Utility.closeQuietly(outputStream);
|
|
|
73 |
}
|
|
|
74 |
}
|
|
|
75 |
});
|
|
|
76 |
}
|
|
|
77 |
|
|
|
78 |
/**
|
|
|
79 |
* Adds a number of bitmap/video attachment files associated with a native app call. The attachments will be
|
|
|
80 |
* served via {@link NativeAppCallContentProvider#openFile(android.net.Uri, String) openFile}.
|
|
|
81 |
*
|
|
|
82 |
* @param context the Context the call is being made from
|
|
|
83 |
* @param callId the unique ID of the call
|
|
|
84 |
* @param mediaAttachmentFiles a Map of attachment names to Files containing the bitmaps/videos; the attachment
|
|
|
85 |
* names will be part of the URI processed by openFile
|
|
|
86 |
* @throws java.io.IOException
|
|
|
87 |
*/
|
|
|
88 |
public void addAttachmentFilesForCall(Context context, UUID callId, Map<String, File> mediaAttachmentFiles) {
|
|
|
89 |
Validate.notNull(context, "context");
|
|
|
90 |
Validate.notNull(callId, "callId");
|
|
|
91 |
Validate.containsNoNulls(mediaAttachmentFiles.values(), "mediaAttachmentFiles");
|
|
|
92 |
Validate.containsNoNullOrEmpty(mediaAttachmentFiles.keySet(), "mediaAttachmentFiles");
|
|
|
93 |
|
|
|
94 |
addAttachments(context, callId, mediaAttachmentFiles, new ProcessAttachment<File>() {
|
|
|
95 |
@Override
|
|
|
96 |
public void processAttachment(File attachment, File outputFile) throws IOException {
|
|
|
97 |
FileOutputStream outputStream = new FileOutputStream(outputFile);
|
|
|
98 |
FileInputStream inputStream = null;
|
|
|
99 |
try {
|
|
|
100 |
inputStream = new FileInputStream(attachment);
|
|
|
101 |
|
|
|
102 |
byte[] buffer = new byte[1024];
|
|
|
103 |
int len;
|
|
|
104 |
while ((len = inputStream.read(buffer)) > 0) {
|
|
|
105 |
outputStream.write(buffer, 0, len);
|
|
|
106 |
}
|
|
|
107 |
} finally {
|
|
|
108 |
Utility.closeQuietly(outputStream);
|
|
|
109 |
Utility.closeQuietly(inputStream);
|
|
|
110 |
}
|
|
|
111 |
}
|
|
|
112 |
});
|
|
|
113 |
}
|
|
|
114 |
|
|
|
115 |
private <T> void addAttachments(Context context, UUID callId, Map<String, T> attachments,
|
|
|
116 |
ProcessAttachment<T> processor) {
|
|
|
117 |
if (attachments.size() == 0) {
|
|
|
118 |
return;
|
|
|
119 |
}
|
|
|
120 |
|
|
|
121 |
// If this is the first time we've been instantiated, clean up any existing attachments.
|
|
|
122 |
if (attachmentsDirectory == null) {
|
|
|
123 |
cleanupAllAttachments(context);
|
|
|
124 |
}
|
|
|
125 |
|
|
|
126 |
ensureAttachmentsDirectoryExists(context);
|
|
|
127 |
|
|
|
128 |
List<File> filesToCleanup = new ArrayList<File>();
|
|
|
129 |
|
|
|
130 |
try {
|
|
|
131 |
for (Map.Entry<String, T> entry : attachments.entrySet()) {
|
|
|
132 |
String attachmentName = entry.getKey();
|
|
|
133 |
T attachment = entry.getValue();
|
|
|
134 |
|
|
|
135 |
File file = getAttachmentFile(callId, attachmentName, true);
|
|
|
136 |
filesToCleanup.add(file);
|
|
|
137 |
|
|
|
138 |
processor.processAttachment(attachment, file);
|
|
|
139 |
}
|
|
|
140 |
} catch (IOException exception) {
|
|
|
141 |
Log.e(TAG, "Got unexpected exception:" + exception);
|
|
|
142 |
for (File file : filesToCleanup) {
|
|
|
143 |
try {
|
|
|
144 |
file.delete();
|
|
|
145 |
} catch (Exception e) {
|
|
|
146 |
// Always try to delete other files.
|
|
|
147 |
}
|
|
|
148 |
}
|
|
|
149 |
throw new FacebookException(exception);
|
|
|
150 |
}
|
|
|
151 |
|
|
|
152 |
}
|
|
|
153 |
|
|
|
154 |
interface ProcessAttachment<T> {
|
|
|
155 |
void processAttachment(T attachment, File outputFile) throws IOException;
|
|
|
156 |
}
|
|
|
157 |
|
|
|
158 |
/**
|
|
|
159 |
* Removes any temporary files associated with a particular native app call.
|
|
|
160 |
*
|
|
|
161 |
* @param context the Context the call is being made from
|
|
|
162 |
* @param callId the unique ID of the call
|
|
|
163 |
*/
|
|
|
164 |
public void cleanupAttachmentsForCall(Context context, UUID callId) {
|
|
|
165 |
File dir = getAttachmentsDirectoryForCall(callId, false);
|
|
|
166 |
Utility.deleteDirectory(dir);
|
|
|
167 |
}
|
|
|
168 |
|
|
|
169 |
@Override
|
|
|
170 |
public File openAttachment(UUID callId, String attachmentName) throws FileNotFoundException {
|
|
|
171 |
if (Utility.isNullOrEmpty(attachmentName) ||
|
|
|
172 |
callId == null) {
|
|
|
173 |
throw new FileNotFoundException();
|
|
|
174 |
}
|
|
|
175 |
|
|
|
176 |
try {
|
|
|
177 |
return getAttachmentFile(callId, attachmentName, false);
|
|
|
178 |
} catch (IOException e) {
|
|
|
179 |
// We don't try to create the file, so we shouldn't get any IOExceptions. But if we do, just
|
|
|
180 |
// act like the file wasn't found.
|
|
|
181 |
throw new FileNotFoundException();
|
|
|
182 |
}
|
|
|
183 |
}
|
|
|
184 |
|
|
|
185 |
synchronized static File getAttachmentsDirectory(Context context) {
|
|
|
186 |
if (attachmentsDirectory == null) {
|
|
|
187 |
attachmentsDirectory = new File(context.getCacheDir(), ATTACHMENTS_DIR_NAME);
|
|
|
188 |
}
|
|
|
189 |
return attachmentsDirectory;
|
|
|
190 |
}
|
|
|
191 |
|
|
|
192 |
File ensureAttachmentsDirectoryExists(Context context) {
|
|
|
193 |
File dir = getAttachmentsDirectory(context);
|
|
|
194 |
dir.mkdirs();
|
|
|
195 |
return dir;
|
|
|
196 |
}
|
|
|
197 |
|
|
|
198 |
File getAttachmentsDirectoryForCall(UUID callId, boolean create) {
|
|
|
199 |
if (attachmentsDirectory == null) {
|
|
|
200 |
return null;
|
|
|
201 |
}
|
|
|
202 |
|
|
|
203 |
File dir = new File(attachmentsDirectory, callId.toString());
|
|
|
204 |
if (create && !dir.exists()) {
|
|
|
205 |
dir.mkdirs();
|
|
|
206 |
}
|
|
|
207 |
return dir;
|
|
|
208 |
}
|
|
|
209 |
|
|
|
210 |
File getAttachmentFile(UUID callId, String attachmentName, boolean createDirs) throws IOException {
|
|
|
211 |
File dir = getAttachmentsDirectoryForCall(callId, createDirs);
|
|
|
212 |
if (dir == null) {
|
|
|
213 |
return null;
|
|
|
214 |
}
|
|
|
215 |
|
|
|
216 |
try {
|
|
|
217 |
return new File(dir, URLEncoder.encode(attachmentName, "UTF-8"));
|
|
|
218 |
} catch (UnsupportedEncodingException e) {
|
|
|
219 |
return null;
|
|
|
220 |
}
|
|
|
221 |
}
|
|
|
222 |
|
|
|
223 |
void cleanupAllAttachments(Context context) {
|
|
|
224 |
// Attachments directory may or may not exist; we won't create it if not, since we are just going to delete it.
|
|
|
225 |
File dir = getAttachmentsDirectory(context);
|
|
|
226 |
Utility.deleteDirectory(dir);
|
|
|
227 |
}
|
|
|
228 |
}
|