148

Does anyone know of a complete choose file dialog? Maybe one where you can filter out all files except for ones with specific extensions?

I have not found anything lightweight enough to implement easily into one of my projects. The only other option seems to be using OI FileManager's open intents, but that requires the user already having the file manager installed.

I would be grateful if someone could point out a Dialog that would allow the user to browse folders and select a file, and return the path.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Aymon Fournier
  • 4,323
  • 12
  • 42
  • 59
  • 5
    If, as you say, "the Internet needs such an example," then this is YOUR opportunity to create one for such a noble purpose. SO is not a "rent a coder" site. On the other hand, if you're trying to build/use a file selection dialog and run into problems, then this is the place to come with your specific question. – Cal Jacobson Sep 08 '10 at 22:13
  • 1
    check this http://www.dreamincode.net/forums/topic/190013-creating-simple-file-chooser/ – Dev.Sinto Nov 18 '11 at 03:21
  • 33
    The question is if something like its ALLREADY exists, which is a good one, because you don't want to reinvent the weel. – Velrok Apr 13 '12 at 11:32
  • 9
    This question should not be closed. I was going to post an answer with aFileChooser (https://github.com/iPaulPro/aFileChooser) but can't, so let's hope those who need see this comment. – Bitcoin Cash - ADA enthusiast Sep 30 '14 at 23:21
  • 2
    I agree, this is a useful question. I was hoping to contribute this simple single-class implementation to the answers: http://www.ninthavenue.com.au/simple-android-file-chooser – Roger Keays Jun 03 '15 at 14:03
  • Though I think I kind of understand why they don't want questions asking for the existence of a certain tool/library, they should add a suggestion where such a question can be asked. EDIT: after searching for a while, I think such questions should be asked at Software Recomendations: http://softwarerecs.stackexchange.com/help/on-topic – Emile Vrijdags Jan 04 '17 at 13:49
  • I think it's absurd having to manually implement a file picker when developing for Android... I miss things like Delphi's/Lazarus' [TOpenDialog](http://wiki.freepascal.org/TOpenDialog) and [TSaveDialog](http://wiki.freepascal.org/TSaveDialog) or Java SE's [JFileChooser](https://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html). Developers should worry only about their application specifics... – Antônio Medeiros Jul 26 '18 at 12:52
  • 1
    This question should not be closed because how we develop for Android changes each six months or so... – Antônio Medeiros Jul 26 '18 at 12:54
  • this is exactly what you need : https://stackoverflow.com/a/59104787/3141844 – Criss Nov 29 '19 at 12:46

6 Answers6

185

You just need to override onCreateDialog in an Activity.

//In an Activity
private String[] mFileList;
private File mPath = new File(Environment.getExternalStorageDirectory() + "//yourdir//");
private String mChosenFile;
private static final String FTYPE = ".txt";    
private static final int DIALOG_LOAD_FILE = 1000;

private void loadFileList() {
    try {
        mPath.mkdirs();
    }
    catch(SecurityException e) {
        Log.e(TAG, "unable to write on the sd card " + e.toString());
    }
    if(mPath.exists()) {
        FilenameFilter filter = new FilenameFilter() {

            @Override
            public boolean accept(File dir, String filename) {
                File sel = new File(dir, filename);
                return filename.contains(FTYPE) || sel.isDirectory();
            }

        };
        mFileList = mPath.list(filter);
    }
    else {
        mFileList= new String[0];
    }
}

protected Dialog onCreateDialog(int id) {
    Dialog dialog = null;
    AlertDialog.Builder builder = new Builder(this);

    switch(id) {
        case DIALOG_LOAD_FILE:
            builder.setTitle("Choose your file");
            if(mFileList == null) {
                Log.e(TAG, "Showing file picker before loading the file list");
                dialog = builder.create();
                return dialog;
            }
            builder.setItems(mFileList, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    mChosenFile = mFileList[which];
                    //you can do stuff with the file here too
                }
            });
            break;
    }
    dialog = builder.show();
    return dialog;
}
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Nathan Schwermann
  • 31,285
  • 16
  • 80
  • 91
  • 4
    Add the ability to navigate folders and go up to parent folder, and you got it – Aymon Fournier Sep 07 '10 at 07:39
  • 50
    If you can't modify the above to navigate the filesystem, I don't know how you're going to graft it into your app in the first place. When he's already bent the "rules" and written the code for you, I sure hope you're not really going to hold the bounty ransom for that. – Blumer Sep 08 '10 at 17:28
  • 6
    I edited the code above to show how to include the folders. You should be able to figure out the rest. If you detect that the file pressed is a directory in onClick just set the new path and call onCreateDialog again. – Nathan Schwermann Sep 08 '10 at 22:04
  • 1
    Hey whats "Environmet" , is that a variable , actually I'm using your code and its not able to detect whats "Environment" . – TRonZ Aug 07 '12 at 08:04
  • Oh you have spelled it wrong I guess . – TRonZ Aug 07 '12 at 08:05
  • 6
    Don't forget to add permission to Manifest – Zar E Ahmer Jul 08 '14 at 07:31
