From 31837924ac41004a528c1c1988e39e634125a3dc Mon Sep 17 00:00:00 2001 From: Jorge Ruesga Date: Sat, 17 Nov 2012 01:56:01 +0100 Subject: [PATCH] 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 --- .../activities/PickerActivity.java | 107 +++++++++++++++++- .../preferences/DisplayRestrictions.java | 39 +++++++ .../tasks/SearchResultDrawingAsyncTask.java | 11 +- .../ui/widgets/NavigationView.java | 30 ++--- .../filemanager/util/FileHelper.java | 95 ++++++++++++++-- 5 files changed, 251 insertions(+), 31 deletions(-) create mode 100644 src/com/cyanogenmod/filemanager/preferences/DisplayRestrictions.java diff --git a/src/com/cyanogenmod/filemanager/activities/PickerActivity.java b/src/com/cyanogenmod/filemanager/activities/PickerActivity.java index e40106411..5d3c03365 100644 --- a/src/com/cyanogenmod/filemanager/activities/PickerActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/PickerActivity.java @@ -19,6 +19,7 @@ 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.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 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 void onReceive(Context context, Intent intent) { } }; - 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 void onConfigurationChanged(Configuration newConfig) { 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 restrictions = new HashMap(); + //- 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 void run() { // 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 @@ private boolean initializeConsole() { 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(); } diff --git a/src/com/cyanogenmod/filemanager/preferences/DisplayRestrictions.java b/src/com/cyanogenmod/filemanager/preferences/DisplayRestrictions.java new file mode 100644 index 000000000..2525ade4e --- /dev/null +++ b/src/com/cyanogenmod/filemanager/preferences/DisplayRestrictions.java @@ -0,0 +1,39 @@ +/* + * 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 +} diff --git a/src/com/cyanogenmod/filemanager/tasks/SearchResultDrawingAsyncTask.java b/src/com/cyanogenmod/filemanager/tasks/SearchResultDrawingAsyncTask.java index df91b8778..c53d59c61 100644 --- a/src/com/cyanogenmod/filemanager/tasks/SearchResultDrawingAsyncTask.java +++ b/src/com/cyanogenmod/filemanager/tasks/SearchResultDrawingAsyncTask.java @@ -28,6 +28,7 @@ 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 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 @@ protected Boolean doInBackground(Object... params) { boolean chRooted = FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) == 0; + // Create display restrictions + Map restrictions = + new HashMap(); + restrictions.put( + DisplayRestrictions.MIME_TYPE_RESTRICTION, MimeTypeHelper.ALL_MIME_TYPES); + //Process all the data final List 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() { diff --git a/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java b/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java index 24b1af59f..dd15c7efc 100644 --- a/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java +++ b/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java @@ -46,6 +46,7 @@ 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.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 void onItemFlingerEnd(OnItemFlingerResponder responder, private NAVIGATION_MODE mNavigationMode; - private String mMimeType = MimeTypeHelper.ALL_MIME_TYPES; + // Restrictions + private Map mRestrictions; /** * @hide @@ -318,6 +321,9 @@ private void init(TypedArray tarray) { this.mNavigationMode = NAVIGATION_MODE.values()[mode]; } + // Initialize default restrictions (no restrictions) + this.mRestrictions = new HashMap(); + //Initialize variables this.mFiles = new ArrayList(); @@ -345,23 +351,21 @@ private void init(TypedArray tarray) { } /** - * 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 The restrictions to apply */ - public String getMimeType() { - return this.mMimeType; + public Map 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 mRestrictions) { + this.mRestrictions = mRestrictions; } /** @@ -888,7 +892,7 @@ void onPostExecuteTask( //Apply user preferences List 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)) { diff --git a/src/com/cyanogenmod/filemanager/util/FileHelper.java b/src/com/cyanogenmod/filemanager/util/FileHelper.java index bd9049799..f4f3612eb 100644 --- a/src/com/cyanogenmod/filemanager/util/FileHelper.java +++ b/src/com/cyanogenmod/filemanager/util/FileHelper.java @@ -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.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.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 static String getHumanReadableSize(FileSystemObject fso) { * @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 static FileSystemObject getReference(FileSystemObject fso) { * (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 The applied mode listed files */ public static List applyUserPreferences( - List files, String mimeType, boolean chRooted) { - return applyUserPreferences(files, mimeType, false, chRooted); + List files, Map restrictions, boolean chRooted) { + return applyUserPreferences(files, restrictions, false, chRooted); } /** @@ -472,13 +479,14 @@ public static List applyUserPreferences( * (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 The applied mode listed files */ public static List applyUserPreferences( - List files, String mimeType, boolean noSort, boolean chRooted) { + List files, Map restrictions, + boolean noSort, boolean chRooted) { //Retrieve user preferences SharedPreferences prefs = Preferences.getSharedPreferences(); FileManagerSettings sortModePref = FileManagerSettings.SETTINGS_SORT_MODE; @@ -522,12 +530,10 @@ public static List applyUserPreferences( } } - //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 int compare(FileSystemObject lhs, FileSystemObject rhs) { 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 restrictions) { + Iterator 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.
* This method invokes the {@link ResolveLinkCommand} in those files that hasn't a valid