summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/browser/UploadDialog.java109
-rw-r--r--src/com/android/browser/UploadHandler.java208
2 files changed, 292 insertions, 25 deletions
diff --git a/src/com/android/browser/UploadDialog.java b/src/com/android/browser/UploadDialog.java
new file mode 100644
index 00000000..d96c4864
--- /dev/null
+++ b/src/com/android/browser/UploadDialog.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.android.browser;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UploadDialog extends AppItem {
+ public List<ResolveInfo> apps;
+ private Activity activity;
+ private List<Intent> uploadIntents;
+
+ public UploadDialog(Activity activity) {
+ super(null);
+ this.activity = activity;
+ this.apps = null;
+ }
+
+ public void getUploadableApps(List<Intent> intents) {
+
+ ArrayList<ResolveInfo> uploadApps = new ArrayList<ResolveInfo>();
+
+ PackageManager pm = activity.getPackageManager();
+
+ for (Intent currentIntent: intents) {
+ List<ResolveInfo> appsList = pm.queryIntentActivities(currentIntent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ for (ResolveInfo res : appsList) {
+ uploadApps.add(res);
+ }
+ }
+
+ this.apps = uploadApps;
+ this.uploadIntents = intents;
+ }
+
+ public void loadView(final UploadHandler uploadHandler) {
+
+ final AppAdapter adapter = new AppAdapter(activity, activity.getPackageManager(),
+ R.layout.app_row, this.apps);
+
+
+ AlertDialog.Builder builderSingle = new AlertDialog.Builder(activity);
+ builderSingle.setIcon(R.mipmap.ic_launcher_browser_swe);
+ builderSingle.setTitle(activity.getString(R.string.choose_upload));
+
+ builderSingle.setAdapter(adapter, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int position) {
+ dialog.dismiss();
+ Intent chooserIntent = Intent.createChooser(uploadIntents.get(position), "Upload Via");
+ uploadHandler.initiateActivity(chooserIntent);
+ }
+ });
+
+
+ builderSingle.setOnCancelListener(new DialogInterface.OnCancelListener()
+ {
+ @Override
+ public void onCancel(DialogInterface dialog)
+ {
+ uploadHandler.setHandled(false);
+ dialog.dismiss();
+ }
+ });
+
+ builderSingle.show();
+
+ }
+} \ No newline at end of file
diff --git a/src/com/android/browser/UploadHandler.java b/src/com/android/browser/UploadHandler.java
index e3eda33a..655d642b 100644
--- a/src/com/android/browser/UploadHandler.java
+++ b/src/com/android/browser/UploadHandler.java
@@ -18,8 +18,14 @@ package com.android.browser;
import android.app.Activity;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
@@ -32,6 +38,8 @@ import com.android.browser.R;
import com.android.browser.reflect.ReflectHelper;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Vector;
/**
@@ -60,12 +68,18 @@ public class UploadHandler {
return mCameraFilePath;
}
- boolean handled() {
+ protected boolean handled() {
return mHandled;
}
- void onResult(int resultCode, Intent intent) {
+ protected void setHandled(boolean handled) {
+ mHandled = handled;
+ mCaughtActivityNotFoundException = false;
+ if (!mHandled)
+ mUploadFilePaths.onReceiveValue(null);
+ }
+ void onResult(int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
// Couldn't resolve an activity, we are going to try again so skip
// this result.
@@ -102,19 +116,8 @@ public class UploadHandler {
filePath = result.getPath();
hasGoodFilePath = filePath != null && !filePath.isEmpty();
} else if ("content".equals(scheme)) {
- ContentResolver cr = mController.getActivity().getContentResolver();
- String[] projection = {"_data"};
- Cursor c = cr.query(result, projection, null, null, null);
- try {
- if (c != null && c.moveToFirst()) {
- filePath = c.getString(0);
- hasGoodFilePath = filePath != null && !filePath.isEmpty();
- }
- } finally {
- if (c != null) {
- c.close();
- }
- }
+ filePath = getFilePath(mController.getContext(), result);
+ hasGoodFilePath = filePath != null && !filePath.isEmpty();
}
}
@@ -132,6 +135,7 @@ public class UploadHandler {
}
if (mUploadMessage != null) {
+
if (!isDRMFileType) {
mUploadMessage.onReceiveValue(result);
} else {
@@ -152,6 +156,124 @@ public class UploadHandler {
mCaughtActivityNotFoundException = false;
}
+
+ public String getDocumentId(final Uri uri) {
+ String id = null;
+ try {
+ Object[] params = {(android.net.Uri)uri};
+ Class[] type = new Class[] {Class.forName("android.net.Uri") };
+ id = (String) ReflectHelper.invokeMethod(
+ "android.provider.DocumentsContract","getDocumentId",
+ type, params);
+
+ } catch(java.lang.ClassNotFoundException e) {
+
+ }
+ return id;
+ }
+
+
+ public String getFilePath(final Context context, final Uri uri) {
+ String id = getDocumentId(uri);
+
+ // DocumentProvider is new API exposed in Kitkat
+ // Its a way of exposing unified file explorer
+ if (id != null) {
+ // ExternalStorageProvider
+ if (isExternalStorageDocument(uri)) {
+ final String docId = id;
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ if ("primary".equalsIgnoreCase(type)) {
+ return Environment.getExternalStorageDirectory() + "/" + split[1];
+ }
+ }
+ // DownloadsProvider
+ else if (isDownloadsDocument(uri)) {
+ final Uri contentUri = ContentUris.withAppendedId(
+ Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
+ return getDataColumn(context, contentUri, null, null);
+ }
+ // MediaProvider
+ else if (isMediaDocument(uri)) {
+ final String docId = id;
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ Uri contentUri = null;
+ if ("image".equals(type)) {
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ } else if ("video".equals(type)) {
+ contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
+ } else if ("audio".equals(type)) {
+ contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+ }
+
+ final String selection = "_id=?";
+ final String[] selectionArgs = new String[] {
+ split[1]
+ };
+
+ return getDataColumn(context, contentUri, selection, selectionArgs);
+ }
+ }
+ // MediaStore (and general)
+ else if ("content".equalsIgnoreCase(uri.getScheme())) {
+ return getDataColumn(context, uri, null, null);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the value of the data column for this Uri. This is useful for
+ * MediaStore Uris, and other file-based ContentProviders.
+ * @return The value of the _data column, which is typically a file path.
+ */
+ private String getDataColumn(Context context, Uri uri, String selection,
+ String[] selectionArgs) {
+
+ Cursor cursor = null;
+ final String column = "_data";
+ final String[] projection = { column };
+
+ try {
+ cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
+ null);
+ if (cursor != null && cursor.moveToFirst()) {
+ final int column_index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(column_index);
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ return null;
+ }
+
+ /**
+ * @return Whether the Uri authority is ExternalStorageProvider.
+ */
+ private boolean isExternalStorageDocument(Uri uri) {
+ return "com.android.externalstorage.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @return Whether the Uri authority is DownloadsProvider.
+ */
+ private boolean isDownloadsDocument(Uri uri) {
+ return "com.android.providers.downloads.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @return Whether the Uri authority is MediaProvider.
+ */
+ public static boolean isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri.getAuthority());
+ }
+
+
void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
final String imageMimeType = "image/*";
@@ -273,6 +395,7 @@ public class UploadHandler {
// Ensure it is not still set from a previous upload.
mCameraFilePath = null;
+ List<Intent> intentList = new ArrayList<Intent>();
if (mimeType.equals(imageMimeType)) {
if (capture) {
@@ -284,9 +407,8 @@ public class UploadHandler {
// Specified just 'image/*', capture=false, or no capture value.
// In all these cases we show a traditional picker filetered on accept type
// so launch an intent for both the Camera and image/* OPENABLE.
- Intent chooser = createChooserIntent(createCameraIntent());
- chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
- startActivity(chooser);
+ intentList.add(createCameraIntent());
+ createUploadDialog(imageMimeType, intentList);
return;
}
} else if (mimeType.equals(videoMimeType)) {
@@ -299,9 +421,8 @@ public class UploadHandler {
// Specified just 'video/*', capture=false, or no capture value.
// In all these cases we show an intent for the traditional file picker, filtered
// on accept type so launch an intent for both camcorder and video/* OPENABLE.
- Intent chooser = createChooserIntent(createCamcorderIntent());
- chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
- startActivity(chooser);
+ intentList.add(createCamcorderIntent());
+ createUploadDialog(videoMimeType, intentList);
return;
}
} else if (mimeType.equals(audioMimeType)) {
@@ -314,16 +435,15 @@ public class UploadHandler {
// Specified just 'audio/*', capture=false, or no capture value.
// In all these cases so go ahead and launch an intent for both the sound
// recorder and audio/* OPENABLE.
- Intent chooser = createChooserIntent(createSoundRecorderIntent());
- chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
- startActivity(chooser);
+ intentList.add(createSoundRecorderIntent());
+ createUploadDialog(audioMimeType, intentList);
return;
}
}
// No special handling based on the accept type was necessary, so trigger the default
// file upload chooser.
- startActivity(createDefaultOpenableIntent());
+ createUploadDialog("*/*", null);
}
@@ -356,9 +476,47 @@ public class UploadHandler {
Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, i);
+
return chooser;
}
+
+ private void createUploadDialog(String openableMimeType, List<Intent> intentList) {
+
+ Intent openable = new Intent(Intent.ACTION_GET_CONTENT);
+ openable.addCategory(Intent.CATEGORY_OPENABLE);
+ openable.setType(openableMimeType);
+
+ if (openableMimeType.equals("*/*") && intentList == null) {
+ intentList = new ArrayList<Intent>();
+ intentList.add(createCameraIntent());
+ intentList.add(createCamcorderIntent());
+ intentList.add(createSoundRecorderIntent());
+ }
+
+ // get all openable apps list and create corresponading intents
+ PackageManager pm = mController.getActivity().getPackageManager();
+ List<ResolveInfo> openableAppsList = pm.queryIntentActivities(openable, 0);
+ for (int j = 0, n = openableAppsList.size(); j < n; j++ ) {
+ Intent i = new Intent(Intent.ACTION_GET_CONTENT);
+ i.setType(openableMimeType);
+ ActivityInfo activityInfo = openableAppsList.get(j).activityInfo;
+ ComponentName name = new ComponentName(activityInfo.applicationInfo.packageName,
+ activityInfo.name);
+ i.setComponent(name);
+ intentList.add(i);
+ }
+
+
+ UploadDialog upDialog = new UploadDialog(mController.getActivity());
+ upDialog.getUploadableApps(intentList);
+ upDialog.loadView(this);
+ }
+
+ public void initiateActivity(Intent intent) {
+ startActivity(intent);
+ }
+
private Intent createChooserIntent(Intent... intents) {
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);