EMMA Coverage Report (generated Fri Aug 23 16:39:17 PDT 2013)
[all classes][org.chromium.ui]

COVERAGE SUMMARY FOR SOURCE FILE [SelectFileDialog.java]

nameclass, %method, %block, %line, %
SelectFileDialog.java0%   (0/1)0%   (0/16)0%   (0/412)0%   (0/84)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SelectFileDialog0%   (0/1)0%   (0/16)0%   (0/412)0%   (0/84)
SelectFileDialog (int): void 0%   (0/1)0%   (0/6)0%   (0/3)
acceptSpecificType (String): boolean 0%   (0/1)0%   (0/20)0%   (0/4)
acceptsSpecificType (String): boolean 0%   (0/1)0%   (0/17)0%   (0/1)
captureCamcorder (): boolean 0%   (0/1)0%   (0/11)0%   (0/1)
captureCamera (): boolean 0%   (0/1)0%   (0/11)0%   (0/1)
captureMicrophone (): boolean 0%   (0/1)0%   (0/11)0%   (0/1)
create (int): SelectFileDialog 0%   (0/1)0%   (0/5)0%   (0/1)
getFileForImageCapture (): File 0%   (0/1)0%   (0/45)0%   (0/6)
noSpecificType (): boolean 0%   (0/1)0%   (0/14)0%   (0/1)
onFileNotSelected (): void 0%   (0/1)0%   (0/5)0%   (0/2)
onIntentCompleted (WindowAndroid, int, ContentResolver, Intent): void 0%   (0/1)0%   (0/74)0%   (0/21)
selectFile (String [], boolean, WindowAndroid): void 0%   (0/1)0%   (0/164)0%   (0/37)
shouldShowAudioTypes (): boolean 0%   (0/1)0%   (0/5)0%   (0/1)
shouldShowImageTypes (): boolean 0%   (0/1)0%   (0/5)0%   (0/1)
shouldShowTypes (String, String): boolean 0%   (0/1)0%   (0/14)0%   (0/2)
shouldShowVideoTypes (): boolean 0%   (0/1)0%   (0/5)0%   (0/1)