73

Thanx schwiz for idea! Here is modified solution:

public class FileDialog {
    private static final String PARENT_DIR = "..";
    private final String TAG = getClass().getName();
    private String[] fileList;
    private File currentPath;
    public interface FileSelectedListener {
        void fileSelected(File file);
    }
    public interface DirectorySelectedListener {
        void directorySelected(File directory);
    }
    private ListenerList<FileSelectedListener> fileListenerList = new ListenerList<FileDialog.FileSelectedListener>();
    private ListenerList<DirectorySelectedListener> dirListenerList = new ListenerList<FileDialog.DirectorySelectedListener>();
    private final Activity activity;
    private boolean selectDirectoryOption;
    private String fileEndsWith;    

    /**
    * @param activity 
    * @param initialPath
    */
    public FileDialog(Activity activity, File initialPath) {
        this(activity, initialPath, null);
    }

    public FileDialog(Activity activity, File initialPath, String fileEndsWith) {
        this.activity = activity;
        setFileEndsWith(fileEndsWith);
        if (!initialPath.exists()) initialPath = Environment.getExternalStorageDirectory();
            loadFileList(initialPath);
    }

    /**
    * @return file dialog
    */
    public Dialog createFileDialog() {
        Dialog dialog = null;
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);

        builder.setTitle(currentPath.getPath());
        if (selectDirectoryOption) {
            builder.setPositiveButton("Select directory", new OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    Log.d(TAG, currentPath.getPath());
                    fireDirectorySelectedEvent(currentPath);
                }
            });
        }

        builder.setItems(fileList, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                String fileChosen = fileList[which];
                File chosenFile = getChosenFile(fileChosen);
                if (chosenFile.isDirectory()) {
                    loadFileList(chosenFile);
                    dialog.cancel();
                    dialog.dismiss();
                    showDialog();
                } else fireFileSelectedEvent(chosenFile);
            }
        });

        dialog = builder.show();
        return dialog;
    }


    public void addFileListener(FileSelectedListener listener) {
        fileListenerList.add(listener);
    }

    public void removeFileListener(FileSelectedListener listener) {
        fileListenerList.remove(listener);
    }

    public void setSelectDirectoryOption(boolean selectDirectoryOption) {
        this.selectDirectoryOption = selectDirectoryOption;
    }

    public void addDirectoryListener(DirectorySelectedListener listener) {
        dirListenerList.add(listener);
    }

    public void removeDirectoryListener(DirectorySelectedListener listener) {
        dirListenerList.remove(listener);
    }

    /**
    * Show file dialog
    */
    public void showDialog() {
        createFileDialog().show();
    }

    private void fireFileSelectedEvent(final File file) {
        fileListenerList.fireEvent(new FireHandler<FileDialog.FileSelectedListener>() {
            public void fireEvent(FileSelectedListener listener) {
                listener.fileSelected(file);
            }
        });
    }

    private void fireDirectorySelectedEvent(final File directory) {
        dirListenerList.fireEvent(new FireHandler<FileDialog.DirectorySelectedListener>() {
            public void fireEvent(DirectorySelectedListener listener) {
                listener.directorySelected(directory);
            }
        });
    }

    private void loadFileList(File path) {
        this.currentPath = path;
        List<String> r = new ArrayList<String>();
        if (path.exists()) {
            if (path.getParentFile() != null) r.add(PARENT_DIR);
            FilenameFilter filter = new FilenameFilter() {
                public boolean accept(File dir, String filename) {
                    File sel = new File(dir, filename);
                    if (!sel.canRead()) return false;
                    if (selectDirectoryOption) return sel.isDirectory();
                    else {
                        boolean endsWith = fileEndsWith != null ? filename.toLowerCase().endsWith(fileEndsWith) : true;
                        return endsWith || sel.isDirectory();
                    }
                }
            };
            String[] fileList1 = path.list(filter);
            for (String file : fileList1) {
                r.add(file);
            }
        }
        fileList = (String[]) r.toArray(new String[]{});
    }

    private File getChosenFile(String fileChosen) {
        if (fileChosen.equals(PARENT_DIR)) return currentPath.getParentFile();
        else return new File(currentPath, fileChosen);
    }

    private void setFileEndsWith(String fileEndsWith) {
        this.fileEndsWith = fileEndsWith != null ? fileEndsWith.toLowerCase() : fileEndsWith;
    }
}

