blob: ee578fa4ed0cdf1b1611d11c2ed94c7ddb207de4 [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
42 private Controller mController;
43
44 public UploadHandler(Controller controller) {
45 mController = controller;
46 }
47
48 String getFilePath() {
49 return mCameraFilePath;
50 }
51
52 void onResult(int resultCode, Intent intent) {
53 Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
54 : intent.getData();
55
56 // As we ask the camera to save the result of the user taking
57 // a picture, the camera application does not return anything other
58 // than RESULT_OK. So we need to check whether the file we expected
59 // was written to disk in the in the case that we
60 // did not get an intent returned but did get a RESULT_OK. If it was,
61 // we assume that this result has came back from the camera.
62 if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
63 File cameraFile = new File(mCameraFilePath);
64 if (cameraFile.exists()) {
65 result = Uri.fromFile(cameraFile);
66 // Broadcast to the media scanner that we have a new photo
67 // so it will be added into the gallery for the user.
68 mController.getActivity().sendBroadcast(
69 new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
70 }
71 }
72
73 mUploadMessage.onReceiveValue(result);
74 }
75
76 void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
77
78 final String imageMimeType = "image/*";
79 final String videoMimeType = "video/*";
80 final String audioMimeType = "audio/*";
81 final String mediaSourceKey = "capture";
82 final String mediaSourceValueCamera = "camera";
83 final String mediaSourceValueFileSystem = "filesystem";
84 final String mediaSourceValueCamcorder = "camcorder";
85 final String mediaSourceValueMicrophone = "microphone";
86
Ben Murdoche4c0cae2011-02-18 11:25:38 +000087 // According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
88 // or 'microphone'.
Michael Kolb8233fac2010-10-26 16:08:53 -070089 String mediaSource = "";
90
Michael Kolb8233fac2010-10-26 16:08:53 -070091 if (mUploadMessage != null) {
92 // Already a file picker operation in progress.
93 return;
94 }
95
96 mUploadMessage = uploadMsg;
97
98 // Parse the accept type.
99 String params[] = acceptType.split(";");
100 String mimeType = params[0];
101
102 for (String p : params) {
103 String[] keyValue = p.split("=");
104 if (keyValue.length == 2) {
105 // Process key=value parameters.
106 if (mediaSourceKey.equals(keyValue[0])) {
107 mediaSource = keyValue[1];
108 }
109 }
110 }
111
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000112 //Ensure it is not still set from a previous upload.
113 mCameraFilePath = null;
114
115 if (mimeType.equals(imageMimeType)) {
116 if (mediaSource.equals(mediaSourceValueCamera)) {
117 // Specified 'image/*' and requested the camera, so go ahead and launch the
118 // camera directly.
119 startActivity(createCameraIntent());
120 return;
121 } else if (mediaSource.equals(mediaSourceValueFileSystem)) {
122 // Specified 'image/*' and requested the filesystem, so go ahead and launch an
123 // OPENABLE intent.
124 startActivity(createOpenableIntent(imageMimeType));
125 return;
126 } else {
127 // Specified just 'image/*', so launch an intent for both the Camera and image/*
128 // OPENABLE.
129 Intent chooser = createChooserIntent(createCameraIntent());
130 chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
131 startActivity(chooser);
132 return;
133 }
134 } else if (mimeType.equals(videoMimeType)) {
135 if (mediaSource.equals(mediaSourceValueCamcorder)) {
136 // Specified 'video/*' and requested the camcorder, so go ahead and launch the
137 // camcorder directly.
138 startActivity(createCamcorderIntent());
139 return;
140 } else if (mediaSource.equals(mediaSourceValueFileSystem)) {
141 // Specified 'video/*' and requested the filesystem, so go ahead and launch an
142 // an OPENABLE intent.
143 startActivity(createOpenableIntent(videoMimeType));
144 return;
145 } else {
146 // Specified just 'video/*', so go ahead and launch an intent for both camcorder and
147 // video/* OPENABLE.
148 Intent chooser = createChooserIntent(createCamcorderIntent());
149 chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
150 startActivity(chooser);
151 return;
152 }
153 } else if (mimeType.equals(audioMimeType)) {
154 if (mediaSource.equals(mediaSourceValueMicrophone)) {
155 // Specified 'audio/*' and requested microphone, so go ahead and launch the sound
156 // recorder.
157 startActivity(createSoundRecorderIntent());
158 return;
159 } else if (mediaSource.equals(mediaSourceValueFileSystem)) {
160 // Specified 'audio/*' and requested filesystem, so go ahead and launch an
161 // OPENABLE intent.
162 startActivity(createOpenableIntent(audioMimeType));
163 return;
164 } else {
165 // Specified just 'audio/*', so go ahead and launch an intent for both the sound
166 // recorder and audio/* OPENABLE.
167 Intent chooser = createChooserIntent(createSoundRecorderIntent());
168 chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
169 startActivity(chooser);
170 return;
171 }
172 }
173
174 // No special handling based on the accept type was necessary, so trigger the default
175 // file upload chooser.
176 startActivity(createDefaultOpenableIntent());
177 }
178
179 private void startActivity(Intent intent) {
180 try {
181 mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
182 } catch (ActivityNotFoundException e) {
183 // No installed app was able to handle the intent that
184 // we sent, so fallback to the default file upload control.
185 try {
186 mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
187 Controller.FILE_SELECTED);
188 } catch (ActivityNotFoundException e2) {
189 // Nothing can return us a file, so file upload is effectively disabled.
190 Toast.makeText(mController.getActivity(), R.string.uploads_disabled,
191 Toast.LENGTH_LONG).show();
192 }
193 }
194 }
195
196 private Intent createDefaultOpenableIntent() {
197 // Create and return a chooser with the default OPENABLE
198 // actions including the camera, camcorder and sound
199 // recorder where available.
Michael Kolb8233fac2010-10-26 16:08:53 -0700200 Intent i = new Intent(Intent.ACTION_GET_CONTENT);
201 i.addCategory(Intent.CATEGORY_OPENABLE);
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000202 i.setType("*/*");
Michael Kolb8233fac2010-10-26 16:08:53 -0700203
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000204 Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
205 createSoundRecorderIntent());
206 chooser.putExtra(Intent.EXTRA_INTENT, i);
207 return chooser;
208 }
209
210 private Intent createChooserIntent(Intent... intents) {
211 Intent chooser = new Intent(Intent.ACTION_CHOOSER);
212 chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
213 chooser.putExtra(Intent.EXTRA_TITLE,
214 mController.getActivity().getResources()
215 .getString(R.string.choose_upload));
216 return chooser;
217 }
218
219 private Intent createOpenableIntent(String type) {
220 Intent i = new Intent(Intent.ACTION_GET_CONTENT);
221 i.addCategory(Intent.CATEGORY_OPENABLE);
222 i.setType(type);
223 return i;
224 }
225
226 private Intent createCameraIntent() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700227 Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
228 File externalDataDir = Environment.getExternalStoragePublicDirectory(
229 Environment.DIRECTORY_DCIM);
230 File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
231 File.separator + "browser-photos");
232 cameraDataDir.mkdirs();
233 mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
234 System.currentTimeMillis() + ".jpg";
235 cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000236 return cameraIntent;
Michael Kolb8233fac2010-10-26 16:08:53 -0700237 }
238
Ben Murdoche4c0cae2011-02-18 11:25:38 +0000239 private Intent createCamcorderIntent() {
240 return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
241 }
242
243 private Intent createSoundRecorderIntent() {
244 return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
Michael Kolb8233fac2010-10-26 16:08:53 -0700245 }
246
247}