Chromium Code Reviews| 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; |
| 11 import android.content.ContentResolver; | 11 import android.content.ContentResolver; |
| 12 import android.content.Context; | 12 import android.content.Context; |
| 13 import android.content.Intent; | 13 import android.content.Intent; |
| 14 import android.content.pm.PackageManager; | 14 import android.content.pm.PackageManager; |
| 15 import android.net.Uri; | 15 import android.net.Uri; |
| 16 import android.os.AsyncTask; | 16 import android.os.AsyncTask; |
| 17 import android.os.Build; | 17 import android.os.Build; |
| 18 import android.provider.MediaStore; | 18 import android.provider.MediaStore; |
| 19 import android.text.TextUtils; | 19 import android.text.TextUtils; |
| 20 import android.util.Log; | 20 import android.util.Log; |
| 21 | 21 |
| 22 import org.chromium.base.ApiCompatibilityUtils; | 22 import org.chromium.base.ApiCompatibilityUtils; |
| 23 import org.chromium.base.ContentUriUtils; | 23 import org.chromium.base.ContentUriUtils; |
| 24 import org.chromium.base.ContextUtils; | 24 import org.chromium.base.ContextUtils; |
| 25 import org.chromium.base.ThreadUtils; | 25 import org.chromium.base.ThreadUtils; |
| 26 import org.chromium.base.VisibleForTesting; | 26 import org.chromium.base.VisibleForTesting; |
| 27 import org.chromium.base.annotations.CalledByNative; | 27 import org.chromium.base.annotations.CalledByNative; |
| 28 import org.chromium.base.annotations.JNINamespace; | 28 import org.chromium.base.annotations.JNINamespace; |
| 29 import org.chromium.base.annotations.MainDex; | 29 import org.chromium.base.annotations.MainDex; |
| 30 import org.chromium.base.metrics.RecordHistogram; | |
| 30 import org.chromium.ui.R; | 31 import org.chromium.ui.R; |
| 31 import org.chromium.ui.UiUtils; | 32 import org.chromium.ui.UiUtils; |
| 32 | 33 |
| 33 import java.io.File; | 34 import java.io.File; |
| 34 import java.io.IOException; | 35 import java.io.IOException; |
| 35 import java.util.ArrayList; | 36 import java.util.ArrayList; |
| 36 import java.util.Arrays; | 37 import java.util.Arrays; |
| 37 import java.util.List; | 38 import java.util.List; |
| 38 | 39 |
| 39 /** | 40 /** |
| 40 * A dialog that is triggered from a file input field that allows a user to sele ct a file based on | 41 * A dialog that is triggered from a file input field that allows a user to sele ct a file based on |
| 41 * a set of accepted file types. The path of the selected file is passed to the native dialog. | 42 * a set of accepted file types. The path of the selected file is passed to the native dialog. |
| 42 */ | 43 */ |
| 43 @JNINamespace("ui") | 44 @JNINamespace("ui") |
| 44 @MainDex | 45 @MainDex |
| 45 public class SelectFileDialog | 46 public class SelectFileDialog |
| 46 implements WindowAndroid.IntentCallback, WindowAndroid.PermissionCallbac k { | 47 implements WindowAndroid.IntentCallback, WindowAndroid.PermissionCallbac k { |
| 47 private static final String TAG = "SelectFileDialog"; | 48 private static final String TAG = "SelectFileDialog"; |
| 48 private static final String IMAGE_TYPE = "image/"; | 49 private static final String IMAGE_TYPE = "image/"; |
| 49 private static final String VIDEO_TYPE = "video/"; | 50 private static final String VIDEO_TYPE = "video/"; |
| 50 private static final String AUDIO_TYPE = "audio/"; | 51 private static final String AUDIO_TYPE = "audio/"; |
| 51 private static final String ALL_IMAGE_TYPES = IMAGE_TYPE + "*"; | 52 private static final String ALL_IMAGE_TYPES = IMAGE_TYPE + "*"; |
| 52 private static final String ALL_VIDEO_TYPES = VIDEO_TYPE + "*"; | 53 private static final String ALL_VIDEO_TYPES = VIDEO_TYPE + "*"; |
| 53 private static final String ALL_AUDIO_TYPES = AUDIO_TYPE + "*"; | 54 private static final String ALL_AUDIO_TYPES = AUDIO_TYPE + "*"; |
| 54 private static final String ANY_TYPES = "*/*"; | 55 private static final String ANY_TYPES = "*/*"; |
| 55 | 56 |
| 56 /** | 57 /** |
| 58 * The SELECT_FILE_DIALOG_SCOPE_* enumerations are used to measure the sort of content that | |
| 59 * developers are requesting to be shown in the select file dialog. Values m ust be kept in sync | |
| 60 * with their definition in //tools/metrics/histograms/histograms.xml. | |
| 61 */ | |
| 62 private static final int SELECT_FILE_DIALOG_SCOPE_GENERIC = 0; | |
| 63 private static final int SELECT_FILE_DIALOG_SCOPE_IMAGES = 1; | |
| 64 private static final int SELECT_FILE_DIALOG_SCOPE_IMAGES_AND_VIDEO = 2; | |
| 65 private static final int SELECT_FILE_DIALOG_SCOPE_MAX = | |
| 66 SELECT_FILE_DIALOG_SCOPE_IMAGES_AND_VIDEO; | |
| 67 | |
| 68 /** | |
| 57 * If set, overrides the WindowAndroid passed in {@link selectFile()}. | 69 * If set, overrides the WindowAndroid passed in {@link selectFile()}. |
| 58 */ | 70 */ |
| 59 private static WindowAndroid sOverrideWindowAndroid; | 71 private static WindowAndroid sOverrideWindowAndroid; |
| 60 | 72 |
| 61 private final long mNativeSelectFileDialog; | 73 private final long mNativeSelectFileDialog; |
| 62 private List<String> mFileTypes; | 74 private List<String> mFileTypes; |
| 63 private boolean mCapture; | 75 private boolean mCapture; |
| 64 private boolean mAllowMultiple; | 76 private boolean mAllowMultiple; |
| 65 private Uri mCameraOutputUri; | 77 private Uri mCameraOutputUri; |
| 66 private WindowAndroid mWindowAndroid; | 78 private WindowAndroid mWindowAndroid; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 } else if (captureMicrophone() && soundRecorder != null) { | 179 } else if (captureMicrophone() && soundRecorder != null) { |
| 168 if (mWindowAndroid.showIntent(soundRecorder, this, R.string.low_memo ry_error)) return; | 180 if (mWindowAndroid.showIntent(soundRecorder, this, R.string.low_memo ry_error)) return; |
| 169 } | 181 } |
| 170 | 182 |
| 171 Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT); | 183 Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT); |
| 172 | 184 |
| 173 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && mAllo wMultiple) { | 185 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && mAllo wMultiple) { |
| 174 getContentIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); | 186 getContentIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); |
| 175 } | 187 } |
| 176 | 188 |
| 189 RecordHistogram.recordEnumeratedHistogram("Android.SelectFileDialogScope ", | |
| 190 determineSelectFileDialogScope(), SELECT_FILE_DIALOG_SCOPE_MAX); | |
| 191 | |
| 177 ArrayList<Intent> extraIntents = new ArrayList<Intent>(); | 192 ArrayList<Intent> extraIntents = new ArrayList<Intent>(); |
| 178 if (!noSpecificType()) { | 193 if (!noSpecificType()) { |
| 179 // Create a chooser based on the accept type that was specified in t he webpage. Note | 194 // Create a chooser based on the accept type that was specified in t he webpage. Note |
| 180 // that if the web page specified multiple accept types, we will hav e built a generic | 195 // that if the web page specified multiple accept types, we will hav e built a generic |
| 181 // chooser above. | 196 // chooser above. |
| 182 if (shouldShowImageTypes()) { | 197 if (shouldShowImageTypes()) { |
| 183 if (camera != null) extraIntents.add(camera); | 198 if (camera != null) extraIntents.add(camera); |
| 184 getContentIntent.setType(ALL_IMAGE_TYPES); | 199 getContentIntent.setType(ALL_IMAGE_TYPES); |
| 185 } else if (shouldShowVideoTypes()) { | 200 } else if (shouldShowVideoTypes()) { |
| 186 if (camcorder != null) extraIntents.add(camcorder); | 201 if (camcorder != null) extraIntents.add(camcorder); |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 return; | 363 return; |
| 349 } | 364 } |
| 350 } | 365 } |
| 351 launchSelectFileIntent(); | 366 launchSelectFileIntent(); |
| 352 } | 367 } |
| 353 | 368 |
| 354 private void onFileNotSelected() { | 369 private void onFileNotSelected() { |
| 355 nativeOnFileNotSelected(mNativeSelectFileDialog); | 370 nativeOnFileNotSelected(mNativeSelectFileDialog); |
| 356 } | 371 } |
| 357 | 372 |
| 373 // Determines the scope of the requested select file dialog for use in a UMA histogram. Right | |
| 374 // now we want to distinguish between generic, photo and visual media picker s. | |
| 375 private int determineSelectFileDialogScope() { | |
|
Miguel Garcia
2017/01/24 18:42:26
So this will log as generic when asking for just v
| |
| 376 if (!noSpecificType() && !shouldShowAudioTypes() && shouldShowImageTypes ()) { | |
| 377 if (shouldShowVideoTypes()) { | |
| 378 return SELECT_FILE_DIALOG_SCOPE_IMAGES_AND_VIDEO; | |
| 379 } else { | |
| 380 return SELECT_FILE_DIALOG_SCOPE_IMAGES; | |
| 381 } | |
| 382 } | |
| 383 | |
| 384 return SELECT_FILE_DIALOG_SCOPE_GENERIC; | |
| 385 } | |
| 386 | |
| 358 private boolean noSpecificType() { | 387 private boolean noSpecificType() { |
| 359 // We use a single Intent to decide the type of the file chooser we disp lay to the user, | 388 // We use a single Intent to decide the type of the file chooser we disp lay to the user, |
| 360 // which means we can only give it a single type. If there are multiple accept types | 389 // which means we can only give it a single type. If there are multiple accept types |
| 361 // specified, we will fallback to a generic chooser (unless a capture pa rameter has been | 390 // specified, we will fallback to a generic chooser (unless a capture pa rameter has been |
| 362 // specified, in which case we'll try to satisfy that first. | 391 // specified, in which case we'll try to satisfy that first. |
| 363 return mFileTypes.size() != 1 || mFileTypes.contains(ANY_TYPES); | 392 return mFileTypes.size() != 1 || mFileTypes.contains(ANY_TYPES); |
| 364 } | 393 } |
| 365 | 394 |
| 366 private boolean shouldShowTypes(String allTypes, String specificType) { | 395 private boolean shouldShowTypes(String allTypes, String specificType) { |
| 367 if (noSpecificType() || mFileTypes.contains(allTypes)) return true; | 396 if (noSpecificType() || mFileTypes.contains(allTypes)) return true; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 457 private static SelectFileDialog create(long nativeSelectFileDialog) { | 486 private static SelectFileDialog create(long nativeSelectFileDialog) { |
| 458 return new SelectFileDialog(nativeSelectFileDialog); | 487 return new SelectFileDialog(nativeSelectFileDialog); |
| 459 } | 488 } |
| 460 | 489 |
| 461 private native void nativeOnFileSelected(long nativeSelectFileDialogImpl, | 490 private native void nativeOnFileSelected(long nativeSelectFileDialogImpl, |
| 462 String filePath, String displayName); | 491 String filePath, String displayName); |
| 463 private native void nativeOnMultipleFilesSelected(long nativeSelectFileDialo gImpl, | 492 private native void nativeOnMultipleFilesSelected(long nativeSelectFileDialo gImpl, |
| 464 String[] filePathArray, String[] displayNameArray); | 493 String[] filePathArray, String[] displayNameArray); |
| 465 private native void nativeOnFileNotSelected(long nativeSelectFileDialogImpl) ; | 494 private native void nativeOnFileNotSelected(long nativeSelectFileDialogImpl) ; |
| 466 } | 495 } |
| OLD | NEW |