class ListenerList<L> {
    private List<L> listenerList = new ArrayList<L>();

    public interface FireHandler<L> {
        void fireEvent(L listener);
    }

    public void add(L listener) {
        listenerList.add(listener);
    }

    public void fireEvent(FireHandler<L> fireHandler) {
        List<L> copy = new ArrayList<L>(listenerList);
        for (L l : copy) {
            fireHandler.fireEvent(l);
        }
    }

    public void remove(L listener) {
        listenerList.remove(listener);
    }

    public List<L> getListenerList() {
        return listenerList;
    }
}

Use it on activity onCreate (directory selection option is commented):

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    File mPath = new File(Environment.getExternalStorageDirectory() + "//DIR//");
    fileDialog = new FileDialog(this, mPath, ".txt");
    fileDialog.addFileListener(new FileDialog.FileSelectedListener() {
        public void fileSelected(File file) {
            Log.d(getClass().getName(), "selected file " + file.toString());
        }
    });
    //fileDialog.addDirectoryListener(new FileDialog.DirectorySelectedListener() {
    //  public void directorySelected(File directory) {
    //      Log.d(getClass().getName(), "selected dir " + directory.toString());
    //  }
    //});
    //fileDialog.setSelectDirectoryOption(false);
    fileDialog.showDialog();
}
NG_
  • 6,895
  • 7
  • 45
  • 67
Kirill Mikhailov
  • 1,029
  • 9
  • 9
  • 8
    Great helper class! I found one small glitch - on first run loadFileList() won't filter by file extension, because it wouldn't be set by SetFileEndsWith yet. I reworked the constructor to accept third parameter fileEnsWith, and set it in constructor before loadFileList() call. – Kurovsky Nov 02 '13 at 20:20
  • hi nice code, thanks. can this code pick multiple file format ie fileDialog.setFileEndsWith(".txt",".pdf"); or fileDialog.setFileEndsWith("fle/*"); please answr – Anitha Jan 29 '15 at 11:46
  • No. But, it's pretty easy to modify. The problem is that the .setFileEndsWith() doesn't work at all, because the file list is allocated in the constructor. You need to change the constructor to accept multiple input and then change the line: "boolean endsWith = fileEndsWith != null ? filename.toLowerCase().endsWith(fileEndsWith) : true;" to properly match whatever you data structure you put it in. It's a pretty trivial change. – Tatarize Feb 28 '15 at 13:24
  • All these dreaded listener lists and fireEvent(FireHandler) look unnecessary (did someone ever use them?), but the code works. – 18446744073709551615 Apr 16 '15 at 09:17
  • hi, thanks for great helper class.How can i setCanceledOnTouchOutside for this. I added in filedialog in show method but i doesnt work for me – Dauezevy Aug 13 '15 at 08:17
  • Okay i did, i changed the dialog=builder.create() instead of dialog = builder.show() then i added dialog.setCanceledOnTouchOutside(true); after that. Then works :) – Dauezevy Aug 13 '15 at 08:21
15

I have created FolderLayout which may help you. This link helped me

folderview.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView android:id="@+id/path" android:text="Path"
        android:layout_width="match_parent" android:layout_height="wrap_content"></TextView>
    <ListView android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:id="@+id/list"></ListView>

</LinearLayout>

FolderLayout.java