1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4 
5package org.chromium.ui;
6 
7import android.app.Activity;
8import android.content.ContentResolver;
9import android.content.Intent;
10import android.database.Cursor;
11import android.net.Uri;
12import android.os.Environment;
13import android.provider.MediaStore;
14import android.text.TextUtils;
15 
16import java.io.File;
17import java.util.ArrayList;
18import java.util.Arrays;
19import java.util.List;
20 
21import org.chromium.base.CalledByNative;
22import org.chromium.base.JNINamespace;
23import org.chromium.ui.WindowAndroid;
24 
25/**
26 * A dialog that is triggered from a file input field that allows a user to select a file based on
27 * a set of accepted file types. The path of the selected file is passed to the native dialog.
28 */
29@JNINamespace("ui")
30class SelectFileDialog implements WindowAndroid.IntentCallback{
31    private static final String IMAGE_TYPE = "image/";
32    private static final String VIDEO_TYPE = "video/";
33    private static final String AUDIO_TYPE = "audio/";
34    private static final String ALL_IMAGE_TYPES = IMAGE_TYPE + "*";
35    private static final String ALL_VIDEO_TYPES = VIDEO_TYPE + "*";
36    private static final String ALL_AUDIO_TYPES = AUDIO_TYPE + "*";
37    private static final String ANY_TYPES = "*/*";
38    private static final String CAPTURE_IMAGE_DIRECTORY = "browser-photos";
39 
40    private final int mNativeSelectFileDialog;
41    private List<String> mFileTypes;
42    private boolean mCapture;
43    private Uri mCameraOutputUri;
44 
45    private SelectFileDialog(int nativeSelectFileDialog) {
46        mNativeSelectFileDialog = nativeSelectFileDialog;
47    }
48 
49    /**
50     * Creates and starts an intent based on the passed fileTypes and capture value.
51     * @param fileTypes MIME types requested (i.e. "image/*")
52     * @param capture The capture value as described in http://www.w3.org/TR/html-media-capture/
53     * @param window The WindowAndroid that can show intents
54     */
55    @CalledByNative
56    private void selectFile(String[] fileTypes, boolean capture, WindowAndroid window) {
57        mFileTypes = new ArrayList<String>(Arrays.asList(fileTypes));
58        mCapture = capture;
59 
60        Intent chooser = new Intent(Intent.ACTION_CHOOSER);
61        Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
62        mCameraOutputUri = Uri.fromFile(getFileForImageCapture());
63        camera.putExtra(MediaStore.EXTRA_OUTPUT, mCameraOutputUri);
64        Intent camcorder = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
65        Intent soundRecorder = new Intent(
66                MediaStore.Audio.Media.RECORD_SOUND_ACTION);
67 
68        // Quick check - if the |capture| parameter is set and |fileTypes| has the appropriate MIME
69        // type, we should just launch the appropriate intent. Otherwise build up a chooser based on
70        // the accept type and then display that to the user.
71        if (captureCamera()) {
72            if (window.showIntent(camera, this, R.string.low_memory_error)) return;
73        } else if (captureCamcorder()) {
74            if (window.showIntent(camcorder, this, R.string.low_memory_error)) return;
75        } else if (captureMicrophone()) {
76            if (window.showIntent(soundRecorder, this, R.string.low_memory_error)) return;
77        }
78 
79        Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT);
80        getContentIntent.addCategory(Intent.CATEGORY_OPENABLE);
81        ArrayList<Intent> extraIntents = new ArrayList<Intent>();
82        if (!noSpecificType()) {
83            // Create a chooser based on the accept type that was specified in the webpage. Note
84            // that if the web page specified multiple accept types, we will have built a generic
85            // chooser above.
86            if (shouldShowImageTypes()) {
87                extraIntents.add(camera);
88                getContentIntent.setType(ALL_IMAGE_TYPES);
89            } else if (shouldShowVideoTypes()) {
90                extraIntents.add(camcorder);
91                getContentIntent.setType(ALL_VIDEO_TYPES);
92            } else if (shouldShowAudioTypes()) {
93                extraIntents.add(soundRecorder);
94                getContentIntent.setType(ALL_AUDIO_TYPES);
95            }
96        }
97 
98        if (extraIntents.isEmpty()) {
99            // We couldn't resolve an accept type, so fallback to a generic chooser.
100            getContentIntent.setType(ANY_TYPES);
101            extraIntents.add(camera);
102            extraIntents.add(camcorder);
103            extraIntents.add(soundRecorder);
104        }
105 
106        chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS,
107                extraIntents.toArray(new Intent[] { }));
108 
109        chooser.putExtra(Intent.EXTRA_INTENT, getContentIntent);
110 
111        if (!window.showIntent(chooser, this, R.string.low_memory_error)) {
112            onFileNotSelected();
113        }
114    }
115 
116    /**
117     * Get a file for the image capture in the CAPTURE_IMAGE_DIRECTORY directory.
118     */
119    private File getFileForImageCapture() {
120        File externalDataDir = Environment.getExternalStoragePublicDirectory(
121                Environment.DIRECTORY_DCIM);
122        File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
123                File.separator + CAPTURE_IMAGE_DIRECTORY);
124        if (!cameraDataDir.exists() && !cameraDataDir.mkdirs()) {
125            cameraDataDir = externalDataDir;
126        }
127        File photoFile = new File(cameraDataDir.getAbsolutePath() +
128                File.separator + System.currentTimeMillis() + ".jpg");
129        return photoFile;
130    }
131 
132    /**
133     * Callback method to handle the intent results and pass on the path to the native
134     * SelectFileDialog.
135     * @param window The window that has access to the application activity.
136     * @param resultCode The result code whether the intent returned successfully.
137     * @param contentResolver The content resolver used to extract the path of the selected file.
138     * @param results The results of the requested intent.
139     */
140    @Override
141    public void onIntentCompleted(WindowAndroid window, int resultCode,
142            ContentResolver contentResolver, Intent results) {
143        if (resultCode != Activity.RESULT_OK) {
144            onFileNotSelected();
145            return;
146        }
147        boolean success = false;
148        if (results == null) {
149            // If we have a successful return but no data, then assume this is the camera returning
150            // the photo that we requested.
151            nativeOnFileSelected(mNativeSelectFileDialog, mCameraOutputUri.getPath());
152            success = true;
153 
154            // Broadcast to the media scanner that there's a new photo on the device so it will
155            // show up right away in the gallery (rather than waiting until the next time the media
156            // scanner runs).
157            window.sendBroadcast(new Intent(
158                    Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mCameraOutputUri));
159        } else {
160            // We get back a content:// URI from the system if the user picked a file from the
161            // gallery. The ContentView has functionality that will convert that content:// URI to
162            // a file path on disk that Chromium understands.
163            Cursor c = contentResolver.query(results.getData(),
164                    new String[] { MediaStore.MediaColumns.DATA }, null, null, null);
165            if (c != null) {
166                if (c.getCount() == 1) {
167                    c.moveToFirst();
168                    String path = c.getString(0);
169                    if (path != null) {
170                        // Not all providers support the MediaStore.DATA column. For example,
171                        // Gallery3D (com.android.gallery3d.provider) does not support it for
172                        // Picasa Web Album images.
173                        nativeOnFileSelected(mNativeSelectFileDialog, path);
174                        success = true;
175                    }
176                }
177                c.close();
178            }
179        }
180        if (!success) {
181            onFileNotSelected();
182            window.showError(R.string.opening_file_error);
183        }
184    }
185 
186    private void onFileNotSelected() {
187        nativeOnFileNotSelected(mNativeSelectFileDialog);
188    }
189 
190    private boolean noSpecificType() {
191        // We use a single Intent to decide the type of the file chooser we display to the user,
192        // which means we can only give it a single type. If there are multiple accept types
193        // specified, we will fallback to a generic chooser (unless a capture parameter has been
194        // specified, in which case we'll try to satisfy that first.
195        return mFileTypes.size() != 1 || mFileTypes.contains(ANY_TYPES);
196    }
197 
198    private boolean shouldShowTypes(String allTypes, String specificType) {
199        if (noSpecificType() || mFileTypes.contains(allTypes)) return true;
200        return acceptSpecificType(specificType);
201    }
202 
203    private boolean shouldShowImageTypes() {
204        return shouldShowTypes(ALL_IMAGE_TYPES,IMAGE_TYPE);
205    }
206 
207    private boolean shouldShowVideoTypes() {
208        return shouldShowTypes(ALL_VIDEO_TYPES, VIDEO_TYPE);
209    }
210 
211    private boolean shouldShowAudioTypes() {
212        return shouldShowTypes(ALL_AUDIO_TYPES, AUDIO_TYPE);
213    }
214 
215    private boolean acceptsSpecificType(String type) {
216        return mFileTypes.size() == 1 && TextUtils.equals(mFileTypes.get(0), type);
217    }
218 
219    private boolean captureCamera() {
220        return mCapture && acceptsSpecificType(ALL_IMAGE_TYPES);
221    }
222 
223    private boolean captureCamcorder() {
224        return mCapture && acceptsSpecificType(ALL_VIDEO_TYPES);
225    }
226 
227    private boolean captureMicrophone() {
228        return mCapture && acceptsSpecificType(ALL_AUDIO_TYPES);
229    }
230 
231    private boolean acceptSpecificType(String accept) {
232        for (String type : mFileTypes) {
233            if (type.startsWith(accept)) {
234                return true;
235            }
236        }
237        return false;
238    }
239 
240    @CalledByNative
241    private static SelectFileDialog create(int nativeSelectFileDialog) {
242        return new SelectFileDialog(nativeSelectFileDialog);
243    }
244 
245    private native void nativeOnFileSelected(int nativeSelectFileDialogImpl,
246            String filePath);
247    private native void nativeOnFileNotSelected(int nativeSelectFileDialogImpl);
248}

[all classes][org.chromium.ui]
EMMA 2.0.5312 (C) Vladimir Roubtsov