OSDN Git Service

CMFileManager : Pass appropriate media type uri when ACTION_VIEW
[android-x86/packages-apps-CMFileManager.git] / src / com / cyanogenmod / filemanager / activities / PickerActivity.java
index 9fe0a42..3fe9c5d 100644 (file)
@@ -18,11 +18,17 @@ package com.cyanogenmod.filemanager.activities;
 
 import android.app.Activity;
 import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnCancelListener;
 import android.content.DialogInterface.OnDismissListener;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -42,40 +48,81 @@ import com.cyanogenmod.filemanager.adapters.CheckableListAdapter;
 import com.cyanogenmod.filemanager.adapters.CheckableListAdapter.CheckableItem;
 import com.cyanogenmod.filemanager.console.ConsoleBuilder;
 import com.cyanogenmod.filemanager.model.FileSystemObject;
+import com.cyanogenmod.filemanager.preferences.DisplayRestrictions;
 import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
 import com.cyanogenmod.filemanager.preferences.Preferences;
+import com.cyanogenmod.filemanager.ui.ThemeManager;
+import com.cyanogenmod.filemanager.ui.ThemeManager.Theme;
 import com.cyanogenmod.filemanager.ui.widgets.Breadcrumb;
 import com.cyanogenmod.filemanager.ui.widgets.ButtonItem;
 import com.cyanogenmod.filemanager.ui.widgets.NavigationView;
+import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnDirectoryChangedListener;
 import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnFilePickedListener;
 import com.cyanogenmod.filemanager.util.DialogHelper;
 import com.cyanogenmod.filemanager.util.ExceptionUtil;
 import com.cyanogenmod.filemanager.util.FileHelper;
+import com.cyanogenmod.filemanager.util.MediaHelper;
+import com.cyanogenmod.filemanager.util.MimeTypeHelper;
 import com.cyanogenmod.filemanager.util.StorageHelper;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * The activity for allow to use a {@link NavigationView} like, to pick a file from other
  * application.
  */
 public class PickerActivity extends Activity
-        implements OnCancelListener, OnDismissListener, OnFilePickedListener {
+        implements OnCancelListener, OnDismissListener, OnFilePickedListener, OnDirectoryChangedListener {
 
     private static final String TAG = "PickerActivity"; //$NON-NLS-1$
 
     private static boolean DEBUG = false;
 
-    private String mMimeType;
-    private FileSystemObject mFso;  // The picked item
+    private final BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent != null) {
+                if (intent.getAction().compareTo(FileManagerSettings.INTENT_THEME_CHANGED) == 0) {
+                    applyTheme();
+                }
+            }
+        }
+    };
+
+    // The result code
+    private static final int RESULT_CROP_IMAGE = 1;
+
+    // The component that holds the crop operation. We use Gallery3d because we are confidence
+    // of his input parameters
+    private static final ComponentName CROP_COMPONENT =
+                                    new ComponentName(
+                                            "com.android.gallery3d", //$NON-NLS-1$
+                                            "com.android.gallery3d.filtershow.crop.CropActivity"); //$NON-NLS-1$
+
+    // Gallery crop editor action
+    private static final String ACTION_CROP = "com.android.camera.action.CROP"; //$NON-NLS-1$
+
+    // Extra data for Gallery CROP action
+    private static final String EXTRA_CROP = "crop"; //$NON-NLS-1$
+
+    // Scheme for file and directory picking
+    private static final String FILE_URI_SCHEME = "file"; //$NON-NLS-1$
+    private static final String FOLDER_URI_SCHEME = "folder"; //$NON-NLS-1$
+    private static final String DIRECTORY_URI_SCHEME = "directory"; //$NON-NLS-1$
+
+    FileSystemObject mFso;  // The picked item
+    FileSystemObject mCurrentDirectory;
     private AlertDialog mDialog;
     private Handler mHandler;
     /**
      * @hide
      */
     NavigationView mNavigationView;
