Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0f3469ab authored by Jorge Ruesga's avatar Jorge Ruesga
Browse files

CMFileManager: AOSP GET_CONTENT_DATA compatibility

This change brings compatibility to GET_CONTENT_DATA for AOSP apps when
using the PickerActivity:

* Detect crop extra; use the com.android.camera.action.CROP action of Gallery3d
to crop and return the requested image. This gets compatilibity for example with
the contacts app, when a user try to set the image of a contact.
* Detect android.provider.MediaStore.Audio.Media.EXTRA_MAX_BYTES; when this extra
is present the PickerActivity only display (and allow select) files with a size lower
than requested.
* Detect Intent.EXTRA_LOCAL_ONLY; useless until CMFM allow access remote file systems.

Change-Id: I1020458505b236653e869ec1c1f532dd6d686633
parent 8936a55d
Loading
Loading
Loading
Loading
+101 −6
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.cyanogenmod.filemanager.activities;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
@@ -45,6 +46,7 @@ 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;
@@ -60,7 +62,9 @@ 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
@@ -84,7 +88,22 @@ public class PickerActivity extends Activity
        }
    };

    private String mMimeType;
    // 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.app.CropImage"); //$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$

    private FileSystemObject mFso;  // The picked item
    private AlertDialog mDialog;
    private Handler mHandler;
@@ -151,14 +170,38 @@ public class PickerActivity extends Activity
    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) {

        if (action.compareTo(Intent.ACTION_GET_CONTENT.toString()) != 0) {
            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) {
            restrictions.put(DisplayRestrictions.MIME_TYPE_RESTRICTION, mimeType);
        }
        // Other restrictions
        Bundle extras = getIntent().getExtras();
        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));
            }
        }

        // Create or use the console
        if (!initializeConsole()) {
            // Something when wrong. Display a message and exit
@@ -187,7 +230,7 @@ public class PickerActivity extends Activity
        // Navigation view
        this.mNavigationView =
                (NavigationView)this.mRootView.findViewById(R.id.navigation_view);
        this.mNavigationView.setMimeType(this.mMimeType);
        this.mNavigationView.setRestrictions(restrictions);
        this.mNavigationView.setOnFilePickedListener(this);
        this.mNavigationView.setBreadcrumb(breadcrumb);

@@ -265,16 +308,68 @@ public class PickerActivity extends Activity
        return false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    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;
        }

        // 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);
    }

    /**
     * {@inheritDoc}
     */
    @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);
                    startActivityForResult(intent, RESULT_CROP_IMAGE);
                    return;
                }
            }

            // 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(Uri.fromFile(src));
            setResult(Activity.RESULT_OK, result);
            finish();

        } else {
            cancel();
        }
+39 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The CyanogenMod Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cyanogenmod.filemanager.preferences;

/**
 * An enumeration of the restrictions that can be applied when displaying list of files.
 */
