Commit 0cd8324e authored by qinmin@chromium.org's avatar qinmin@chromium.org

Pass display names for uploaded content URI files

The display names are missing for content URI files.
That will cause some upload to fail.
This CL translates the content URI to displayed name and passes them to native code.

BUG=402537

Review URL: https://codereview.chromium.org/450003002

Cr-Commit-Position: refs/heads/master@{#289102}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289102 0039d316-1c4b-4281-b951-d872f2087c98
parent 2aa94e19
......@@ -573,7 +573,8 @@ public class AwContents {
mDIPScale = DeviceDisplayInfo.create(mContext).getDIPScale();
mLayoutSizer.setDelegate(new AwLayoutSizerDelegate());
mLayoutSizer.setDIPScale(mDIPScale);
mWebContentsDelegate = new AwWebContentsDelegateAdapter(contentsClient, mContainerView);
mWebContentsDelegate = new AwWebContentsDelegateAdapter(
contentsClient, mContainerView, mContext);
mContentsClientBridge = new AwContentsClientBridge(contentsClient,
mBrowserContext.getKeyStore(), AwContentsStatics.getClientCertLookupTable());
mZoomControls = new AwZoomControls(this);
......
......@@ -41,5 +41,5 @@ public abstract class AwWebContentsDelegate extends WebContentsDelegateAndroid {
// Call in response to a prior runFileChooser call.
protected static native void nativeFilesSelectedInChooser(int processId, int renderId,
int mode_flags, String[] filePath);
int mode_flags, String[] filePath, String[] displayName);
}
......@@ -4,14 +4,20 @@
package org.chromium.android_webview;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ConsoleMessage;
import android.webkit.ValueCallback;
import org.chromium.base.ContentUriUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.content.browser.ContentVideoView;
import org.chromium.content.browser.ContentViewCore;
......@@ -26,11 +32,13 @@ class AwWebContentsDelegateAdapter extends AwWebContentsDelegate {
final AwContentsClient mContentsClient;
View mContainerView;
final Context mContext;
public AwWebContentsDelegateAdapter(AwContentsClient contentsClient,
View containerView) {
View containerView, Context context) {
mContentsClient = contentsClient;
setContainerView(containerView);
mContext = context;
}
public void setContainerView(View containerView) {
......@@ -161,10 +169,10 @@ class AwWebContentsDelegateAdapter extends AwWebContentsDelegate {
}
@Override
public void runFileChooser(final int processId, final int renderId, final int mode_flags,
public void runFileChooser(final int processId, final int renderId, final int modeFlags,
String acceptTypes, String title, String defaultFilename, boolean capture) {
AwContentsClient.FileChooserParams params = new AwContentsClient.FileChooserParams();
params.mode = mode_flags;
params.mode = modeFlags;
params.acceptTypes = acceptTypes;
params.title = title;
params.defaultFilename = defaultFilename;
......@@ -178,7 +186,14 @@ class AwWebContentsDelegateAdapter extends AwWebContentsDelegate {
throw new IllegalStateException("Duplicate showFileChooser result");
}
mCompleted = true;
nativeFilesSelectedInChooser(processId, renderId, mode_flags, results);
if (results == null) {
nativeFilesSelectedInChooser(
processId, renderId, modeFlags, null, null);
return;
}
GetDisplayNameTask task = new GetDisplayNameTask(
mContext.getContentResolver(), processId, renderId, modeFlags, results);
task.execute();
}
}, params);
}
......@@ -200,4 +215,46 @@ class AwWebContentsDelegateAdapter extends AwWebContentsDelegate {
if (videoView != null) videoView.exitFullscreen(false);
}
}
private static class GetDisplayNameTask extends AsyncTask<Void, Void, String[]> {
final int mProcessId;
final int mRenderId;
final int mModeFlags;
final String[] mFilePaths;
final ContentResolver mContentResolver;
public GetDisplayNameTask(ContentResolver contentResolver, int processId, int renderId,
int modeFlags, String[] filePaths) {
mProcessId = processId;
mRenderId = renderId;
mModeFlags = modeFlags;
mFilePaths = filePaths;
mContentResolver = contentResolver;
}
@Override
protected String[] doInBackground(Void...voids) {
String[] displayNames = new String[mFilePaths.length];
for (int i = 0; i < mFilePaths.length; i++) {
displayNames[i] = resolveFileName(mFilePaths[i]);
}
return displayNames;
}
@Override
protected void onPostExecute(String[] result) {
nativeFilesSelectedInChooser(mProcessId, mRenderId, mModeFlags, mFilePaths, result);
}
/**
* @return the display name of a path if it is a content URI and is present in the database
* or an empty string otherwise.
*/
private String resolveFileName(String filePath) {
if (mContentResolver == null || filePath == null) return "";
Uri uri = Uri.parse(filePath);
return ContentUriUtils.getDisplayName(
uri, mContentResolver, MediaStore.MediaColumns.DISPLAY_NAME);
}
}
}
......@@ -230,16 +230,19 @@ bool AwWebContentsDelegate::IsFullscreenForTabOrPending(
static void FilesSelectedInChooser(
JNIEnv* env, jclass clazz,
jint process_id, jint render_id, jint mode_flags,
jobjectArray file_paths) {
jobjectArray file_paths, jobjectArray display_names) {
content::RenderViewHost* rvh = content::RenderViewHost::FromID(process_id,
render_id);
if (!rvh)
return;
std::vector<std::string> file_path_str;
std::vector<std::string> display_name_str;
// Note file_paths maybe NULL, but this will just yield a zero-length vector.
base::android::AppendJavaStringArrayToStringVector(env, file_paths,
&file_path_str);
base::android::AppendJavaStringArrayToStringVector(env, display_names,
&display_name_str);
std::vector<ui::SelectedFileInfo> files;
files.reserve(file_path_str.size());
for (size_t i = 0; i < file_path_str.size(); ++i) {
......@@ -247,7 +250,10 @@ static void FilesSelectedInChooser(
if (!url.is_valid())
continue;
base::FilePath path(url.SchemeIsFile() ? url.path() : file_path_str[i]);
files.push_back(ui::SelectedFileInfo(path, base::FilePath()));
ui::SelectedFileInfo file_info(path, base::FilePath());
if (!display_name_str[i].empty())
file_info.display_name = display_name_str[i];
files.push_back(file_info);
}
FileChooserParams::Mode mode;
if (mode_flags & kFileChooserModeOpenFolder) {
......
......@@ -6,6 +6,7 @@ package org.chromium.base;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;
......@@ -13,7 +14,7 @@ import android.util.Log;
/**
* This class provides methods to access content URI schemes.
*/
abstract class ContentUriUtils {
public abstract class ContentUriUtils {
private static final String TAG = "ContentUriUtils";
// Prevent instantiation.
......@@ -71,4 +72,35 @@ abstract class ContentUriUtils {
}
return pfd;
}
/**
* Method to resolve the display name of a content URI.
*
* @param uri the content URI to be resolved.
* @param contentResolver the content resolver to query.
* @param columnField the column field to query.
* @returns the display name of the @code uri if present in the database
* or an empty string otherwise.
*/
public static String getDisplayName(
Uri uri, ContentResolver contentResolver, String columnField) {
if (contentResolver == null || uri == null) return "";
Cursor cursor = null;
try {
cursor = contentResolver.query(uri, null, null, null, null);
if (cursor != null && cursor.getCount() >= 1) {
cursor.moveToFirst();
int index = cursor.getColumnIndex(columnField);
if (index > -1) return cursor.getString(index);
}
} catch (NullPointerException e) {
// Some android models don't handle the provider call correctly.
// see crbug.com/345393
return "";
} finally {
if (cursor != null) cursor.close();
}
return "";
}
}
......@@ -9,14 +9,15 @@ import android.app.Activity;
import android.content.ClipData;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import org.chromium.base.CalledByNative;
import org.chromium.base.ContentUriUtils;
import org.chromium.base.JNINamespace;
import org.chromium.ui.R;
......@@ -139,31 +140,6 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
return photoFile;
}
/**
* @return the display name of the @code uri if present in the database
* or an empty string otherwise.
*/
private String resolveFileName(Uri uri, ContentResolver contentResolver) {
if (contentResolver == null || uri == null) return "";
Cursor cursor = null;
try {
cursor = contentResolver.query(uri, null, null, null, null);
if (cursor != null && cursor.getCount() >= 1) {
cursor.moveToFirst();
int index = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
if (index > -1) return cursor.getString(index);
}
} catch (NullPointerException e) {
// Some android models don't handle the provider call correctly.
// see crbug.com/345393
return "";
} finally {
if (cursor != null) cursor.close();
}
return "";
}
/**
* Callback method to handle the intent results and pass on the path to the native
* SelectFileDialog.
......@@ -208,18 +184,12 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
return;
}
String[] filePathArray = new String[itemCount];
String[] displayNameArray = new String[itemCount];
Uri[] filePathArray = new Uri[itemCount];
for (int i = 0; i < itemCount; ++i) {
final Uri uri = clipData.getItemAt(i).getUri();
filePathArray[i] = uri.toString();
displayNameArray[i] = resolveFileName(uri, contentResolver);
filePathArray[i] = clipData.getItemAt(i).getUri();
}
nativeOnMultipleFilesSelected(mNativeSelectFileDialog,
filePathArray, displayNameArray);
GetDisplayNameTask task = new GetDisplayNameTask(contentResolver, true);
task.execute(filePathArray);
return;
}
......@@ -230,10 +200,8 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
}
if (ContentResolver.SCHEME_CONTENT.equals(results.getScheme())) {
nativeOnFileSelected(mNativeSelectFileDialog,
results.getData().toString(),
resolveFileName(results.getData(),
contentResolver));
GetDisplayNameTask task = new GetDisplayNameTask(contentResolver, false);
task.execute(results.getData());
return;
}
......@@ -295,6 +263,38 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
return false;
}
private class GetDisplayNameTask extends AsyncTask<Uri, Void, String[]> {
String[] mFilePaths;
final ContentResolver mContentResolver;
final boolean mIsMultiple;
public GetDisplayNameTask(ContentResolver contentResolver, boolean isMultiple) {
mContentResolver = contentResolver;
mIsMultiple = isMultiple;
}
@Override
protected String[] doInBackground(Uri...uris) {
mFilePaths = new String[uris.length];
String[] displayNames = new String[uris.length];
for (int i = 0; i < uris.length; i++) {
mFilePaths[i] = uris[i].toString();
displayNames[i] = ContentUriUtils.getDisplayName(
uris[i], mContentResolver, MediaStore.MediaColumns.DISPLAY_NAME);
}
return displayNames;
}
@Override
protected void onPostExecute(String[] result) {
if (mIsMultiple) {
nativeOnMultipleFilesSelected(mNativeSelectFileDialog, mFilePaths, result);
} else {
nativeOnFileSelected(mNativeSelectFileDialog, mFilePaths[0], result[0]);
}
}
}
@CalledByNative
private static SelectFileDialog create(long nativeSelectFileDialog) {
return new SelectFileDialog(nativeSelectFileDialog);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment