Upload Handler.

Change-Id: Ia6ed884ac558f4f5371c227bad992f3efc0feaee
diff --git a/src/com/android/browser/UploadHandler.java b/src/com/android/browser/UploadHandler.java
index e3eda33..655d642 100644
--- a/src/com/android/browser/UploadHandler.java
+++ b/src/com/android/browser/UploadHandler.java
@@ -18,8 +18,14 @@
 
 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.reflect.ReflectHelper;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Vector;
 
 /**
@@ -60,12 +68,18 @@
         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 @@
                 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 @@
         }
 
         if (mUploadMessage != null) {
+
             if (!isDRMFileType) {
                 mUploadMessage.onReceiveValue(result);
             } else {
@@ -152,6 +156,124 @@
         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 @@
 
         // 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 @@
                 // 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 @@
                 // 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 @@
                 // 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 @@
         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);