Android FileBrowser v.2.0 (Iconified-List-Based)
What is this: We want to pimp the FileBrowser (created in a tutorial before), so it displays fancy little Icons, indicating the type of the ListEntry. i.e.: directories (
), audio-files (
), html/php-Files (
), zip/gz/jar-packages (
), ....What this tutorial includes:
- Browsing the FileSystem showing fancy icons for the Files/Directories
- Defining Array in XML
- Sending Intents to the System (Open clicked files)
- Building an Android FileBrowser (list-based)
(as we are modifying/improving that tutorial!) - Iconified TextList - The making of

Difficulty: 2 of 5 (+ 2 other projects done before
What it will look like:
(Mode: RELATIVE)
Images taken with SDK-Version m3 !


Images taken with SDK-Version m3 !


0. Copy these three files (IconifiedText.java, IconifiedTextView.java and IconifiedTextListAdapter.java) from the Iconified TextList, to the (basic) FileBrowser-Project you've had created somewhen before.
1.So not that much will be changed within this tutorial, the most important change is that icon-thing.
As we now want to display Iconified Texts our class-field this.directoryEntries has to be change:
Using java Syntax Highlighting
- // from:
- private List<String> directoryEntries = new ArrayList<String>();
- // to:
- private List<IconifiedText> directoryEntries = new ArrayList<IconifiedText>();
Parsed in 0.031 seconds, using GeSHi 1.0.8.4
2.As we want to produce highly generic code, we do not 'hardcode' the fileendings to our application, but we define each fileType-Category(Autio, Image, Text, ...) as an array in an XML-File, like the following:
Using xml Syntax Highlighting
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <array name="fileEndingImage">
- <item>.png</item>
- <item>.gif</item>
- <item>.jpg</item>
- <item>.jpeg</item>
- <item>.bmp</item>
- </array>
- <array name="fileEndingAudio">
- <item>.mp3</item>
- <item>.wav</item>
- <item>.ogg</item>
- <item>.midi</item>
- </array>
- <array name="fileEndingPackage">
- <item>.jar</item>
- <item>.zip</item>
- <item>.rar</item>
- <item>.gz</item>
- </array>
- <array name="fileEndingWebText">
- <item>.htm</item>
- <item>.html</item>
- <item>.php</item>
- </array>
- </resources>
Parsed in 0.005 seconds, using GeSHi 1.0.8.4
Isn't that generic
3.The main change is within the 'private void fill(File[] files) {...'-method. For each File in the File[]-Array passed, we need to determine its Type(a Directory or a real File) and if it is a real File, we need to find the accurate icon for it.
The first thign of course is to clear the list of the directoryEntries (as we have browsed to another directory). We also add the Directory-Navigation-Icons, as already in Version 1.0:
Using java Syntax Highlighting
- this.directoryEntries.clear();
- // Add the "." == "current directory"
- this.directoryEntries.add(new IconifiedText(
- getString(R.string.current_dir),
- getResources().getDrawable(R.drawable.folder)));
- // and the ".." == 'Up one level'
- if(this.currentDirectory.getParent() != null)
- this.directoryEntries.add(new IconifiedText(
- getString(R.string.up_one_level),
- getResources().getDrawable(R.drawable.uponelevel)));
Parsed in 0.033 seconds, using GeSHi 1.0.8.4
Now we create an Variable of the type Drawable (~Icon) that will hold the current Icon to be used as we are looping through the Array of Files that was passed as the parameter. If the currentFile is a folder we load the icon from the resources:
Using java Syntax Highlighting
- Drawable currentIcon = null;
- for (File currentFile : files){
- if (currentFile.isDirectory()) {
- currentIcon = getResources().getDrawable(R.drawable.folder);
- }else{
Parsed in 0.034 seconds, using GeSHi 1.0.8.4
If currentFile was no Folder then it was a File
Using java Syntax Highlighting
- }else{
- String fileName = currentFile.getName();
- /* Determine the Icon to be used,
- * depending on the FileEndings defined in:
- * res/values/fileendings.xml. */
- if(checkEndsWithInStringArray(fileName, getResources().
- getStringArray(R.array.fileEndingImage))){
- currentIcon = getResources().getDrawable(R.drawable.image);
- }else if(checkEndsWithInStringArray(fileName, getResources().
- getStringArray(R.array.fileEndingWebText))){
- currentIcon = getResources().getDrawable(R.drawable.webtext);
- }else if(checkEndsWithInStringArray(fileName, getResources().
- getStringArray(R.array.fileEndingPackage))){
- currentIcon = getResources().getDrawable(R.drawable.packed);
- }else if(checkEndsWithInStringArray(fileName, getResources().
- getStringArray(R.array.fileEndingAudio))){
- currentIcon = getResources().getDrawable(R.drawable.audio);
- }else{
- currentIcon = getResources().getDrawable(R.drawable.text);
- }
- }
Parsed in 0.038 seconds, using GeSHi 1.0.8.4
Lets take a short look at one of those if's:
Using java Syntax Highlighting
- /* If fileName endsWith on of the FileEndings
- * defined in 'fileendings.xml' we load the
- * appropriate Drawable from the Resources */
- if(checkEndsWithInStringArray(fileName, getResources().
- getStringArray(R.array.fileEndingImage))){
- currentIcon = getResources().getDrawable(R.drawable.image);
- //...
- /** Checks whether checkItsEnd ends with
- * one of the Strings from fileEndings */
- private boolean checkEndsWithInStringArray(String checkItsEnd,
- String[] fileEndings){
- for(String aEnd : fileEndings){
- if(checkItsEnd.endsWith(aEnd))
- return true;
- }
- return false;
- }
Parsed in 0.037 seconds, using GeSHi 1.0.8.4
Having determined the correct Drawable to be displayed, we switch on our displayMode (as already in v1.0) and add a new IconifiedText to this.directoryEntries with the
Using java Syntax Highlighting
- switch (this.displayMode) {
- case ABSOLUTE:
- /* On absolute Mode, we show the full path */
- this.directoryEntries.add(new IconifiedText(currentFile
- .getPath(), currentIcon));
- break;
- case RELATIVE:
- /* On relative Mode, we have to cut the
- * current-path at the beginning */
- int currentPathStringLenght = this.currentDirectory.
- getAbsolutePath().length();
- this.directoryEntries.add(new IconifiedText(
- currentFile.getAbsolutePath().
- substring(currentPathStringLenght),
- currentIcon));
- break;
- }
Parsed in 0.037 seconds, using GeSHi 1.0.8.4
Having looped through all files and determined all the Drawables for them, we finally sort them (was not in v1.0) [Note: I simply made: 'public class IconifiedText implements Comparable<IconifiedText>' based on the Text (FileName here). Having sorted them, we create an IconifiedTextListAdapter to handle the IconifiedTexts being put to a ListView (better said: 'itla' is set to be the ListAdapter of our ListActivity):
Using java Syntax Highlighting
- Collections.sort(this.directoryEntries);
- IconifiedTextListAdapter itla = new IconifiedTextListAdapter(this);
- itla.setListItems(this.directoryEntries);
- this.setListAdapter(itla);
Parsed in 0.036 seconds, using GeSHi 1.0.8.4
There was another little change to browseTo, which alters the Title of our Application, if we are in Relative Mode:
Using java Syntax Highlighting
- private void browseTo(final File aDirectory){
- // On relative we display the full path in the title.
- if(this.displayMode == DISPLAYMODE.RELATIVE)
- this.setTitle(aDirectory.getAbsolutePath() + " :: " +
- getString(R.string.app_name));
Parsed in 0.036 seconds, using GeSHi 1.0.8.4
The full source:
Get IconifiedList-Files here (click)
Download all Resource-Files for this tutorial here: here (click)"/src/your_package_structure/AndroidFileBrowser.java"
Using java Syntax Highlighting
- package org.anddev.android.filebrowser;
- import java.io.File;
- import java.net.URISyntaxException;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- import org.anddev.android.filebrowser.iconifiedlist.IconifiedText;
- import org.anddev.android.filebrowser.iconifiedlist.IconifiedTextListAdapter;
- import android.app.AlertDialog;
- import android.app.ListActivity;
- import android.content.DialogInterface;
- import android.content.Intent;
- import android.content.DialogInterface.OnClickListener;
- import android.graphics.drawable.Drawable;
- import android.net.ContentURI;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.ListView;
- public class AndroidFileBrowser extends ListActivity {
- private enum DISPLAYMODE{ ABSOLUTE, RELATIVE; }
- private final DISPLAYMODE displayMode = DISPLAYMODE.RELATIVE;
- private List<IconifiedText> directoryEntries = new ArrayList<IconifiedText>();
- private File currentDirectory = new File("/");
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- browseToRoot();
- }
- /**
- * This function browses to the
- * root-directory of the file-system.
- */
- private void browseToRoot() {
- browseTo(new File("/"));
- }
- /**
- * This function browses up one level
- * according to the field: currentDirectory
- */
- private void upOneLevel(){
- if(this.currentDirectory.getParent() != null)
- this.browseTo(this.currentDirectory.getParentFile());
- }
- private void browseTo(final File aDirectory){
- // On relative we display the full path in the title.
- if(this.displayMode == DISPLAYMODE.RELATIVE)
- this.setTitle(aDirectory.getAbsolutePath() + " :: " +
- getString(R.string.app_name));
- if (aDirectory.isDirectory()){
- this.currentDirectory = aDirectory;
- fill(aDirectory.listFiles());
- }else{
- OnClickListener okButtonListener = new OnClickListener(){
- // @Override
- public void onClick(DialogInterface arg0, int arg1) {
- // Lets start an intent to View the file, that was clicked...
- AndroidFileBrowser.this.openFile(aDirectory);
- }
- };
- OnClickListener cancelButtonListener = new OnClickListener(){
- // @Override
- public void onClick(DialogInterface arg0, int arg1) {
- // Do nothing ^^
- }
- };
- AlertDialog.show(this,"Question", R.drawable.folder, "Do you want to open that file?n"
- + aDirectory.getName(),
- "OK", okButtonListener,
- "Cancel", cancelButtonListener, false, null);
- }
- }
- private void openFile(File aFile) {
- Intent myIntent = new Intent(android.content.Intent.VIEW_ACTION,
- Uri.parse("file://" + aFile.getAbsolutePath()));
- startActivity(myIntent);
- }
- private void fill(File[] files) {
- this.directoryEntries.clear();
- // Add the "." == "current directory"
- this.directoryEntries.add(new IconifiedText(
- getString(R.string.current_dir),
- getResources().getDrawable(R.drawable.folder)));
- // and the ".." == 'Up one level'
- if(this.currentDirectory.getParent() != null)
- this.directoryEntries.add(new IconifiedText(
- getString(R.string.up_one_level),
- getResources().getDrawable(R.drawable.uponelevel)));
- Drawable currentIcon = null;
- for (File currentFile : files){
- if (currentFile.isDirectory()) {
- currentIcon = getResources().getDrawable(R.drawable.folder);
- }else{
- String fileName = currentFile.getName();
- /* Determine the Icon to be used,
- * depending on the FileEndings defined in:
- * res/values/fileendings.xml. */
- if(checkEndsWithInStringArray(fileName, getResources().
- getStringArray(R.array.fileEndingImage))){
- currentIcon = getResources().getDrawable(R.drawable.image);
- }else if(checkEndsWithInStringArray(fileName, getResources().
- getStringArray(R.array.fileEndingWebText))){
- currentIcon = getResources().getDrawable(R.drawable.webtext);
- }else if(checkEndsWithInStringArray(fileName, getResources().
- getStringArray(R.array.fileEndingPackage))){
- currentIcon = getResources().getDrawable(R.drawable.packed);
- }else if(checkEndsWithInStringArray(fileName, getResources().
- getStringArray(R.array.fileEndingAudio))){
- currentIcon = getResources().getDrawable(R.drawable.audio);
- }else{
- currentIcon = getResources().getDrawable(R.drawable.text);
- }
- }
- switch (this.displayMode) {
- case ABSOLUTE:
- /* On absolute Mode, we show the full path */
- this.directoryEntries.add(new IconifiedText(currentFile
- .getPath(), currentIcon));
- break;
- case RELATIVE:
- /* On relative Mode, we have to cut the
- * current-path at the beginning */
- int currentPathStringLenght = this.currentDirectory.
- getAbsolutePath().length();
- this.directoryEntries.add(new IconifiedText(
- currentFile.getAbsolutePath().
- substring(currentPathStringLenght),
- currentIcon));
- break;
- }
- }
- Collections.sort(this.directoryEntries);
- IconifiedTextListAdapter itla = new IconifiedTextListAdapter(this);
- itla.setListItems(this.directoryEntries);
- this.setListAdapter(itla);
- }
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- super.onListItemClick(l, v, position, id);
- String selectedFileString = this.directoryEntries.get(position)
- .getText();
- if (selectedFileString.equals(getString(R.string.current_dir))) {
- // Refresh
- this.browseTo(this.currentDirectory);
- } else if (selectedFileString.equals(getString(R.string.up_one_level))) {
- this.upOneLevel();
- } else {
- File clickedFile = null;
- switch (this.displayMode) {
- case RELATIVE:
- clickedFile = new File(this.currentDirectory
- .getAbsolutePath()
- + this.directoryEntries.get(position)
- .getText());
- break;
- case ABSOLUTE:
- clickedFile = new File(this.directoryEntries.get(
- position).getText());
- break;
- }
- if (clickedFile != null)
- this.browseTo(clickedFile);
- }
- }
- /** Checks whether checkItsEnd ends with
- * one of the Strings from fileEndings */
- private boolean checkEndsWithInStringArray(String checkItsEnd,
- String[] fileEndings){
- for(String aEnd : fileEndings){
- if(checkItsEnd.endsWith(aEnd))
- return true;
- }
- return false;
- }
- }
Parsed in 0.062 seconds, using GeSHi 1.0.8.4
Regards,
plusminus








