| Author |
Message |
plusminus Site Admin

Joined: 14 Nov 2007 Posts: 2025 Location: Germany
|
Posted: Sat Nov 24, 2007 7:37 pm Post subject: Android FileBrowser v.2.0 |
|
|
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)
See also: ListActivity - Functionality
Designed/Tested with sdk-version: m5-rc14
Read before: As we are mostly combining them
- Building an Android FileBrowser (list-based)
(as we are modifying/improving that tutorial!)
- Iconified TextList - The making of

Problems/Questions: post right below...
Difficulty: 2 of 5 (+ 2 other projects done before )
What it will look like:
(Mode: RELATIVE)
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:
| Java: | // from:
private List<String> directoryEntries = new ArrayList<String>();
// to:
private List<IconifiedText> directoryEntries = new ArrayList<IconifiedText>(); |
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:
| XML: | <?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> |
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:
| Java: | 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)));
|
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:
| Java: | Drawable currentIcon = null;
for (File currentFile : files){
if (currentFile.isDirectory()) {
currentIcon = getResources().getDrawable(R.drawable.folder);
}else{ |
If currentFile was no Folder then it was a File we get a Drawable from the Resources, depending on the ending of the fileName of currentFile and what we entered on our fileendings.xml.
| Java: | }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);
}
} |
Lets take a short look at one of those if's:
| Java: | /* 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;
} |
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
| Java: | 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;
} |
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):
| Java: | Collections.sort(this.directoryEntries);
IconifiedTextListAdapter itla = new IconifiedTextListAdapter(this);
itla.setListItems(this.directoryEntries);
this.setListAdapter(itla); |
There was another little change to browseTo, which alters the Title of our Application, if we are in Relative Mode:
| Java: | 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)); |
The full source:
Get IconifiedList-Files here (click)
Download all Resource-Files for this tutorial here: here (click)
"/src/your_package_structure/AndroidFileBrowser.java"
| Java: | 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;
}
} |
Regards,
plusminus
| Description: |
Android File Browser 2.0 Full Source SDK-Version: m3 ! |
|
 Download |
| Filename: |
Android_File _Browser_2_0.zip |
| Filesize: |
107.52 KB |
| Downloaded: |
568 Time(s) |
_________________
| Android Development Community / Tutorials
Last edited by plusminus on Thu Feb 21, 2008 5:18 pm; edited 3 times in total |
|
| Back to top |
|
 |
ice2age Freshman
Joined: 27 Dec 2007 Posts: 2
|
Posted: Thu Dec 27, 2007 8:03 pm Post subject: Hmm. Am i doing something wrong. |
|
|
Im getting 2 errors.
Bound mismatch: The generic method sort(List<T>) of type Collections is not applicable for the arguments (List<IconifiedText>). The inferred type IconifiedText is not a valid substitute for the bounded parameter <T extends Comparable<? super T>>
The method compareTo(IconifiedText) of type IconifiedText must override a superclass method
|
|
| Back to top |
|
 |
plusminus Site Admin

Joined: 14 Nov 2007 Posts: 2025 Location: Germany
|
|
| Back to top |
|
 |
ice2age Freshman
Joined: 27 Dec 2007 Posts: 2
|
Posted: Fri Dec 28, 2007 5:01 pm Post subject: That worked |
|
|
Thanks plusminus. Could you tell me why i cant browse the /data folder?
Im new to the platform and i wonder why there is no /home folder like on other *nix systems.
I tought there would be one something like /home/android/ {and here Pictures, Music .... }.
Is there any universal folder for Pictures, Music?. example If there is some program that can take pictures from the camera and it stores it somwhere in its own data folder and someone else has written a progrem for picture editing how can he know where the pictures are? Thanks
|
|
| Back to top |
|
 |
plusminus Site Admin

Joined: 14 Nov 2007 Posts: 2025 Location: Germany
|
Posted: Fri Dec 28, 2007 5:55 pm Post subject: |
|
|
Hello ice2age,
yes I'm also a bit surprised about the differences between the output of the program and what the DDMS-View shows...
You probably cannot browse the "/data/"-Folder, because the rights of the Application are not high enough to do so.
I'm not aware of any default-folders for images/music yet. (also not that familiar with Linux)
Regards,
plusminus
_________________
| Android Development Community / Tutorials |
|
| Back to top |
|
 |
raquibulbari Developer

Joined: 16 Dec 2007 Posts: 25 Location: dhaka,bangladesh
|
Posted: Sun Jan 27, 2008 9:43 am Post subject: |
|
|
Hello +-,
How are you? These tutorials are simply great
Can i use codes in this forum to my android submission?? will there be any licensing issues???
_________________ Shimugool |
|
| Back to top |
|
 |
plusminus Site Admin

Joined: 14 Nov 2007 Posts: 2025 Location: Germany
|
Posted: Sun Jan 27, 2008 1:06 pm Post subject: |
|
|
| raquibulbari wrote: | Hello +-,
How are you? These tutorials are simply great
Can i use codes in this forum to my android submission?? will there be any licensing issues??? |
We want 50% of all outcomes Of course NOT
The only thing you "have to do" is, when someone asks you if you know a helpful Android-Forum, you will know what to answer
Regards,
plusminus
_________________
| Android Development Community / Tutorials |
|
| Back to top |
|
 |
raquibulbari Developer

Joined: 16 Dec 2007 Posts: 25 Location: dhaka,bangladesh
|
Posted: Sun Jan 27, 2008 3:04 pm Post subject: |
|
|
already started to advertise your site, told 2 of my android developer friend
_________________ Shimugool |
|
| Back to top |
|
 |
gvkreddyvamsi Developer
Joined: 21 Jan 2008 Posts: 43 Location: INDIA
|
Posted: Wed Feb 13, 2008 8:18 am Post subject: cann't resolve R.java |
|
|
HI, application is fine. Done well.
Plz attach zip file for this application.
by
vamsi
|
|
| Back to top |
|
 |
plusminus Site Admin

Joined: 14 Nov 2007 Posts: 2025 Location: Germany
|
Posted: Wed Feb 13, 2008 9:29 am Post subject: Re: cann't resolve R.java |
| | |