| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.ui.base; | 5 package org.chromium.ui.base; |
| 6 | 6 |
| 7 import android.Manifest; | 7 import android.Manifest; |
| 8 import android.annotation.TargetApi; | 8 import android.annotation.TargetApi; |
| 9 import android.app.Activity; | 9 import android.app.Activity; |
| 10 import android.content.ClipData; | 10 import android.content.ClipData; |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 // on the accept type and then display that to the user. | 160 // on the accept type and then display that to the user. |
| 161 if (captureCamera() && camera != null) { | 161 if (captureCamera() && camera != null) { |
| 162 if (mWindowAndroid.showIntent(camera, this, R.string.low_memory_erro
r)) return; | 162 if (mWindowAndroid.showIntent(camera, this, R.string.low_memory_erro
r)) return; |
| 163 } else if (captureCamcorder() && camcorder != null) { | 163 } else if (captureCamcorder() && camcorder != null) { |
| 164 if (mWindowAndroid.showIntent(camcorder, this, R.string.low_memory_e
rror)) return; | 164 if (mWindowAndroid.showIntent(camcorder, this, R.string.low_memory_e
rror)) return; |
| 165 } else if (captureMicrophone() && soundRecorder != null) { | 165 } else if (captureMicrophone() && soundRecorder != null) { |
| 166 if (mWindowAndroid.showIntent(soundRecorder, this, R.string.low_memo
ry_error)) return; | 166 if (mWindowAndroid.showIntent(soundRecorder, this, R.string.low_memo
ry_error)) return; |
| 167 } | 167 } |
| 168 | 168 |
| 169 Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT); | 169 Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT); |
| 170 getContentIntent.addCategory(Intent.CATEGORY_OPENABLE); | |
| 171 | 170 |
| 172 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && mAllo
wMultiple) { | 171 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && mAllo
wMultiple) { |
| 173 getContentIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); | 172 getContentIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); |
| 174 } | 173 } |
| 175 | 174 |
| 176 ArrayList<Intent> extraIntents = new ArrayList<Intent>(); | 175 ArrayList<Intent> extraIntents = new ArrayList<Intent>(); |
| 177 if (!noSpecificType()) { | 176 if (!noSpecificType()) { |
| 178 // Create a chooser based on the accept type that was specified in t
he webpage. Note | 177 // Create a chooser based on the accept type that was specified in t
he webpage. Note |
| 179 // that if the web page specified multiple accept types, we will hav
e built a generic | 178 // that if the web page specified multiple accept types, we will hav
e built a generic |
| 180 // chooser above. | 179 // chooser above. |
| 181 if (shouldShowImageTypes()) { | 180 if (shouldShowImageTypes()) { |
| 182 if (camera != null) extraIntents.add(camera); | 181 if (camera != null) extraIntents.add(camera); |
| 183 getContentIntent.setType(ALL_IMAGE_TYPES); | 182 getContentIntent.setType(ALL_IMAGE_TYPES); |
| 184 } else if (shouldShowVideoTypes()) { | 183 } else if (shouldShowVideoTypes()) { |
| 185 if (camcorder != null) extraIntents.add(camcorder); | 184 if (camcorder != null) extraIntents.add(camcorder); |
| 186 getContentIntent.setType(ALL_VIDEO_TYPES); | 185 getContentIntent.setType(ALL_VIDEO_TYPES); |
| 187 } else if (shouldShowAudioTypes()) { | 186 } else if (shouldShowAudioTypes()) { |
| 188 if (soundRecorder != null) extraIntents.add(soundRecorder); | 187 if (soundRecorder != null) extraIntents.add(soundRecorder); |
| 189 getContentIntent.setType(ALL_AUDIO_TYPES); | 188 getContentIntent.setType(ALL_AUDIO_TYPES); |
| 190 } | 189 } |
| 190 |
| 191 // If any types are specified, then only accept openable files, as c
oercing |
| 192 // virtual files may yield to a MIME type different than expected. |
| 193 getContentIntent.addCategory(Intent.CATEGORY_OPENABLE); |
| 191 } | 194 } |
| 192 | 195 |
| 193 if (extraIntents.isEmpty()) { | 196 if (extraIntents.isEmpty()) { |
| 194 // We couldn't resolve an accept type, so fallback to a generic choo
ser. | 197 // We couldn't resolve an accept type, so fallback to a generic choo
ser. |
| 195 getContentIntent.setType(ANY_TYPES); | 198 getContentIntent.setType(ANY_TYPES); |
| 196 if (camera != null) extraIntents.add(camera); | 199 if (camera != null) extraIntents.add(camera); |
| 197 if (camcorder != null) extraIntents.add(camcorder); | 200 if (camcorder != null) extraIntents.add(camcorder); |
| 198 if (soundRecorder != null) extraIntents.add(soundRecorder); | 201 if (soundRecorder != null) extraIntents.add(soundRecorder); |
| 199 } | 202 } |
| 200 | 203 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 File photoFile = File.createTempFile(String.valueOf(System.currentTimeMi
llis()), ".jpg", | 259 File photoFile = File.createTempFile(String.valueOf(System.currentTimeMi
llis()), ".jpg", |
| 257 UiUtils.getDirectoryForImageCapture(context)); | 260 UiUtils.getDirectoryForImageCapture(context)); |
| 258 return photoFile; | 261 return photoFile; |
| 259 } | 262 } |
| 260 | 263 |
| 261 /** | 264 /** |
| 262 * Callback method to handle the intent results and pass on the path to the
native | 265 * Callback method to handle the intent results and pass on the path to the
native |
| 263 * SelectFileDialog. | 266 * SelectFileDialog. |
| 264 * @param window The window that has access to the application activity. | 267 * @param window The window that has access to the application activity. |
| 265 * @param resultCode The result code whether the intent returned successfull
y. | 268 * @param resultCode The result code whether the intent returned successfull
y. |
| 266 * @param contentResolver The content resolver used to extract the path of t
he selected file. | 269 * @param context Application context. |
| 267 * @param results The results of the requested intent. | 270 * @param results The results of the requested intent. |
| 268 */ | 271 */ |
| 269 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) | 272 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) |
| 270 @Override | 273 @Override |
| 271 public void onIntentCompleted(WindowAndroid window, int resultCode, | 274 public void onIntentCompleted( |
| 272 ContentResolver contentResolver, Intent results) { | 275 WindowAndroid window, int resultCode, Context context, Intent result
s) { |
| 273 if (resultCode != Activity.RESULT_OK) { | 276 if (resultCode != Activity.RESULT_OK) { |
| 274 onFileNotSelected(); | 277 onFileNotSelected(); |
| 275 return; | 278 return; |
| 276 } | 279 } |
| 277 | 280 |
| 278 if (results == null | 281 if (results == null |
| 279 || (results.getData() == null | 282 || (results.getData() == null |
| 280 && (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY
_BEAN_MR2 | 283 && (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY
_BEAN_MR2 |
| 281 || results.getClipData() == null))) { | 284 || results.getClipData() == null))) { |
| 282 // If we have a successful return but no data, then assume this is t
he camera returning | 285 // If we have a successful return but no data, then assume this is t
he camera returning |
| (...skipping 23 matching lines...) Expand all Loading... |
| 306 int itemCount = clipData.getItemCount(); | 309 int itemCount = clipData.getItemCount(); |
| 307 if (itemCount == 0) { | 310 if (itemCount == 0) { |
| 308 onFileNotSelected(); | 311 onFileNotSelected(); |
| 309 return; | 312 return; |
| 310 } | 313 } |
| 311 | 314 |
| 312 Uri[] filePathArray = new Uri[itemCount]; | 315 Uri[] filePathArray = new Uri[itemCount]; |
| 313 for (int i = 0; i < itemCount; ++i) { | 316 for (int i = 0; i < itemCount; ++i) { |
| 314 filePathArray[i] = clipData.getItemAt(i).getUri(); | 317 filePathArray[i] = clipData.getItemAt(i).getUri(); |
| 315 } | 318 } |
| 316 GetDisplayNameTask task = new GetDisplayNameTask(contentResolver, tr
ue); | 319 GetDisplayNameTask task = new GetDisplayNameTask(context, true); |
| 317 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, filePathArray
); | 320 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, filePathArray
); |
| 318 return; | 321 return; |
| 319 } | 322 } |
| 320 | 323 |
| 321 if (ContentResolver.SCHEME_FILE.equals(results.getData().getScheme())) { | 324 if (ContentResolver.SCHEME_FILE.equals(results.getData().getScheme())) { |
| 322 nativeOnFileSelected( | 325 nativeOnFileSelected( |
| 323 mNativeSelectFileDialog, results.getData().getSchemeSpecific
Part(), ""); | 326 mNativeSelectFileDialog, results.getData().getSchemeSpecific
Part(), ""); |
| 324 return; | 327 return; |
| 325 } | 328 } |
| 326 | 329 |
| 327 if (ContentResolver.SCHEME_CONTENT.equals(results.getScheme())) { | 330 if (ContentResolver.SCHEME_CONTENT.equals(results.getScheme())) { |
| 328 GetDisplayNameTask task = new GetDisplayNameTask(contentResolver, fa
lse); | 331 GetDisplayNameTask task = new GetDisplayNameTask(context, false); |
| 329 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, results.getDa
ta()); | 332 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, results.getDa
ta()); |
| 330 return; | 333 return; |
| 331 } | 334 } |
| 332 | 335 |
| 333 onFileNotSelected(); | 336 onFileNotSelected(); |
| 334 window.showError(R.string.opening_file_error); | 337 window.showError(R.string.opening_file_error); |
| 335 } | 338 } |
| 336 | 339 |
| 337 @Override | 340 @Override |
| 338 public void onRequestPermissionsResult(String[] permissions, int[] grantResu
lts) { | 341 public void onRequestPermissionsResult(String[] permissions, int[] grantResu
lts) { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 for (String type : mFileTypes) { | 397 for (String type : mFileTypes) { |
| 395 if (type.startsWith(accept)) { | 398 if (type.startsWith(accept)) { |
| 396 return true; | 399 return true; |
| 397 } | 400 } |
| 398 } | 401 } |
| 399 return false; | 402 return false; |
| 400 } | 403 } |
| 401 | 404 |
| 402 private class GetDisplayNameTask extends AsyncTask<Uri, Void, String[]> { | 405 private class GetDisplayNameTask extends AsyncTask<Uri, Void, String[]> { |
| 403 String[] mFilePaths; | 406 String[] mFilePaths; |
| 404 final ContentResolver mContentResolver; | 407 final Context mContext; |
| 405 final boolean mIsMultiple; | 408 final boolean mIsMultiple; |
| 406 | 409 |
| 407 public GetDisplayNameTask(ContentResolver contentResolver, boolean isMul
tiple) { | 410 public GetDisplayNameTask(Context context, boolean isMultiple) { |
| 408 mContentResolver = contentResolver; | 411 mContext = context; |
| 409 mIsMultiple = isMultiple; | 412 mIsMultiple = isMultiple; |
| 410 } | 413 } |
| 411 | 414 |
| 412 @Override | 415 @Override |
| 413 protected String[] doInBackground(Uri...uris) { | 416 protected String[] doInBackground(Uri...uris) { |
| 414 mFilePaths = new String[uris.length]; | 417 mFilePaths = new String[uris.length]; |
| 415 String[] displayNames = new String[uris.length]; | 418 String[] displayNames = new String[uris.length]; |
| 416 try { | 419 try { |
| 417 for (int i = 0; i < uris.length; i++) { | 420 for (int i = 0; i < uris.length; i++) { |
| 418 mFilePaths[i] = uris[i].toString(); | 421 mFilePaths[i] = uris[i].toString(); |
| 419 displayNames[i] = ContentUriUtils.getDisplayName( | 422 displayNames[i] = ContentUriUtils.getDisplayName( |
| 420 uris[i], mContentResolver, MediaStore.MediaColumns.D
ISPLAY_NAME); | 423 uris[i], mContext, MediaStore.MediaColumns.DISPLAY_N
AME); |
| 421 } | 424 } |
| 422 } catch (SecurityException e) { | 425 } catch (SecurityException e) { |
| 423 // Some third party apps will present themselves as being able | 426 // Some third party apps will present themselves as being able |
| 424 // to handle the ACTION_GET_CONTENT intent but then declare them
selves | 427 // to handle the ACTION_GET_CONTENT intent but then declare them
selves |
| 425 // as exported=false (or more often omit the exported keyword in | 428 // as exported=false (or more often omit the exported keyword in |
| 426 // the manifest which defaults to false after JB). | 429 // the manifest which defaults to false after JB). |
| 427 // In those cases trying to access the contents raises a securit
y exception | 430 // In those cases trying to access the contents raises a securit
y exception |
| 428 // which we should not crash on. See crbug.com/382367 for detail
s. | 431 // which we should not crash on. See crbug.com/382367 for detail
s. |
| 429 Log.w(TAG, "Unable to extract results from the content provider"
); | 432 Log.w(TAG, "Unable to extract results from the content provider"
); |
| 430 return null; | 433 return null; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 451 private static SelectFileDialog create(long nativeSelectFileDialog) { | 454 private static SelectFileDialog create(long nativeSelectFileDialog) { |
| 452 return new SelectFileDialog(nativeSelectFileDialog); | 455 return new SelectFileDialog(nativeSelectFileDialog); |
| 453 } | 456 } |
| 454 | 457 |
| 455 private native void nativeOnFileSelected(long nativeSelectFileDialogImpl, | 458 private native void nativeOnFileSelected(long nativeSelectFileDialogImpl, |
| 456 String filePath, String displayName); | 459 String filePath, String displayName); |
| 457 private native void nativeOnMultipleFilesSelected(long nativeSelectFileDialo
gImpl, | 460 private native void nativeOnMultipleFilesSelected(long nativeSelectFileDialo
gImpl, |
| 458 String[] filePathArray, String[] displayNameArray); | 461 String[] filePathArray, String[] displayNameArray); |
| 459 private native void nativeOnFileNotSelected(long nativeSelectFileDialogImpl)
; | 462 private native void nativeOnFileNotSelected(long nativeSelectFileDialogImpl)
; |
| 460 } | 463 } |
| OLD | NEW |