blob: 5947e4a723d65658a815d94a625dfa94aec06dc2 [file] [log] [blame]
Michael Kolb8233fac2010-10-26 16:08:53 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
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
17package com.android.browser;
18
19import android.app.Activity;
Ben Murdoche4c0cae2011-02-18 11:25:38 +000020import android.content.ActivityNotFoundException;
Michael Kolb8233fac2010-10-26 16:08:53 -070021import android.content.Intent;
22import android.net.Uri;
23import android.os.Environment;
24import android.provider.MediaStore;
25import android.webkit.ValueCallback;
Ben Murdoche4c0cae2011-02-18 11:25:38 +000026import android.widget.Toast;
Michael Kolb8233fac2010-10-26 16:08:53 -070027
28import java.io.File;
29import java.util.Vector;
30
31/**
32 * Handle the file upload callbacks from WebView here
33 */
34public class UploadHandler {
35
36 /*
37 * The Object used to inform the WebView of the file to upload.
38 */
39 private ValueCallback<Uri> mUploadMessage;
40 private String mCameraFilePath;
41
Ben Murdoch51f6a2f2011-02-21 12:27:07 +000042 private boolean mHandled;
43 private boolean mCaughtActivityNotFoundException;
44
Michael Kolb8233fac2010-10-26 16:08:53 -070045 private Controller mController;
46
47 public UploadHandler(Controller controller) {
48 mController = controller;
49 }
50
51 String getFilePath() {
52 return mCameraFilePath;
53 }
54
Ben Murdoch51f6a2f2011-02-21 12:27:07 +000055 boolean handled() {
56 return mHandled;
57 }
58
Michael Kolb8233fac2010-10-26 16:08:53 -070059 void onResult(int resultCode, Intent intent) {
Ben Murdoch51f6a2f2011-02-21 12:27:07 +000060
61 if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
62 // Couldn't resolve an activity, we are going to try again so skip
63 // this result.
64 mCaughtActivityNotFoundException = false;
65 return;
66 }
67
Michael Kolb8233fac2010-10-26 16:08:53 -070068 Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
69 : intent.getData();
70
71 // As we ask the camera to save the result of the user taking
72 // a picture, the camera application does not return anything other
73 // than RESULT_OK. So we need to check whether the file we expected
74 // was written to disk in the in the case that we
75 // did not get an intent returned but did get a RESULT_OK. If it was,
76 // we assume that this result has came back from the camera.
77 if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
78 File cameraFile = new File(mCameraFilePath);
79 if (cameraFile.exists()) {
80 result = Uri.fromFile(cameraFile);
81 // Broadcast to the media scanner that we have a new photo
82 // so it will be added into the gallery for the user.
83 mController.getActivity().sendBroadcast(
84 new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
85 }
86 }
87
88 mUploadMessage.onReceiveValue(result);
Ben Murdoch51f6a2f2011-02-21 12:27:07 +000089 mHandled = true;
90 mCaughtActivityNotFoundException = false;
Michael Kolb8233fac2010-10-26 16:08:53 -070091 }
92
93 void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
94
95 final String imageMimeType = "image/*";
96 final String videoMimeType = "video/*";
97 final String audioMimeType = "audio/*";
98 final String mediaSourceKey = "capture";
99 final String mediaSourceValueCamera = "camera";
100 final String mediaSourceValueFileSystem = "filesystem";
101 final String mediaSourceValueCamcorder = "camcorder";
102 final String mediaSourceValueMicrophone = "microphone";
103
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000104 // According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
105 // or 'microphone'.
Michael Kolb8233fac2010-10-26 16:08:53 -0700106 String mediaSource = "";
107
Michael Kolb8233fac2010-10-26 16:08:53 -0700108 if (mUploadMessage != null) {
109 // Already a file picker operation in progress.
110 return;
111 }
112
113 mUploadMessage = uploadMsg;
114
115 // Parse the accept type.
116 String params[] = acceptType.split(";");
117 String mimeType = params[0];
118
119 for (String p : params) {
120 String[] keyValue = p.split("=");
121 if (keyValue.length == 2) {
122 // Process key=value parameters.
123 if (mediaSourceKey.equals(keyValue[0])) {
124 mediaSource = keyValue[1];
125 }
126 }
127 }
128
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000129 //Ensure it is not still set from a previous upload.
130 mCameraFilePath = null;
131
132 if (mimeType.equals(imageMimeType)) {
133 if (mediaSource.equals(mediaSourceValueCamera)) {
134 // Specified 'image/*' and requested the camera, so go ahead and launch the
135 // camera directly.
136 startActivity(createCameraIntent());
137 return;
138 } else if (mediaSource.equals(mediaSourceValueFileSystem)) {
139 // Specified 'image/*' and requested the filesystem, so go ahead and launch an
140 // OPENABLE intent.
141 startActivity(createOpenableIntent(imageMimeType));
142 return;
143 } else {
144 // Specified just 'image/*', so launch an intent for both the Camera and image/*
145 // OPENABLE.
146 Intent chooser = createChooserIntent(createCameraIntent());
147 chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
148 startActivity(chooser);
149 return;
150 }
151 } else if (mimeType.equals(videoMimeType)) {
152 if (mediaSource.equals(mediaSourceValueCamcorder)) {
153 // Specified 'video/*' and requested the camcorder, so go ahead and launch the
154 // camcorder directly.
155 startActivity(createCamcorderIntent());
156 return;
157 } else if (mediaSource.equals(mediaSourceValueFileSystem)) {
158 // Specified 'video/*' and requested the filesystem, so go ahead and launch an
159 // an OPENABLE intent.
160 startActivity(createOpenableIntent(videoMimeType));
161 return;
162 } else {
163 // Specified just 'video/*', so go ahead and launch an intent for both camcorder and
164 // video/* OPENABLE.
165 Intent chooser = createChooserIntent(createCamcorderIntent());
166 chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
167 startActivity(chooser);
168 return;
169 }
170 } else if (mimeType.equals(audioMimeType)) {
171 if (mediaSource.equals(mediaSourceValueMicrophone)) {
172 // Specified 'audio/*' and requested microphone, so go ahead and launch the sound
173 // recorder.
174 startActivity(createSoundRecorderIntent());
175 return;
176 } else if (mediaSource.equals(mediaSourceValueFileSystem)) {
177 // Specified 'audio/*' and requested filesystem, so go ahead and launch an
178 // OPENABLE intent.
179 startActivity(createOpenableIntent(audioMimeType));
180 return;
181 } else {
182 // Specified just 'audio/*', so go ahead and launch an intent for both the sound
183 // recorder and audio/* OPENABLE.
184 Intent chooser = createChooserIntent(createSoundRecorderIntent());
185 chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
186 startActivity(chooser);
187 return;
188 }
189 }
190
191 // No special handling based on the accept type was necessary, so trigger the default
192 // file upload chooser.
193 startActivity(createDefaultOpenableIntent());
194 }
195
196 private void startActivity(Intent intent) {
197 try {
198 mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
199 } catch (ActivityNotFoundException e) {
200 // No installed app was able to handle the intent that
201 // we sent, so fallback to the default file upload control.
202 try {
Ben Murdoch51f6a2f2011-02-21 12:27:07 +0000203 mCaughtActivityNotFoundException = true;
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000204 mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
205 Controller.FILE_SELECTED);
206 } catch (ActivityNotFoundException e2) {
207 // Nothing can return us a file, so file upload is effectively disabled.
208 Toast.makeText(mController.getActivity(), R.string.uploads_disabled,
209 Toast.LENGTH_LONG).show();
210 }
211 }
212 }
213
214 private Intent createDefaultOpenableIntent() {
215 // Create and return a chooser with the default OPENABLE
216 // actions including the camera, camcorder and sound
217 // recorder where available.
Michael Kolb8233fac2010-10-26 16:08:53 -0700218 Intent i = new Intent(Intent.ACTION_GET_CONTENT);
219 i.addCategory(Intent.CATEGORY_OPENABLE);
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000220 i.setType("*/*");
Michael Kolb8233fac2010-10-26 16:08:53 -0700221
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000222 Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
223 createSoundRecorderIntent());
224 chooser.putExtra(Intent.EXTRA_INTENT, i);
225 return chooser;
226 }
227
228 private Intent createChooserIntent(Intent... intents) {
229 Intent chooser = new Intent(Intent.ACTION_CHOOSER);
230 chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
231 chooser.putExtra(Intent.EXTRA_TITLE,
232 mController.getActivity().getResources()
233 .getString(R.string.choose_upload));
234 return chooser;
235 }
236
237 private Intent createOpenableIntent(String type) {
238 Intent i = new Intent(Intent.ACTION_GET_CONTENT);
239 i.addCategory(Intent.CATEGORY_OPENABLE);
240 i.setType(type);
241 return i;
242 }
243
244 private Intent createCameraIntent() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700245 Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
246 File externalDataDir = Environment.getExternalStoragePublicDirectory(
247 Environment.DIRECTORY_DCIM);
248 File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
249 File.separator + "browser-photos");
250 cameraDataDir.mkdirs();
251 mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
252 System.currentTimeMillis() + ".jpg";
253 cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000254 return cameraIntent;
Michael Kolb8233fac2010-10-26 16:08:53 -0700255 }
256
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000257 private Intent createCamcorderIntent() {
258 return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
259 }
260
261 private Intent createSoundRecorderIntent() {
262 return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
Michael Kolb8233fac2010-10-26 16:08:53 -0700263 }
264
265}