1 /* 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 17 package com.android.browser; 18 19 import android.app.Activity; 20 import android.content.ActivityNotFoundException; 21 import android.content.ClipData; 22 import android.content.Intent; 23 import android.net.Uri; 24 import android.provider.MediaStore; 25 import android.support.v4.content.FileProvider; 26 import android.webkit.WebChromeClient.FileChooserParams; 27 import android.webkit.ValueCallback; 28 import android.widget.Toast; 29 30 import java.io.File; 31 32 /** 33 * Handle the file upload. This does not support selecting multiple files yet. 34 */ 35 public class UploadHandler { 36 private final static String IMAGE_MIME_TYPE = "image/*"; 37 private final static String VIDEO_MIME_TYPE = "video/*"; 38 private final static String AUDIO_MIME_TYPE = "audio/*"; 39 40 private final static String FILE_PROVIDER_AUTHORITY = "com.android.browser-classic.file"; 41 42 /* 43 * The Object used to inform the WebView of the file to upload. 44 */ 45 private ValueCallback<Uri[]> mUploadMessage; 46 47 private boolean mHandled; 48 private Controller mController; 49 private FileChooserParams mParams; 50 private Uri mCapturedMedia; 51 UploadHandler(Controller controller)52 public UploadHandler(Controller controller) { 53 mController = controller; 54 } 55 handled()56 boolean handled() { 57 return mHandled; 58 } 59 onResult(int resultCode, Intent intent)60 void onResult(int resultCode, Intent intent) { 61 Uri[] uris; 62 // As the media capture is always supported, we can't use 63 // FileChooserParams.parseResult(). 64 uris = parseResult(resultCode, intent); 65 mUploadMessage.onReceiveValue(uris); 66 mHandled = true; 67 } 68 openFileChooser(ValueCallback<Uri[]> callback, FileChooserParams fileChooserParams)69 void openFileChooser(ValueCallback<Uri[]> callback, FileChooserParams fileChooserParams) { 70 71 if (mUploadMessage != null) { 72 // Already a file picker operation in progress. 73 return; 74 } 75 76 mUploadMessage = callback; 77 mParams = fileChooserParams; 78 Intent[] captureIntents = createCaptureIntent(); 79 assert(captureIntents != null && captureIntents.length > 0); 80 Intent intent = null; 81 // Go to the media capture directly if capture is specified, this is the 82 // preferred way. 83 if (fileChooserParams.isCaptureEnabled() && captureIntents.length == 1) { 84 intent = captureIntents[0]; 85 } else { 86 intent = new Intent(Intent.ACTION_CHOOSER); 87 intent.putExtra(Intent.EXTRA_INITIAL_INTENTS, captureIntents); 88 intent.putExtra(Intent.EXTRA_INTENT, fileChooserParams.createIntent()); 89 } 90 startActivity(intent); 91 } 92 parseResult(int resultCode, Intent intent)93 private Uri[] parseResult(int resultCode, Intent intent) { 94 if (resultCode == Activity.RESULT_CANCELED) { 95 return null; 96 } 97 Uri result = intent == null || resultCode != Activity.RESULT_OK ? null 98 : intent.getData(); 99 100 // As we ask the camera to save the result of the user taking 101 // a picture, the camera application does not return anything other 102 // than RESULT_OK. So we need to check whether the file we expected 103 // was written to disk in the in the case that we 104 // did not get an intent returned but did get a RESULT_OK. If it was, 105 // we assume that this result has came back from the camera. 106 if (result == null && intent == null && resultCode == Activity.RESULT_OK 107 && mCapturedMedia != null) { 108 result = mCapturedMedia; 109 } 110 111 Uri[] uris = null; 112 if (result != null) { 113 uris = new Uri[1]; 114 uris[0] = result; 115 } 116 return uris; 117 } 118 startActivity(Intent intent)119 private void startActivity(Intent intent) { 120 try { 121 mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED); 122 } catch (ActivityNotFoundException e) { 123 // No installed app was able to handle the intent that 124 // we sent, so file upload is effectively disabled. 125 Toast.makeText(mController.getActivity(), R.string.uploads_disabled, 126 Toast.LENGTH_LONG).show(); 127 } 128 } 129 createCaptureIntent()130 private Intent[] createCaptureIntent() { 131 String mimeType = "*/*"; 132 String[] acceptTypes = mParams.getAcceptTypes(); 133 if ( acceptTypes != null && acceptTypes.length > 0) { 134 mimeType = acceptTypes[0]; 135 } 136 Intent[] intents; 137 if (mimeType.equals(IMAGE_MIME_TYPE)) { 138 intents = new Intent[1]; 139 intents[0] = createCameraIntent(createTempFileContentUri(".jpg")); 140 } else if (mimeType.equals(VIDEO_MIME_TYPE)) { 141 intents = new Intent[1]; 142 intents[0] = createCamcorderIntent(); 143 } else if (mimeType.equals(AUDIO_MIME_TYPE)) { 144 intents = new Intent[1]; 145 intents[0] = createSoundRecorderIntent(); 146 } else { 147 intents = new Intent[3]; 148 intents[0] = createCameraIntent(createTempFileContentUri(".jpg")); 149 intents[1] = createCamcorderIntent(); 150 intents[2] = createSoundRecorderIntent(); 151 } 152 return intents; 153 } 154 createTempFileContentUri(String suffix)155 private Uri createTempFileContentUri(String suffix) { 156 try { 157 File mediaPath = new File(mController.getActivity().getFilesDir(), "captured_media"); 158 if (!mediaPath.exists() && !mediaPath.mkdir()) { 159 throw new RuntimeException("Folder cannot be created."); 160 } 161 File mediaFile = File.createTempFile( 162 String.valueOf(System.currentTimeMillis()), suffix, mediaPath); 163 return FileProvider.getUriForFile(mController.getActivity(), 164 FILE_PROVIDER_AUTHORITY, mediaFile); 165 } catch (java.io.IOException e) { 166 throw new RuntimeException(e); 167 } 168 } 169 createCameraIntent(Uri contentUri)170 private Intent createCameraIntent(Uri contentUri) { 171 if (contentUri == null) throw new IllegalArgumentException(); 172 mCapturedMedia = contentUri; 173 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 174 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | 175 Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 176 intent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedMedia); 177 intent.setClipData(ClipData.newUri(mController.getActivity().getContentResolver(), 178 FILE_PROVIDER_AUTHORITY, mCapturedMedia)); 179 return intent; 180 } 181 createCamcorderIntent()182 private Intent createCamcorderIntent() { 183 return new Intent(MediaStore.ACTION_VIDEO_CAPTURE); 184 } 185 createSoundRecorderIntent()186 private Intent createSoundRecorderIntent() { 187 return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION); 188 } 189 } 190