package com.testsample.activity;




   public class FolderLayout extends LinearLayout implements OnItemClickListener {

    Context context;
    IFolderItemListener folderListener;
    private List<String> item = null;
    private List<String> path = null;
    private String root = "/";
    private TextView myPath;
    private ListView lstView;

    public FolderLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        // TODO Auto-generated constructor stub
        this.context = context;


        LayoutInflater layoutInflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = layoutInflater.inflate(R.layout.folderview, this);

        myPath = (TextView) findViewById(R.id.path);
        lstView = (ListView) findViewById(R.id.list);

        Log.i("FolderView", "Constructed");
        getDir(root, lstView);

    }

    public void setIFolderItemListener(IFolderItemListener folderItemListener) {
        this.folderListener = folderItemListener;
    }

    //Set Directory for view at anytime
    public void setDir(String dirPath){
        getDir(dirPath, lstView);
    }


    private void getDir(String dirPath, ListView v) {

        myPath.setText("Location: " + dirPath);
        item = new ArrayList<String>();
        path = new ArrayList<String>();
        File f = new File(dirPath);
        File[] files = f.listFiles();

        if (!dirPath.equals(root)) {

            item.add(root);
            path.add(root);
            item.add("../");
            path.add(f.getParent());

        }
        for (int i = 0; i < files.length; i++) {
            File file = files[i];
            path.add(file.getPath());
            if (file.isDirectory())
                item.add(file.getName() + "/");
            else
                item.add(file.getName());

        }

        Log.i("Folders", files.length + "");

        setItemList(item);

    }

    //can manually set Item to display, if u want
    public void setItemList(List<String> item){
        ArrayAdapter<String> fileList = new ArrayAdapter<String>(context,
                R.layout.row, item);

        lstView.setAdapter(fileList);
        lstView.setOnItemClickListener(this);
    }


    public void onListItemClick(ListView l, View v, int position, long id) {
        File file = new File(path.get(position));
        if (file.isDirectory()) {
            if (file.canRead())
                getDir(path.get(position), l);
            else {
//what to do when folder is unreadable
                if (folderListener != null) {
                    folderListener.OnCannotFileRead(file);

                }

            }
        } else {

//what to do when file is clicked
//You can add more,like checking extension,and performing separate actions
            if (folderListener != null) {
                folderListener.OnFileClicked(file);
            }

        }
    }

    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        // TODO Auto-generated method stub
        onListItemClick((ListView) arg0, arg0, arg2, arg3);
    }

}

And an Interface IFolderItemListener to add what to do when a fileItem is clicked

IFolderItemListener.java

public interface IFolderItemListener {

    void OnCannotFileRead(File file);//implement what to do folder is Unreadable
    void OnFileClicked(File file);//What to do When a file is clicked
}

Also an xml to define the row

row.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rowtext" android:layout_width="fill_parent"
    android:textSize="23sp" android:layout_height="match_parent"/>

How to Use in your Application

In your xml,

folders.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="horizontal" android:weightSum="1">
    <com.testsample.activity.FolderLayout android:layout_height="match_parent" layout="@layout/folderview"
        android:layout_weight="0.35"
        android:layout_width="200dp" android:id="@+id/localfolders"></com.testsample.activity.FolderLayout></LinearLayout>

In Your Activity,

SampleFolderActivity.java

public class SampleFolderActivity extends Activity implements IFolderItemListener {

    FolderLayout localFolders;

    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        localFolders = (FolderLayout)findViewById(R.id.localfolders);
        localFolders.setIFolderItemListener(this);
            localFolders.setDir("./sys");//change directory if u want,default is root   

    }

    //Your stuff here for Cannot open Folder
    public void OnCannotFileRead(File file) {
        // TODO Auto-generated method stub
        new AlertDialog.Builder(this)
        .setIcon(R.drawable.icon)
        .setTitle(
                "[" + file.getName()
                        + "] folder can't be read!")
        .setPositiveButton("OK",
                new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialog,
                            int which) {


                    }
                }).show();

    }


    //Your stuff here for file Click
    public void OnFileClicked(File file) {
        // TODO Auto-generated method stub
        new AlertDialog.Builder(this)
        .setIcon(R.drawable.icon)
        .setTitle("[" + file.getName() + "]")
        .setPositiveButton("OK",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog,
                            int which) {


                    }

                }).show();
    }

}

Import the libraries needed. Hope these help you...

sonu thomas
  • 2,161
  • 4
  • 24
  • 38
5

Was looking for a file/folder browser myself recently and decided to make a new explorer activity (Android library): https://github.com/vaal12/AndroidFileBrowser

Matching Test application https://github.com/vaal12/FileBrowserTestApplication- is a sample how to use.

Allows picking directories and files from phone file structure.

Alexey Vassiliev
  • 2,349
  • 2
  • 17
  • 8
3

Adding to the mix: the OI File Manager has a public api registered at openintents.org

http://www.openintents.org/filemanager

http://www.openintents.org/action/org-openintents-action-pick-file/

Juozas Kontvainis
  • 9,461
  • 6
  • 55
  • 66
Edward Falk
  • 9,991
  • 11
  • 77
  • 112
2

I have implemented the Samsung File Selector Dialog, it provides the ability to open, save file, file extension filter, and create new directory in the same dialog I think it worth trying Here is the Link you have to log in to Samsung developer site to view the solution

Firas Shrourou
  • 625
  • 8
  • 19