+    private View mRootView;
 
     /**
      * {@inheritDoc}
@@ -86,8 +133,14 @@ public class PickerActivity extends Activity
             Log.d(TAG, "PickerActivity.onCreate"); //$NON-NLS-1$
         }
 
-        //Request features
-        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        // Register the broadcast receiver
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(FileManagerSettings.INTENT_THEME_CHANGED);
+        registerReceiver(this.mNotificationReceiver, filter);
+
+        // Set the theme before setContentView
+        Theme theme = ThemeManager.getCurrentTheme(this);
+        theme.setBaseTheme(this, true);
 
         // Initialize the activity
         init();
@@ -97,20 +150,93 @@ public class PickerActivity extends Activity
     }
 
     /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void onDestroy() {
+        if (DEBUG) {
+            Log.d(TAG, "PickerActivity.onDestroy"); //$NON-NLS-1$
+        }
+
+        // Unregister the receiver
+        try {
+            unregisterReceiver(this.mNotificationReceiver);
+        } catch (Throwable ex) {
+            /**NON BLOCK**/
+        }
+
+        //All destroy. Continue
+        super.onDestroy();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        measureHeight();
+    }
+
+    /**
      * Method that displays a dialog with a {@link NavigationView} to select the
      * proposed file
      */
     private void init() {
-        // Check that call has a valid request (GET_CONTENT a and mime type)
-        String action = getIntent().getAction();
-        this.mMimeType = getIntent().getType();
-        if (action.compareTo(Intent.ACTION_GET_CONTENT.toString()) != 0 ||
-             this.mMimeType == null) {
+        final boolean pickingDirectory;
+        final Intent intent = getIntent();
+
+        if (isFilePickIntent(intent)) {
+            // ok
+            Log.d(TAG, "PickerActivity: got file pick intent: " + String.valueOf(intent)); //$NON-NLS-1$
+            pickingDirectory = false;
+        } else if (isDirectoryPickIntent(getIntent())) {
+            // ok
+            Log.d(TAG, "PickerActivity: got folder pick intent: " + String.valueOf(intent)); //$NON-NLS-1$
+            pickingDirectory = true;
+        } else {
+            Log.d(TAG, "PickerActivity got unrecognized intent: " + String.valueOf(intent)); //$NON-NLS-1$
             setResult(Activity.RESULT_CANCELED);
             finish();
             return;
         }
 
+        // Display restrictions
+        Map<DisplayRestrictions, Object> restrictions = new HashMap<DisplayRestrictions, Object>();
+        //- Mime/Type restriction
+        String mimeType = getIntent().getType();
+        if (mimeType != null) {
+            if (!MimeTypeHelper.isMimeTypeKnown(this, mimeType)) {
+                Log.i(TAG,
+                        String.format(
+                                "Mime type %s unknown, falling back to wildcard.", //$NON-NLS-1$
+                                mimeType));
+                mimeType = MimeTypeHelper.ALL_MIME_TYPES;
+            }
+            restrictions.put(DisplayRestrictions.MIME_TYPE_RESTRICTION, mimeType);
+        }
+        // Other restrictions
+        Bundle extras = getIntent().getExtras();
+        Log.d(TAG, "PickerActivity. extras: " + String.valueOf(extras)); //$NON-NLS-1$
+        if (extras != null) {
+            //-- File size
+            if (extras.containsKey(android.provider.MediaStore.Audio.Media.EXTRA_MAX_BYTES)) {
+                long size =
+                        extras.getLong(android.provider.MediaStore.Audio.Media.EXTRA_MAX_BYTES);
+                restrictions.put(DisplayRestrictions.SIZE_RESTRICTION, Long.valueOf(size));
+            }
+            //-- Local filesystems only
+            if (extras.containsKey(Intent.EXTRA_LOCAL_ONLY)) {
+                boolean localOnly = extras.getBoolean(Intent.EXTRA_LOCAL_ONLY);
+                restrictions.put(
+                        DisplayRestrictions.LOCAL_FILESYSTEM_ONLY_RESTRICTION,
+                        Boolean.valueOf(localOnly));
+            }
+        }
+        if (pickingDirectory) {
+            restrictions.put(DisplayRestrictions.DIRECTORY_ONLY_RESTRICTION, Boolean.TRUE);
+        }
+
         // Create or use the console
         if (!initializeConsole()) {
             // Something when wrong. Display a message and exit
@@ -119,25 +245,17 @@ public class PickerActivity extends Activity
             return;
         }
 
-        // Calculate the dialog size based on the window height
-        DisplayMetrics displaymetrics = new DisplayMetrics();
-        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
-        final int height = displaymetrics.heightPixels;
-
         // Create the root file
-        final View rootView = getLayoutInflater().inflate(R.layout.picker, null, false);
-        rootView.post(new Runnable() {
+        this.mRootView = getLayoutInflater().inflate(R.layout.picker, null, false);
+        this.mRootView.post(new Runnable() {
             @Override
             public void run() {
-                FrameLayout.LayoutParams params =
-                        new FrameLayout.LayoutParams(
-                                LayoutParams.WRAP_CONTENT, (height * 70) / 100);
-                rootView.setLayoutParams(params);
+                measureHeight();
             }
         });
 
         // Breadcrumb
-        Breadcrumb breadcrumb = (Breadcrumb)rootView.findViewById(R.id.breadcrumb_view);
+        Breadcrumb breadcrumb = (Breadcrumb)this.mRootView.findViewById(R.id.breadcrumb_view);
         // Set the free disk space warning level of the breadcrumb widget
         String fds = Preferences.getSharedPreferences().getString(
                 FileManagerSettings.SETTINGS_DISK_USAGE_WARNING_LEVEL.getId(),
@@ -146,16 +264,23 @@ public class PickerActivity extends Activity
 
         // Navigation view
         this.mNavigationView =
-                (NavigationView)rootView.findViewById(R.id.navigation_view);
-        this.mNavigationView.setMimeType(this.mMimeType);
+                (NavigationView)this.mRootView.findViewById(R.id.navigation_view);
+        this.mNavigationView.setRestrictions(restrictions);
         this.mNavigationView.setOnFilePickedListener(this);
+        this.mNavigationView.setOnDirectoryChangedListener(this);
         this.mNavigationView.setBreadcrumb(breadcrumb);
 
+        // Apply the current theme
+        applyTheme();
+
         // Create the dialog
         this.mDialog = DialogHelper.createDialog(
-            this, R.drawable.ic_launcher, R.string.picker_title, rootView);
+            this, R.drawable.ic_launcher,
+            pickingDirectory ? R.string.directory_picker_title : R.string.picker_title,
+            this.mRootView);
+
         this.mDialog.setButton(
-                DialogInterface.BUTTON_NEUTRAL,
+                DialogInterface.BUTTON_NEGATIVE,
                 getString(R.string.cancel),
                 new DialogInterface.OnClickListener() {
             @Override
@@ -163,36 +288,74 @@ public class PickerActivity extends Activity
                 dlg.cancel();
             }
         });
+        if (pickingDirectory) {
+            this.mDialog.setButton(
+                    DialogInterface.BUTTON_POSITIVE,
+                    getString(R.string.select),
+                    new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dlg, int which) {
+                    PickerActivity.this.mFso = PickerActivity.this.mCurrentDirectory;
+                    dlg.dismiss();
+                }
+            });
+        }
         this.mDialog.setCancelable(true);
         this.mDialog.setOnCancelListener(this);
         this.mDialog.setOnDismissListener(this);
-        this.mDialog.show();
+        DialogHelper.delegateDialogShow(this, this.mDialog);
 
         // Set content description of storage volume button
-        ButtonItem fs = (ButtonItem)rootView.findViewById(R.id.ab_filesystem_info);
+        ButtonItem fs = (ButtonItem)this.mRootView.findViewById(R.id.ab_filesystem_info);
         fs.setContentDescription(getString(R.string.actionbar_button_storage_cd));
 
+        final File initialDir = getInitialDirectoryFromIntent(getIntent());
+        final String rootDirectory;
+
+        if (initialDir != null) {
+            rootDirectory = initialDir.getAbsolutePath();
+        } else {
+            rootDirectory = FileHelper.ROOT_DIRECTORY;
+        }
+
         this.mHandler = new Handler();
         this.mHandler.post(new Runnable() {
             @Override
             public void run() {
                 // Navigate to. The navigation view will redirect to the appropriate directory
-                PickerActivity.this.mNavigationView.changeCurrentDir(FileHelper.ROOT_DIRECTORY);
+                PickerActivity.this.mNavigationView.changeCurrentDir(rootDirectory);
             }
         });
 
     }
 
     /**
+     * Method that measure the height needed to avoid resizing when
+     * change to a new directory. This method fixed the height of the window
+     * @hide
+     */
+    void measureHeight() {
+        // Calculate the dialog size based on the window height
+        DisplayMetrics displaymetrics = new DisplayMetrics();
+        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
+        final int height = displaymetrics.heightPixels;
+
+        Configuration config = getResources().getConfiguration();
+        int percent = config.orientation == Configuration.ORIENTATION_LANDSCAPE ? 55 : 70;
+
+        FrameLayout.LayoutParams params =
+                new FrameLayout.LayoutParams(
+                        LayoutParams.WRAP_CONTENT, (height * percent) / 100);
+        this.mRootView.setLayoutParams(params);
+    }
+
+    /**
      * Method that initializes a console
      */
     private boolean initializeConsole() {
         try {
-            // Is there a console allocate
-            if (!ConsoleBuilder.isAlloc()) {
-                // Create a ChRooted console
-                ConsoleBuilder.createDefaultConsole(this, false, false);
-            }
+            // Create a ChRooted console
+            ConsoleBuilder.createDefaultConsole(this, false, false);
             // There is a console allocated. Use it.
             return true;
         } catch (Throwable _throw) {
@@ -206,13 +369,26 @@ public class PickerActivity extends Activity
      * {@inheritDoc}
      */
     @Override
-    protected void onDestroy() {
-        if (DEBUG) {
-            Log.d(TAG, "PickerActivity.onDestroy"); //$NON-NLS-1$
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        switch (requestCode) {
+            case RESULT_CROP_IMAGE:
+                // Return what the callee activity returns
+                setResult(resultCode, data);
+                finish();
+                return;
+
+            default:
+                break;
         }
 
-        //All destroy. Continue
-        super.onDestroy();
+        // The response is not understood
+        Log.w(TAG,
+                String.format(
+                        "Ignore response. requestCode: %s, resultCode: %s, data: %s", //$NON-NLS-1$
+                        Integer.valueOf(requestCode),
+                        Integer.valueOf(resultCode),
+                        data));
+        DialogHelper.showToast(this, R.string.msgs_operation_failure, Toast.LENGTH_SHORT);
     }
 
     /**
@@ -221,15 +397,122 @@ public class PickerActivity extends Activity
     @Override
     public void onDismiss(DialogInterface dialog) {
         if (this.mFso != null) {
+            File src = new File(this.mFso.getFullPath());
+            if (getIntent().getExtras() != null) {
+                // Some AOSP applications use the gallery to edit and crop the selected image
+                // with the Gallery crop editor. In this case pass the picked file to the
+                // CropActivity with the requested parameters
+                // Expected result is on onActivityResult
+                Bundle extras = getIntent().getExtras();
+                String crop = extras.getString(EXTRA_CROP);
+                if (Boolean.parseBoolean(crop)) {
+                    // We want to use the Gallery3d activity because we know about it, and his
+                    // parameters. At least we have a compatible one.
+                    Intent intent = new Intent(ACTION_CROP);
+                    if (getIntent().getType() != null) {
+                        intent.setType(getIntent().getType());
+                    }
+                    intent.setData(Uri.fromFile(src));
+                    intent.putExtras(extras);
+                    intent.setComponent(CROP_COMPONENT);
+                    try {
+                        startActivityForResult(intent, RESULT_CROP_IMAGE);
+                        return;
+                    } catch (ActivityNotFoundException e) {
+                        Log.w(TAG, "Failed to find crop activity!");
+                    }
+                    intent.setComponent(null);
+                    try {
+                        startActivityForResult(intent, RESULT_CROP_IMAGE);
+                        return;
+                    } catch (ActivityNotFoundException e) {
+                        Log.w(TAG, "Failed to find any crop activity!");
+                    }
+                }
+            }
+
+            // Return the picked file, as expected (this activity should fill the intent data
+            // and return RESULT_OK result)
             Intent result = new Intent();
-            result.setData(Uri.fromFile(new File(this.mFso.getFullPath())));
+            result.setData(getResultUriForFileFromIntent(this, src, getIntent()));
             setResult(Activity.RESULT_OK, result);
             finish();
+
         } else {
             cancel();
         }
     }
 
+    private static boolean isFilePickIntent(Intent intent) {
+        final String action = intent.getAction();
+
+        if (Intent.ACTION_GET_CONTENT.equals(action)) {
+            return true;
+        }
+        if (Intent.ACTION_PICK.equals(action)) {
+            final Uri data = intent.getData();
+            if (data != null && FILE_URI_SCHEME.equals(data.getScheme())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private static boolean isDirectoryPickIntent(Intent intent) {
+        if (Intent.ACTION_PICK.equals(intent.getAction()) && intent.getData() != null) {
+            String scheme = intent.getData().getScheme();
+            if (FOLDER_URI_SCHEME.equals(scheme) || DIRECTORY_URI_SCHEME.equals(scheme)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private static File getInitialDirectoryFromIntent(Intent intent) {
+        if (!Intent.ACTION_PICK.equals(intent.getAction())) {
+            return null;
+        }
+
+        final Uri data = intent.getData();
+        if (data == null) {
+            return null;
+        }
+
+        final String path = data.getPath();
+        if (path == null) {
+            return null;
+        }
+
+        final File file = new File(path);
+        if (!file.exists() || !file.isAbsolute()) {
+            return null;
+        }
+
+        if (file.isDirectory()) {
+            return file;
+        }
+        return file.getParentFile();
+    }
+
+    private static Uri getResultUriForFileFromIntent(Context context, File src, Intent intent) {
+        // Try to find the preferred uri scheme
+        Uri result = MediaHelper.fileToContentUri(context, src);
+        if (result == null) {
+            result = Uri.fromFile(src);
+        }
+
+        if (Intent.ACTION_PICK.equals(intent.getAction()) && intent.getData() != null) {
+            String scheme = intent.getData().getScheme();
+            if (scheme != null) {
+                result = result.buildUpon().scheme(scheme).build();
+            }
+        }
+
+        return result;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -248,6 +531,14 @@ public class PickerActivity extends Activity
     }
 
     /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onDirectoryChanged(FileSystemObject item) {
+        this.mCurrentDirectory = item;
+    }
+
+    /**
      * Method invoked when an action item is clicked.
      *
      * @param view The button pushed
@@ -302,7 +593,6 @@ public class PickerActivity extends Activity
             public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                 popup.dismiss();
                 if (volumes != null) {
-
                     PickerActivity.this.
                         mNavigationView.changeCurrentDir(volumes[position].getPath());
                 }
@@ -310,4 +600,17 @@ public class PickerActivity extends Activity
         });
         popup.show();
     }
+
+    /**
+     * Method that applies the current theme to the activity
+     * @hide
+     */
+    void applyTheme() {
+        Theme theme = ThemeManager.getCurrentTheme(this);
+        theme.setBaseTheme(this, true);
+
+        // View
+        theme.setBackgroundDrawable(this, this.mRootView, "background_drawable"); //$NON-NLS-1$
+        this.mNavigationView.applyTheme();
+    }
 }