diff --git a/README.markdown b/README.markdown index cb4619c..5011579 100644 --- a/README.markdown +++ b/README.markdown @@ -46,8 +46,14 @@ Use `startActivityForResult(Intent, int)` to launch the "Intent Chooser" dialog public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Intent getContentIntent = FileUtils.createGetContentIntent(); - Intent intent = Intent.createChooser(getContentIntent, "Select a file"); + Intent intent = new Intent(this, FileChooserActivity.class); + + //Add the following statement only if you want to set a custom root path for the chooser: + intent.putExtra(FileChooserActivity.PATH, "/your/custom/path"); + + //Add the following statement only if you want to enable the user to select only a single file type + intent.putExtra(FileChooserActivity.ALLOWED_FILE_EXTENSION, "pdf") + startActivityForResult(intent, REQUEST_CHOOSER); } diff --git a/aFileChooser/.classpath b/aFileChooser/.classpath index e4781b7..ba3edb4 100644 --- a/aFileChooser/.classpath +++ b/aFileChooser/.classpath @@ -5,5 +5,6 @@ + diff --git a/aFileChooser/.settings/org.eclipse.jdt.core.prefs b/aFileChooser/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..b080d2d --- /dev/null +++ b/aFileChooser/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/aFileChooser/libs/android-support-v4.jar b/aFileChooser/libs/android-support-v4.jar index 428bdbc..cf12d28 100644 Binary files a/aFileChooser/libs/android-support-v4.jar and b/aFileChooser/libs/android-support-v4.jar differ diff --git a/aFileChooser/src/com/ipaulpro/afilechooser/FileChooserActivity.java b/aFileChooser/src/com/ipaulpro/afilechooser/FileChooserActivity.java index a7e63bb..79e982e 100644 --- a/aFileChooser/src/com/ipaulpro/afilechooser/FileChooserActivity.java +++ b/aFileChooser/src/com/ipaulpro/afilechooser/FileChooserActivity.java @@ -1,21 +1,24 @@ -/* +/* * Copyright (C) 2013 Paul Burke - * - * 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. - */ + * + * 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.ipaulpro.afilechooser; +import java.io.File; + +import android.annotation.SuppressLint; import android.app.ActionBar; import android.content.BroadcastReceiver; import android.content.Context; @@ -34,36 +37,37 @@ import android.view.MenuItem; import android.widget.Toast; -import java.io.File; - /** - * Main Activity that handles the FileListFragments - * + * Main Activity that handles the FileListFragments + * * @version 2013-06-25 - * + * * @author paulburke (ipaulpro) - * + * @author alexbbb */ +@SuppressLint("NewApi") public class FileChooserActivity extends FragmentActivity implements OnBackStackChangedListener { public static final String PATH = "path"; + public static final String ALLOWED_FILE_EXTENSION = "allowedFileExtension"; public static final String EXTERNAL_BASE_PATH = Environment .getExternalStorageDirectory().getAbsolutePath(); private static final boolean HAS_ACTIONBAR = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; private FragmentManager mFragmentManager; - private BroadcastReceiver mStorageListener = new BroadcastReceiver() { + private final BroadcastReceiver mStorageListener = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, R.string.storage_removed, Toast.LENGTH_LONG).show(); finishWithResult(null); } }; - + private String mPath; - + private String mAllowedExtension; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -73,11 +77,34 @@ protected void onCreate(Bundle savedInstanceState) { mFragmentManager = getSupportFragmentManager(); mFragmentManager.addOnBackStackChangedListener(this); - if (savedInstanceState == null) { - mPath = EXTERNAL_BASE_PATH; - addFragment(); - } else { - mPath = savedInstanceState.getString(PATH); + Intent intent = getIntent(); + if (intent != null) { + final String customPath = intent.getStringExtra(PATH); + if (customPath != null && !customPath.equals("")) { + mPath = customPath; + } + + final String allowedExtension = intent.getStringExtra(ALLOWED_FILE_EXTENSION); + if (allowedExtension != null) { + mAllowedExtension = allowedExtension; + } + } + + if (mPath == null) { + if (savedInstanceState == null) { + mPath = EXTERNAL_BASE_PATH; + addFragment(); + } else { + mPath = savedInstanceState.getString(PATH); + } + } + + if (mAllowedExtension == null) { + if (savedInstanceState == null) { + mAllowedExtension = ""; + } else { + mAllowedExtension = savedInstanceState.getString(ALLOWED_FILE_EXTENSION); + } } setTitle(mPath); @@ -86,27 +113,28 @@ protected void onCreate(Bundle savedInstanceState) { @Override protected void onPause() { super.onPause(); - + unregisterStorageListener(); } @Override protected void onResume() { super.onResume(); - + registerStorageListener(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - + outState.putString(PATH, mPath); + outState.putString(ALLOWED_FILE_EXTENSION, mAllowedExtension); } @Override public void onBackStackChanged() { - + int count = mFragmentManager.getBackStackEntryCount(); if (count > 0) { BackStackEntry fragment = mFragmentManager.getBackStackEntryAt(count - 1); @@ -114,24 +142,24 @@ public void onBackStackChanged() { } else { mPath = EXTERNAL_BASE_PATH; } - + setTitle(mPath); if (HAS_ACTIONBAR) invalidateOptionsMenu(); } - + @Override public boolean onCreateOptionsMenu(Menu menu) { if (HAS_ACTIONBAR) { boolean hasBackStack = mFragmentManager.getBackStackEntryCount() > 0; - + ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(hasBackStack); actionBar.setHomeButtonEnabled(hasBackStack); } - + return true; } - + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { @@ -147,7 +175,7 @@ public boolean onOptionsItemSelected(MenuItem item) { * Add the initial Fragment with given path. */ private void addFragment() { - FileListFragment fragment = FileListFragment.newInstance(mPath); + FileListFragment fragment = FileListFragment.newInstance(mPath, mAllowedExtension); mFragmentManager.beginTransaction() .add(R.id.explorer_fragment, fragment).commit(); } @@ -155,13 +183,13 @@ private void addFragment() { /** * "Replace" the existing Fragment with a new one using given path. * We're really adding a Fragment to the back stack. - * + * * @param file The file (directory) to display. */ private void replaceFragment(File file) { mPath = file.getAbsolutePath(); - FileListFragment fragment = FileListFragment.newInstance(mPath); + FileListFragment fragment = FileListFragment.newInstance(mPath, mAllowedExtension); mFragmentManager.beginTransaction() .replace(R.id.explorer_fragment, fragment) .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) @@ -170,7 +198,7 @@ private void replaceFragment(File file) { /** * Finish this Activity with a result code and URI of the selected file. - * + * * @param file The file selected. */ private void finishWithResult(File file) { @@ -179,14 +207,14 @@ private void finishWithResult(File file) { setResult(RESULT_OK, new Intent().setData(uri)); finish(); } else { - setResult(RESULT_CANCELED); + setResult(RESULT_CANCELED); finish(); } } - + /** * Called when the user selects a File - * + * * @param file The file that was selected */ protected void onFileSelected(File file) { @@ -194,13 +222,13 @@ protected void onFileSelected(File file) { if (file.isDirectory()) { replaceFragment(file); } else { - finishWithResult(file); + finishWithResult(file); } } else { Toast.makeText(FileChooserActivity.this, R.string.error_selecting_file, Toast.LENGTH_SHORT).show(); } } - + /** * Register the external storage BroadcastReceiver. */ diff --git a/aFileChooser/src/com/ipaulpro/afilechooser/FileListFragment.java b/aFileChooser/src/com/ipaulpro/afilechooser/FileListFragment.java index 59420ef..0afe988 100644 --- a/aFileChooser/src/com/ipaulpro/afilechooser/FileListFragment.java +++ b/aFileChooser/src/com/ipaulpro/afilechooser/FileListFragment.java @@ -1,21 +1,24 @@ -/* +/* * Copyright (C) 2012 Paul Burke - * - * 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. - */ + * + * 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.ipaulpro.afilechooser; +import java.io.File; +import java.util.List; + import android.os.Bundle; import android.os.Environment; import android.support.v4.app.ListFragment; @@ -24,16 +27,13 @@ import android.view.View; import android.widget.ListView; -import java.io.File; -import java.util.List; - /** * Fragment that displays a list of Files in a given path. - * + * * @version 2012-10-28 - * + * * @author paulburke (ipaulpro) - * + * */ public class FileListFragment extends ListFragment implements LoaderManager.LoaderCallbacks> { @@ -42,17 +42,19 @@ public class FileListFragment extends ListFragment implements private FileListAdapter mAdapter; private String mPath; + private String mAllowedFileExtension; /** * Create a new instance with the given file path. - * + * * @param path The absolute path of the file (directory) to display. - * @return A new Fragment with the given file path. + * @return A new Fragment with the given file path. */ - public static FileListFragment newInstance(String path) { + public static FileListFragment newInstance(String path, String allowedFiles) { FileListFragment fragment = new FileListFragment(); Bundle args = new Bundle(); args.putString(FileChooserActivity.PATH, path); + args.putString(FileChooserActivity.ALLOWED_FILE_EXTENSION, allowedFiles); fragment.setArguments(args); return fragment; @@ -66,6 +68,9 @@ public void onCreate(Bundle savedInstanceState) { mPath = getArguments() != null ? getArguments().getString( FileChooserActivity.PATH) : Environment .getExternalStorageDirectory().getAbsolutePath(); + + mAllowedFileExtension = getArguments() != null ? getArguments().getString( + FileChooserActivity.ALLOWED_FILE_EXTENSION) : ""; } @Override @@ -75,7 +80,7 @@ public void onActivityCreated(Bundle savedInstanceState) { setListShown(false); getLoaderManager().initLoader(LOADER_ID, null, this); - + super.onActivityCreated(savedInstanceState); } @@ -91,7 +96,7 @@ public void onListItemClick(ListView l, View v, int position, long id) { @Override public Loader> onCreateLoader(int id, Bundle args) { - return new FileLoader(getActivity(), mPath); + return new FileLoader(getActivity(), mPath, mAllowedFileExtension); } @Override diff --git a/aFileChooser/src/com/ipaulpro/afilechooser/FileLoader.java b/aFileChooser/src/com/ipaulpro/afilechooser/FileLoader.java index cb36a2b..1bcff1a 100644 --- a/aFileChooser/src/com/ipaulpro/afilechooser/FileLoader.java +++ b/aFileChooser/src/com/ipaulpro/afilechooser/FileLoader.java @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2012 Paul Burke - * - * 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. - */ + * + * 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.ipaulpro.afilechooser; @@ -27,11 +27,11 @@ /** * Loader that returns a list of Files in a given file path. - * + * * @version 2012-10-28 - * + * * @author paulburke (ipaulpro) - * + * */ public class FileLoader extends AsyncTaskLoader> { @@ -39,20 +39,22 @@ public class FileLoader extends AsyncTaskLoader> { | FileObserver.DELETE | FileObserver.DELETE_SELF | FileObserver.MOVED_FROM | FileObserver.MOVED_TO | FileObserver.MODIFY | FileObserver.MOVE_SELF; - + private FileObserver mFileObserver; - + private List mData; - private String mPath; + private final String mPath; + private final String mAllowedExtension; - public FileLoader(Context context, String path) { + public FileLoader(Context context, String path, String allowedExtension) { super(context); this.mPath = path; + this.mAllowedExtension = allowedExtension; } @Override public List loadInBackground() { - return FileUtils.getFileList(mPath); + return FileUtils.getFileList(mPath, mAllowedExtension); } @Override @@ -64,7 +66,7 @@ public void deliverResult(List data) { List oldData = mData; mData = data; - + if (isStarted()) super.deliverResult(data); @@ -81,12 +83,12 @@ protected void onStartLoading() { mFileObserver = new FileObserver(mPath, FILE_OBSERVER_MASK) { @Override public void onEvent(int event, String path) { - onContentChanged(); + onContentChanged(); } }; } mFileObserver.startWatching(); - + if (takeContentChanged() || mData == null) forceLoad(); } @@ -114,7 +116,7 @@ public void onCanceled(List data) { } protected void onReleaseResources(List data) { - + if (mFileObserver != null) { mFileObserver.stopWatching(); mFileObserver = null; diff --git a/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java b/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java index ab49760..77918f1 100644 --- a/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java +++ b/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2007-2008 OpenIntents.org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -41,7 +41,7 @@ /** * @version 2009-07-03 - * + * * @author Peli * */ @@ -50,15 +50,15 @@ public class FileUtils { static final String TAG = "FileUtils"; private static final boolean DEBUG = false; // Set to true to enable logging - public static final String MIME_TYPE_AUDIO = "audio/*"; - public static final String MIME_TYPE_TEXT = "text/*"; - public static final String MIME_TYPE_IMAGE = "image/*"; - public static final String MIME_TYPE_VIDEO = "video/*"; + public static final String MIME_TYPE_AUDIO = "audio/*"; + public static final String MIME_TYPE_TEXT = "text/*"; + public static final String MIME_TYPE_IMAGE = "image/*"; + public static final String MIME_TYPE_VIDEO = "video/*"; public static final String MIME_TYPE_APP = "application/*"; /** * Whether the filename is a video file. - * + * * @param filename * @return *//* @@ -73,7 +73,7 @@ public static boolean isVideo(String filename) { /** * Whether the URI is a local one. - * + * * @param uri * @return */ @@ -86,7 +86,7 @@ public static boolean isLocal(String uri) { /** * Gets the extension of a file name, like ".png" or ".jpg". - * + * * @param uri * @return Extension including the dot("."); "" if there is no extension; * null if uri was null. @@ -107,7 +107,7 @@ public static String getExtension(String uri) { /** * Returns true if uri is a media uri. - * + * * @param uri * @return */ @@ -177,7 +177,7 @@ public static File getPathWithoutFilename(File file) { /** * Constructs a file from a path and file name. - * + * * @param curdir * @param file * @return @@ -199,19 +199,19 @@ public static File getFile(File curdir, String file) { /** * Get a file path from a Uri. - * + * * @param context * @param uri * @return * @throws URISyntaxException - * + * * @author paulburke */ public static String getPath(Context context, Uri uri) throws URISyntaxException { - if(DEBUG) Log.d(TAG+" File -", - "Authority: " + uri.getAuthority() + - ", Fragment: " + uri.getFragment() + + if(DEBUG) Log.d(TAG+" File -", + "Authority: " + uri.getAuthority() + + ", Fragment: " + uri.getFragment() + ", Port: " + uri.getPort() + ", Query: " + uri.getQuery() + ", Scheme: " + uri.getScheme() + @@ -244,10 +244,10 @@ else if ("file".equalsIgnoreCase(uri.getScheme())) { /** * Get the file size in a human-readable string. - * + * * @param size * @return - * + * * @author paulburke */ public static String getReadableFileSize(int size) { @@ -276,7 +276,7 @@ public static String getReadableFileSize(int size) { /** * Load MIME types from XML - * + * * @param context * @return */ @@ -291,11 +291,11 @@ private static MimeTypes getMimeTypes(Context context) { if(DEBUG) Log.e(TAG, "getMimeTypes", e); } return mimeTypes; - } + } /** * Get the file MIME type - * + * * @param context * @param file * @return @@ -309,79 +309,79 @@ public static String getMimeType(Context context, File file) { /** * Attempt to retrieve the thumbnail of given File from the MediaStore. - * + * * This should not be called on the UI thread. - * + * * @param context * @param file * @return - * + * * @author paulburke */ public static Bitmap getThumbnail(Context context, File file) { return getThumbnail(context, getUri(file), getMimeType(context, file)); } - + /** * Attempt to retrieve the thumbnail of given Uri from the MediaStore. - * + * * This should not be called on the UI thread. - * + * * @param context * @param uri * @return - * + * * @author paulburke */ public static Bitmap getThumbnail(Context context, Uri uri) { return getThumbnail(context, uri, getMimeType(context, getFile(uri))); } - + /** * Attempt to retrieve the thumbnail of given Uri from the MediaStore. - * + * * This should not be called on the UI thread. - * + * * @param context * @param uri * @param mimeType * @return - * + * * @author paulburke */ public static Bitmap getThumbnail(Context context, Uri uri, String mimeType) { if(DEBUG) Log.d(TAG, "Attempting to get thumbnail"); - + if (isMediaUri(uri)) { Log.e(TAG, "You can only retrieve thumbnails for images and videos."); return null; } - + Bitmap bm = null; if (uri != null) { final ContentResolver resolver = context.getContentResolver(); - Cursor cursor = null; + Cursor cursor = null; try { - cursor = resolver.query(uri, null, null,null, null); + cursor = resolver.query(uri, null, null,null, null); if (cursor.moveToFirst()) { final int id = cursor.getInt(0); - if(DEBUG) Log.d(TAG, "Got thumb ID: "+id); + if(DEBUG) Log.d(TAG, "Got thumb ID: "+id); if (mimeType.contains("video")) { bm = MediaStore.Video.Thumbnails.getThumbnail( - resolver, - id, - MediaStore.Video.Thumbnails.MINI_KIND, + resolver, + id, + MediaStore.Video.Thumbnails.MINI_KIND, null); - } + } else if (mimeType.contains(FileUtils.MIME_TYPE_IMAGE)) { bm = MediaStore.Images.Thumbnails.getThumbnail( - resolver, - id, - MediaStore.Images.Thumbnails.MINI_KIND, + resolver, + id, + MediaStore.Images.Thumbnails.MINI_KIND, null); } - } + } } catch (Exception e) { if(DEBUG) Log.e(TAG, "getThumbnail", e); } finally { @@ -390,63 +390,72 @@ else if (mimeType.contains(FileUtils.MIME_TYPE_IMAGE)) { } return bm; } - + private static final String HIDDEN_PREFIX = "."; /** * File and folder comparator. - * TODO Expose sorting option method - * + * TODO Expose sorting option method + * * @author paulburke */ private static Comparator mComparator = new Comparator() { - public int compare(File f1, File f2) { + @Override + public int compare(File f1, File f2) { // Sort alphabetically by lower case, which is much cleaner return f1.getName().toLowerCase().compareTo( f2.getName().toLowerCase()); } }; - + /** * File (not directories) filter. - * + * * @author paulburke */ private static FileFilter mFileFilter = new FileFilter() { - public boolean accept(File file) { + @Override + public boolean accept(File file) { final String fileName = file.getName(); // Return files only (not directories) and skip hidden files return file.isFile() && !fileName.startsWith(HIDDEN_PREFIX); } }; - + /** * Folder (directories) filter. - * + * * @author paulburke */ private static FileFilter mDirFilter = new FileFilter() { - public boolean accept(File file) { + @Override + public boolean accept(File file) { final String fileName = file.getName(); // Return directories only and skip hidden directories return file.isDirectory() && !fileName.startsWith(HIDDEN_PREFIX); } }; - + /** * Get a list of Files in the give path - * + * * @param path + * @param allowedExtension * @return Collection of files in give directory * @author paulburke */ - public static List getFileList(String path) { + public static List getFileList(String path, final String allowedExtension) { ArrayList list = new ArrayList(); + File parent = new File(path).getParentFile(); + if (parent != null) { + list.add(parent); + } + // Current directory File instance final File pathDir = new File(path); - + // List file in this directory with the directory filter final File[] dirs = pathDir.listFiles(mDirFilter); if (dirs != null) { @@ -457,29 +466,46 @@ public static List getFileList(String path) { } // List file in this directory with the file filter - final File[] files = pathDir.listFiles(mFileFilter); + final File[] files; + + if (allowedExtension != null && !allowedExtension.equals("")) { + files = pathDir.listFiles(new FileFilter() { + + @Override + public boolean accept(File file) { + final String fileName = file.getName(); + // Return files only (not directories) and skip hidden files + return file.isFile() + && !fileName.startsWith(HIDDEN_PREFIX) + && fileName.endsWith(allowedExtension); + } + }); + } else { + files = pathDir.listFiles(mFileFilter); + } + if (files != null) { // Sort the files alphabetically Arrays.sort(files, mComparator); // Add each file to the File list for the list adapter for (File file : files) list.add(file); - } - + } + return list; } /** * Get the Intent for selecting content to be used in an Intent Chooser. - * + * * @return The intent for opening a file with Intent.createChooser() - * + * * @author paulburke */ public static Intent createGetContentIntent() { // Implicitly allow the user to select a particular kind of data - final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); // The MIME data type filter - intent.setType("*/*"); + intent.setType("*/*"); // Only return URIs that can be opened with ContentResolver intent.addCategory(Intent.CATEGORY_OPENABLE); return intent;