public enum DisplayRestrictions {
    /**
     * Restriction for display only files with the category.
     */
    CATEGORY_TYPE_RESTRICTION,
    /**
     * Restriction for display only files with the mime/type.
     */
    MIME_TYPE_RESTRICTION,
    /**
     * Restriction for display only files with a size lower than the specified
     */
    SIZE_RESTRICTION,
    /**
     * Restriction for display only files from the local file system. Avoid remote files.
     */
    LOCAL_FILESYSTEM_ONLY_RESTRICTION
}
+10 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import com.cyanogenmod.filemanager.model.FileSystemObject;
import com.cyanogenmod.filemanager.model.Query;
import com.cyanogenmod.filemanager.model.SearchResult;
import com.cyanogenmod.filemanager.preferences.AccessMode;
import com.cyanogenmod.filemanager.preferences.DisplayRestrictions;
import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
import com.cyanogenmod.filemanager.preferences.NavigationSortMode;
import com.cyanogenmod.filemanager.preferences.ObjectStringIdentifier;
@@ -40,7 +41,9 @@ import com.cyanogenmod.filemanager.util.SearchHelper;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * A class for paint the resulting file system object of a search.
@@ -112,11 +115,17 @@ public class SearchResultDrawingAsyncTask extends AsyncTask<Object, Integer, Boo
            boolean chRooted =
                    FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) == 0;

            // Create display restrictions
            Map<DisplayRestrictions, Object> restrictions =
                    new HashMap<DisplayRestrictions, Object>();
            restrictions.put(
                    DisplayRestrictions.MIME_TYPE_RESTRICTION, MimeTypeHelper.ALL_MIME_TYPES);

            //Process all the data
            final List<SearchResult> result =
                    SearchHelper.convertToResults(
                            FileHelper.applyUserPreferences(
                                    this.mFiles, MimeTypeHelper.ALL_MIME_TYPES, true, chRooted),
                                    this.mFiles, restrictions, true, chRooted),
                            this.mQueries);
            if (mode.compareTo(SearchSortResultMode.NAME) == 0) {
                Collections.sort(result, new Comparator<SearchResult>() {
+17 −13
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import com.cyanogenmod.filemanager.model.Symlink;
import com.cyanogenmod.filemanager.parcelables.NavigationViewInfoParcelable;
import com.cyanogenmod.filemanager.parcelables.SearchInfoParcelable;
import com.cyanogenmod.filemanager.preferences.AccessMode;
import com.cyanogenmod.filemanager.preferences.DisplayRestrictions;
import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
import com.cyanogenmod.filemanager.preferences.NavigationLayoutMode;
import com.cyanogenmod.filemanager.preferences.ObjectIdentifier;
@@ -60,11 +61,12 @@ import com.cyanogenmod.filemanager.util.CommandHelper;
import com.cyanogenmod.filemanager.util.DialogHelper;
import com.cyanogenmod.filemanager.util.ExceptionUtil;
import com.cyanogenmod.filemanager.util.FileHelper;
import com.cyanogenmod.filemanager.util.MimeTypeHelper;
import com.cyanogenmod.filemanager.util.StorageHelper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The file manager implementation view (contains the graphical representation and the input
@@ -204,7 +206,8 @@ public class NavigationView extends RelativeLayout implements

    private NAVIGATION_MODE mNavigationMode;

    private String mMimeType = MimeTypeHelper.ALL_MIME_TYPES;
    // Restrictions
    private Map<DisplayRestrictions, Object> mRestrictions;

    /**
     * @hide
@@ -318,6 +321,9 @@ public class NavigationView extends RelativeLayout implements
            this.mNavigationMode = NAVIGATION_MODE.values()[mode];
        }

        // Initialize default restrictions (no restrictions)
        this.mRestrictions = new HashMap<DisplayRestrictions, Object>();

        //Initialize variables
        this.mFiles = new ArrayList<FileSystemObject>();

@@ -345,23 +351,21 @@ public class NavigationView extends RelativeLayout implements
    }

    /**
     * Method that returns the mime/type used by this class. Only the files with this mime/type
     * are shown.
     * Method that returns the display restrictions to apply to this view.
     *
     * @return String The mime/type
     * @return Map<DisplayRestrictions, Object> The restrictions to apply
     */
    public String getMimeType() {
        return this.mMimeType;
    public Map<DisplayRestrictions, Object> getRestrictions() {
        return this.mRestrictions;
    }

    /**
     * Method that sets the mime/type used by this class. Only the files with this mime/type
     * are shown.
     * Method that sets the display restrictions to apply to this view.
     *
     * @param mimeType String The mime/type
     * @param mRestrictions The restrictions to apply
     */
    public void setMimeType(String mimeType) {
        this.mMimeType = mimeType;
    public void setRestrictions(Map<DisplayRestrictions, Object> mRestrictions) {
        this.mRestrictions = mRestrictions;
    }

    /**
@@ -888,7 +892,7 @@ public class NavigationView extends RelativeLayout implements

            //Apply user preferences
            List<FileSystemObject> sortedFiles =
                    FileHelper.applyUserPreferences(files, this.mMimeType, this.mChRooted);
                    FileHelper.applyUserPreferences(files, this.mRestrictions, this.mChRooted);

            //Remove parent directory if we are in the root of a chrooted environment
            if (this.mChRooted && StorageHelper.isStorageVolume(newDir)) {
+84 −11
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.cyanogenmod.filemanager.util;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
@@ -39,10 +40,12 @@ import com.cyanogenmod.filemanager.model.RegularFile;
import com.cyanogenmod.filemanager.model.Symlink;
import com.cyanogenmod.filemanager.model.SystemFile;
import com.cyanogenmod.filemanager.model.User;
import com.cyanogenmod.filemanager.preferences.DisplayRestrictions;
import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
import com.cyanogenmod.filemanager.preferences.NavigationSortMode;
import com.cyanogenmod.filemanager.preferences.ObjectIdentifier;
import com.cyanogenmod.filemanager.preferences.Preferences;
import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -53,7 +56,9 @@ import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * A helper class with useful methods for deal with files.
@@ -156,6 +161,7 @@ public final class FileHelper {
     * @param size The size in bytes
     * @return String The human readable size
     */
    @SuppressLint("DefaultLocale")
    public static String getHumanReadableSize(long size) {
        Resources res = FileManagerApplication.getInstance().getResources();
        final String format = "%d %s"; //$NON-NLS-1$
@@ -458,13 +464,14 @@ public final class FileHelper {
     * (sort mode, hidden files, ...).
     *
     * @param files The listed files
     * @param mimeType The mime-type to apply. if null returns all.
     * @param restrictions The restrictions to apply when displaying files
     * @param chRooted If app run with no privileges
     * @return List<FileSystemObject> The applied mode listed files
     */
    public static List<FileSystemObject> applyUserPreferences(
                    List<FileSystemObject> files, String mimeType, boolean chRooted) {
        return applyUserPreferences(files, mimeType, false, chRooted);
                    List<FileSystemObject> files, Map<DisplayRestrictions,
                    Object> restrictions, boolean chRooted) {
        return applyUserPreferences(files, restrictions, false, chRooted);
    }

    /**
@@ -472,13 +479,14 @@ public final class FileHelper {
     * (sort mode, hidden files, ...).
     *
     * @param files The listed files
     * @param mimeType The mime-type to apply. if null returns all.
     * @param restrictions The restrictions to apply when displaying files
     * @param noSort If sort must be applied
     * @param chRooted If app run with no privileges
     * @return List<FileSystemObject> The applied mode listed files
     */
    public static List<FileSystemObject> applyUserPreferences(
            List<FileSystemObject> files, String mimeType, boolean noSort, boolean chRooted) {
            List<FileSystemObject> files, Map<DisplayRestrictions, Object> restrictions,
            boolean noSort, boolean chRooted) {
        //Retrieve user preferences
        SharedPreferences prefs = Preferences.getSharedPreferences();
        FileManagerSettings sortModePref = FileManagerSettings.SETTINGS_SORT_MODE;
@@ -522,12 +530,10 @@ public final class FileHelper {
                }
            }

            //Mime/Type
            if (chRooted && !isDirectory(file)) {
                if (mimeType != null && mimeType.compareTo(MimeTypeHelper.ALL_MIME_TYPES) != 0) {
                    // NOTE: We don't need the context here, because mime-type database should
                    // be loaded prior to this call
                    if (!MimeTypeHelper.matchesMimeType(null, file, mimeType)) {
            // Restrictions (only apply to files)
            if (restrictions != null) {
                if (!isDirectory(file)) {
                    if (!isDisplayAllowed(file, restrictions)) {
                        files.remove(i);
                        continue;
                    }
@@ -582,6 +588,73 @@ public final class FileHelper {
        return files;
    }

    /**
     * Method that check if a file should be displayed according to the restrictions
     *
     * @param fso The file system object to check
     * @param restrictions The restrictions map
     * @return boolean If the file should be displayed
     */
    private static boolean isDisplayAllowed(
            FileSystemObject fso, Map<DisplayRestrictions, Object> restrictions) {
        Iterator<DisplayRestrictions> it = restrictions.keySet().iterator();
        while (it.hasNext()) {
            DisplayRestrictions restriction = it.next();
            Object value = restrictions.get(restriction);
            if (value == null) {
                continue;
            }
            switch (restriction) {
                case CATEGORY_TYPE_RESTRICTION:
                    if (value instanceof MimeTypeCategory) {
                        MimeTypeCategory cat1 = (MimeTypeCategory)value;
                        // NOTE: We don't need the context here, because mime-type
                        // database should be loaded prior to this call
                        MimeTypeCategory cat2 = MimeTypeHelper.getCategory(null, fso);
                        if (cat1.compareTo(cat2) != 0) {
                            return false;
                        }
                    }
                    break;

                case MIME_TYPE_RESTRICTION:
                    if (value instanceof String) {
                        String mimeType = (String)value;
                        if (mimeType.compareTo(MimeTypeHelper.ALL_MIME_TYPES) != 0) {
                            // NOTE: We don't need the context here, because mime-type
                            // database should be loaded prior to this call
                            if (!MimeTypeHelper.matchesMimeType(null, fso, mimeType)) {
                                return false;
                            }
                        }
                    }
                    break;

                case SIZE_RESTRICTION:
                    if (value instanceof Long) {
                        Long maxSize = (Long)value;
                        if (fso.getSize() > maxSize.longValue()) {
                            return false;
                        }
                    }
                    break;

                case LOCAL_FILESYSTEM_ONLY_RESTRICTION:
                    if (value instanceof Boolean) {
                        Boolean localOnly = (Boolean)value;
                        if (localOnly.booleanValue()) {
                            /** TODO Needed when CMFM gets networking **/
                        }
                    }
                    break;

                default:
                    break;
            }
        }
        return true;
    }

    /**
     * Method that resolve the symbolic links of the list of files passed as argument.<br />
     * This method invokes the {@link ResolveLinkCommand} in those files that hasn't a valid