-
Notifications
You must be signed in to change notification settings - Fork 127
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Photo Picker Dialog: Recursively traverse the photo directories.
(Only visible change, since the picker is not decoding yet, is that it will show as many gray squares as there are photos on disk). BUG=656015 Review-Url: https://codereview.chromium.org/2810773002 Cr-Commit-Position: refs/heads/master@{#464641}
- Loading branch information
1 parent
5be07ac
commit a106f0a
Showing
5 changed files
with
260 additions
and
22 deletions.
There are no files selected for viewing
127 changes: 127 additions & 0 deletions
127
chrome/android/java/src/org/chromium/chrome/browser/photo_picker/FileEnumWorkerTask.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// Copyright 2017 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
package org.chromium.chrome.browser.photo_picker; | ||
|
||
import android.os.AsyncTask; | ||
import android.os.Environment; | ||
|
||
import org.chromium.base.ThreadUtils; | ||
|
||
import java.io.File; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
/** | ||
* A worker task to enumerate image files on disk. | ||
*/ | ||
class FileEnumWorkerTask extends AsyncTask<Void, Void, List<PickerBitmap>> { | ||
/** | ||
* An interface to use to communicate back the results to the client. | ||
*/ | ||
public interface FilesEnumeratedCallback { | ||
/** | ||
* A callback to define to receive the list of all images on disk. | ||
* @param files The list of images. | ||
*/ | ||
void filesEnumeratedCallback(List<PickerBitmap> files); | ||
} | ||
|
||
// The callback to use to communicate the results. | ||
private FilesEnumeratedCallback mCallback; | ||
|
||
// The filter to apply to the list. | ||
private MimeTypeFileFilter mFilter; | ||
|
||
// The camera directory undir DCIM. | ||
private static final String SAMPLE_DCIM_SOURCE_SUB_DIRECTORY = "Camera"; | ||
|
||
/** | ||
* A FileEnumWorkerTask constructor. | ||
* @param callback The callback to use to communicate back the results. | ||
* @param filter The file filter to apply to the list. | ||
*/ | ||
public FileEnumWorkerTask(FilesEnumeratedCallback callback, MimeTypeFileFilter filter) { | ||
mCallback = callback; | ||
mFilter = filter; | ||
} | ||
|
||
/** | ||
* Retrieves the DCIM/camera directory. | ||
*/ | ||
private File getCameraDirectory() { | ||
return new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), | ||
SAMPLE_DCIM_SOURCE_SUB_DIRECTORY); | ||
} | ||
|
||
/** | ||
* Recursively enumerate files in a directory (and subdirectories) and add them to a list. | ||
* @param directory The parent directory to recursively traverse. | ||
* @param pickerBitmaps The list to add the results to. | ||
* @return True if traversing can continue, false if traversing was aborted and should stop. | ||
*/ | ||
private boolean traverseDir(File directory, List<PickerBitmap> pickerBitmaps) { | ||
File[] files = directory.listFiles(mFilter); | ||
if (files == null) return true; | ||
|
||
for (File file : files) { | ||
if (isCancelled()) return false; | ||
|
||
if (file.isDirectory()) { | ||
if (!traverseDir(file, pickerBitmaps)) return false; | ||
} else { | ||
pickerBitmaps.add(new PickerBitmap( | ||
file.getPath(), file.lastModified(), PickerBitmap.PICTURE)); | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Enumerates (in the background) the image files on disk. Called on a non-UI thread | ||
* @param params Ignored, do not use. | ||
* @return A sorted list of images (by last-modified first). | ||
*/ | ||
@Override | ||
protected List<PickerBitmap> doInBackground(Void... params) { | ||
assert !ThreadUtils.runningOnUiThread(); | ||
|
||
if (isCancelled()) return null; | ||
|
||
List<PickerBitmap> pickerBitmaps = new ArrayList<>(); | ||
|
||
// TODO(finnur): Figure out which directories to scan and stop hard coding "Camera" above. | ||
File[] sourceDirs = new File[] { | ||
getCameraDirectory(), | ||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), | ||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), | ||
}; | ||
|
||
for (File directory : sourceDirs) { | ||
if (!traverseDir(directory, pickerBitmaps)) return null; | ||
} | ||
|
||
Collections.sort(pickerBitmaps); | ||
|
||
pickerBitmaps.add(0, new PickerBitmap("", 0, PickerBitmap.GALLERY)); | ||
pickerBitmaps.add(0, new PickerBitmap("", 0, PickerBitmap.CAMERA)); | ||
|
||
return pickerBitmaps; | ||
} | ||
|
||
/** | ||
* Communicates the results back to the client. Called on the UI thread. | ||
* @param files The resulting list of files on disk. | ||
*/ | ||
@Override | ||
protected void onPostExecute(List<PickerBitmap> files) { | ||
if (isCancelled()) { | ||
return; | ||
} | ||
|
||
mCallback.filesEnumeratedCallback(files); | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
chrome/android/java/src/org/chromium/chrome/browser/photo_picker/MimeTypeFileFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2017 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
package org.chromium.chrome.browser.photo_picker; | ||
|
||
import android.support.annotation.NonNull; | ||
import android.webkit.MimeTypeMap; | ||
|
||
import java.io.File; | ||
import java.io.FileFilter; | ||
import java.util.HashSet; | ||
import java.util.Locale; | ||
|
||
/** | ||
* A file filter for handling extensions mapping to MIME types (such as images/jpeg and images/*). | ||
*/ | ||
class MimeTypeFileFilter implements FileFilter { | ||
private HashSet<String> mExtensions = new HashSet<>(); | ||
private HashSet<String> mMimeTypes = new HashSet<>(); | ||
private HashSet<String> mMimeSupertypes = new HashSet<>(); | ||
private MimeTypeMap mMimeTypeMap; | ||
|
||
/** | ||
* Contructs a MimeTypeFileFilter object. | ||
* @param acceptAttr A comma seperated list of MIME types this filter accepts. | ||
* For example: images/gif, video/*. | ||
*/ | ||
// TODO(finnur): Convert param to List. | ||
public MimeTypeFileFilter(@NonNull String acceptAttr) { | ||
for (String field : acceptAttr.toLowerCase(Locale.US).split(",")) { | ||
field = field.trim(); | ||
if (field.startsWith(".")) { | ||
mExtensions.add(field.substring(1)); | ||
} else if (field.endsWith("/*")) { | ||
mMimeSupertypes.add(field.substring(0, field.length() - 2)); | ||
} else if (field.contains("/")) { | ||
mMimeTypes.add(field); | ||
} else { | ||
// Throw exception? | ||
} | ||
} | ||
|
||
mMimeTypeMap = MimeTypeMap.getSingleton(); | ||
} | ||
|
||
@Override | ||
public boolean accept(@NonNull File file) { | ||
if (file.isDirectory()) { | ||
return true; | ||
} | ||
|
||
String uri = file.toURI().toString(); | ||
String ext = MimeTypeMap.getFileExtensionFromUrl(uri).toLowerCase(Locale.US); | ||
if (mExtensions.contains(ext)) { | ||
return true; | ||
} | ||
|
||
String mimeType = getMimeTypeFromExtension(ext); | ||
if (mimeType != null) { | ||
if (mMimeTypes.contains(mimeType) | ||
|| mMimeSupertypes.contains(getMimeSupertype(mimeType))) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
private HashSet<String> getAcceptedSupertypes() { | ||
HashSet<String> supertypes = new HashSet<>(); | ||
supertypes.addAll(mMimeSupertypes); | ||
for (String mimeType : mMimeTypes) { | ||
supertypes.add(getMimeSupertype(mimeType)); | ||
} | ||
for (String ext : mExtensions) { | ||
String mimeType = getMimeTypeFromExtension(ext); | ||
if (mimeType != null) { | ||
supertypes.add(getMimeSupertype(mimeType)); | ||
} | ||
} | ||
return supertypes; | ||
} | ||
|
||
private String getMimeTypeFromExtension(@NonNull String ext) { | ||
String mimeType = mMimeTypeMap.getMimeTypeFromExtension(ext); | ||
return (mimeType != null) ? mimeType.toLowerCase(Locale.US) : null; | ||
} | ||
|
||
@NonNull | ||
private String getMimeSupertype(@NonNull String mimeType) { | ||
return mimeType.split("/", 2)[0]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters