diff options
-rw-r--r-- | src/com/android/browser/UploadDialog.java | 109 | ||||
-rw-r--r-- | src/com/android/browser/UploadHandler.java | 208 |
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); |