Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(279)

Side by Side Diff: ui/android/java/src/org/chromium/ui/SelectFileDialog.java

Issue 10916160: Upstreaming SelectFileDialog for Android (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/DEPS ('k') | ui/android/java/src/org/chromium/ui/gfx/NativeWindow.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.ui;
6
7 import android.app.Activity;
8 import android.content.ContentResolver;
9 import android.content.Intent;
10 import android.database.Cursor;
11 import android.net.Uri;
12 import android.os.Environment;
13 import android.provider.MediaStore;
14
15 import java.io.File;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.List;
19
20 import org.chromium.base.CalledByNative;
21 import org.chromium.base.JNINamespace;
22 import org.chromium.ui.gfx.NativeWindow;
23
24 /**
25 * A dialog that is triggered from a file input field that allows a user to sele ct a file based on
26 * a set of accepted file types. The path of the selected file is passed to the native dialog.
27 */
28 @JNINamespace("ui")
29 class SelectFileDialog implements NativeWindow.IntentCallback{
30 // TODO (aurimas): Swap these constants with AppResources when it gets moved to base to support
31 // internationalization.
32 private static final String LOW_MEMORY_ERROR =
33 "Unable to complete previous operation due to low memory";
34 private static final String OPENING_FILE_ERROR = "Failed to open selected fi le";
35
36 private static final String IMAGE_TYPE = "image/";
37 private static final String VIDEO_TYPE = "video/";
38 private static final String AUDIO_TYPE = "audio/";
39 private static final String ALL_IMAGE_TYPES = IMAGE_TYPE + "*";
40 private static final String ALL_VIDEO_TYPES = VIDEO_TYPE + "*";
41 private static final String ALL_AUDIO_TYPES = AUDIO_TYPE + "*";
42 private static final String ANY_TYPES = "*/*";
43 private static final String CAPTURE_CAMERA = "camera";
44 private static final String CAPTURE_CAMCORDER = "camcorder";
45 private static final String CAPTURE_MICROPHONE = "microphone";
46 private static final String CAPTURE_FILESYSTEM = "filesystem";
47 private static final String CAPTURE_IMAGE_DIRECTORY = "browser-photos";
48
49 private final int mNativeSelectFileDialog;
50 private List<String> mFileTypes;
51 private String mCapture; // May be null if no capture parameter was set.
52 private Uri mCameraOutputUri;
53
54 private SelectFileDialog(int nativeSelectFileDialog) {
55 mNativeSelectFileDialog = nativeSelectFileDialog;
56 }
57
58 /**
59 * Creates and starts an intent based on the passed fileTypes and capture va lue.
60 * @param fileTypes MIME types requested (i.e. "image/*")
61 * @param capture The capture value as described in http://www.w3.org/TR/htm l-media-capture/
62 * @param window The NativeWindow that can show intents
63 */
64 @CalledByNative
65 private void selectFile(String[] fileTypes, String capture, NativeWindow win dow) {
66 mFileTypes = new ArrayList<String>(Arrays.asList(fileTypes));
67 mCapture = capture;
68
69 Intent chooser = new Intent(Intent.ACTION_CHOOSER);
70 Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
71 mCameraOutputUri = Uri.fromFile(getFileForImageCapture());
72 camera.putExtra(MediaStore.EXTRA_OUTPUT, mCameraOutputUri);
73 Intent camcorder = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
74 Intent soundRecorder = new Intent(
75 MediaStore.Audio.Media.RECORD_SOUND_ACTION);
76
77 // Quick check - if a capture parameter other than filesystem (the defau lt) is specified we
78 // should just launch the appropriate intent. Otherwise build up a choos er based on the
79 // accept type and then display that to the user.
80 if (captureCamera()) {
81 if (window.showIntent(camera, this, LOW_MEMORY_ERROR)) return;
82 } else if (captureCamcorder()) {
83 if (window.showIntent(camcorder, this, LOW_MEMORY_ERROR)) return;
84 } else if (captureMicrophone()) {
85 if (window.showIntent(soundRecorder, this, LOW_MEMORY_ERROR)) return ;
86 }
87
88 Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT);
89 getContentIntent.addCategory(Intent.CATEGORY_OPENABLE);
90 ArrayList<Intent> extraIntents = new ArrayList<Intent>();
91 if (!noSpecificType()) {
92 // Create a chooser based on the accept type that was specified in t he webpage. Note
93 // that if the web page specified multiple accept types, we will hav e built a generic
94 // chooser above.
95 if (shouldShowImageTypes()) {
96 extraIntents.add(camera);
97 getContentIntent.setType("image/*");
98 } else if (shouldShowVideoTypes()) {
99 extraIntents.add(camcorder);
100 getContentIntent.setType("video/*");
101 } else if (shouldShowAudioTypes()) {
102 extraIntents.add(soundRecorder);
103 getContentIntent.setType("audio/*");
104 }
105 }
106
107 if (extraIntents.isEmpty()) {
108 // We couldn't resolve an accept type, so fallback to a generic choo ser.
109 getContentIntent.setType("*/*");
110 extraIntents.add(camera);
111 extraIntents.add(camcorder);
112 extraIntents.add(soundRecorder);
113 }
114
115 chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS,
116 extraIntents.toArray(new Intent[] { }));
117
118 chooser.putExtra(Intent.EXTRA_INTENT, getContentIntent);
119
120 if (!window.showIntent(chooser, this, LOW_MEMORY_ERROR)) onFileNotSelect ed();
121 }
122
123 /**
124 * Get a file for the image capture in the CAPTURE_IMAGE_DIRECTORY directory .
125 */
126 private File getFileForImageCapture() {
127 File externalDataDir = Environment.getExternalStoragePublicDirectory(
128 Environment.DIRECTORY_DCIM);
129 File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
130 File.separator + CAPTURE_IMAGE_DIRECTORY);
131 if (!cameraDataDir.exists() && !cameraDataDir.mkdirs()) {
132 cameraDataDir = externalDataDir;
133 }
134 File photoFile = new File(cameraDataDir.getAbsolutePath() +
135 File.separator + System.currentTimeMillis() + ".jpg");
136 return photoFile;
137 }
138
139 /**
140 * Callback method to handle the intent results and pass on the path to the native
141 * SelectFileDialog.
142 * @param window The window that has access to the application activity.
143 * @param resultCode The result code whether the intent returned successfull y.
144 * @param contentResolver The content resolver used to extract the path of t he selected file.
145 * @param results The results of the requested intent.
146 */
147 @Override
148 public void onIntentCompleted(NativeWindow window, int resultCode,
149 ContentResolver contentResolver, Intent results) {
150 if (resultCode != Activity.RESULT_OK) {
151 onFileNotSelected();
152 return;
153 }
154 boolean success = false;
155 if (results == null) {
156 // If we have a successful return but no data, then assume this is t he camera returning
157 // the photo that we requested.
158 nativeOnFileSelected(mNativeSelectFileDialog, mCameraOutputUri.getPa th());
159 success = true;
160
161 // Broadcast to the media scanner that there's a new photo on the de vice so it will
162 // show up right away in the gallery (rather than waiting until the next time the media
163 // scanner runs).
164 window.getActivity().sendBroadcast(new Intent(
165 Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mCameraOutputUri));
166 } else {
167 // We get back a content:// URI from the system if the user picked a file from the
168 // gallery. The ContentView has functionality that will convert that content:// URI to
169 // a file path on disk that Chromium understands.
170 Cursor c = contentResolver.query(results.getData(),
171 new String[] { MediaStore.MediaColumns.DATA }, null, null, n ull);
172 if (c != null) {
173 if (c.getCount() == 1) {
174 c.moveToFirst();
175 String path = c.getString(0);
176 if (path != null) {
177 // Not all providers support the MediaStore.DATA column. For example,
178 // Gallery3D (com.android.gallery3d.provider) does not s upport it for
179 // Picasa Web Album images.
180 nativeOnFileSelected(mNativeSelectFileDialog, path);
181 success = true;
182 }
183 }
184 c.close();
185 }
186 }
187 if (!success) {
188 onFileNotSelected();
189 window.showError(OPENING_FILE_ERROR);
190 }
191 }
192
193 private void onFileNotSelected() {
194 nativeOnFileNotSelected(mNativeSelectFileDialog);
195 }
196
197 private boolean noSpecificType() {
198 // We use a single Intent to decide the type of the file chooser we disp lay to the user,
199 // which means we can only give it a single type. If there are multiple accept types
200 // specified, we will fallback to a generic chooser (unless a capture pa rameter has been
201 // specified, in which case we'll try to satisfy that first.
202 return mFileTypes.size() != 1 || mFileTypes.contains(ANY_TYPES);
203 }
204
205 private boolean shouldShowTypes(String allTypes, String specificType) {
206 if (noSpecificType() || mFileTypes.contains(allTypes)) return true;
207 return acceptSpecificType(specificType);
208 }
209
210 private boolean shouldShowImageTypes() {
211 return shouldShowTypes(ALL_IMAGE_TYPES,IMAGE_TYPE);
212 }
213
214 private boolean shouldShowVideoTypes() {
215 return shouldShowTypes(ALL_VIDEO_TYPES, VIDEO_TYPE);
216 }
217
218 private boolean shouldShowAudioTypes() {
219 return shouldShowTypes(ALL_AUDIO_TYPES, AUDIO_TYPE);
220 }
221
222 private boolean captureCamera() {
223 return shouldShowImageTypes() && mCapture != null && mCapture.startsWith (CAPTURE_CAMERA);
224 }
225
226 private boolean captureCamcorder() {
227 return shouldShowVideoTypes() && mCapture != null &&
228 mCapture.startsWith(CAPTURE_CAMCORDER);
229 }
230
231 private boolean captureMicrophone() {
232 return shouldShowAudioTypes() && mCapture != null &&
233 mCapture.startsWith(CAPTURE_MICROPHONE);
234 }
235
236 private boolean captureFilesystem() {
237 return mCapture != null && mCapture.startsWith(CAPTURE_FILESYSTEM);
238 }
239
240 private boolean acceptSpecificType(String accept) {
241 for (String type : mFileTypes) {
242 if (type.startsWith(accept)) {
243 return true;
244 }
245 }
246 return false;
247 }
248
249 @CalledByNative
250 private static SelectFileDialog create(int nativeSelectFileDialog) {
251 return new SelectFileDialog(nativeSelectFileDialog);
252 }
253
254 private native void nativeOnFileSelected(int nativeSelectFileDialogImpl,
255 String filePath);
256 private native void nativeOnFileNotSelected(int nativeSelectFileDialogImpl);
257 }
OLDNEW
« no previous file with comments | « ui/DEPS ('k') | ui/android/java/src/org/chromium/ui/gfx/NativeWindow.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698