//From the desk of Frank P. Westlake; public domain.
package jackpal.androidterm.shortcuts;
import android.content. Intent;
import android.content. SharedPreferences;
import android.graphics. Typeface;
import android.net. Uri;
import android.os. Environment;
import android.preference. PreferenceManager;
import android.view. Gravity;
import android.view. KeyEvent;
import android.view. Menu;
import android.view. MenuItem;
import android.view. View;
import android.widget. EditText;
import android.widget. HorizontalScrollView;
import android.widget. ImageView;
import android.widget. LinearLayout;
import android.widget. ScrollView;
import android.widget. TextView;
import android.widget. Toast;
import java.io. File;
import java.io. IOException;
import java.util. HashMap;
import jackpal.androidterm. R;
public class FSNavigator
extends android.app.Activity
{
private final int ACTION_THEME_SWAP= 0x00000100;
private final int BUTTON_SIZE= 150;
private android.content.Context context= this;
private float textLg= 24;
private int theme= android.R.style.Theme;
private SharedPreferences SP;
private File cd;
private File extSdCardFile;
private String extSdCard;
private HashMap<Integer, LinearLayout> cachedFileView;
private HashMap<Integer, LinearLayout> cachedDirectoryView;
private HashMap<Integer, TextView> cachedDividerView;
private int countFileView;
private int countDirectoryView;
private int countDividerView;
private LinearLayout contentView;
private LinearLayout titleView;
private LinearLayout pathEntryView;
////////////////////////////////////////////////////////////
public void onCreate(android.os.Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setTitle(getString(R.string.fsnavigator_title));//"File Selector");
SP=PreferenceManager.getDefaultSharedPreferences(context);
theme=SP.getInt("theme", theme);
setTheme(theme);
getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
Intent intent= getIntent();
extSdCardFile=Environment.getExternalStorageDirectory();
extSdCard=getCanonicalPath(extSdCardFile);
Uri uri=intent.getData();
String path=uri==null?null:uri.getPath();
if(null == path || null==(chdir(path))) chdir(extSdCard);
if(intent.hasExtra("title")) setTitle(intent.getStringExtra("title"));
titleView= directoryEntry("..");
pathEntryView= fileEntry(null);
contentView= makeContentView();
cachedDirectoryView= new HashMap<Integer, LinearLayout>();
cachedFileView= new HashMap<Integer, LinearLayout>();
cachedDividerView= new HashMap<Integer, TextView>();
}
////////////////////////////////////////////////////////////
public void onPause()
{
super.onPause();
doPause();
}
////////////////////////////////////////////////////////////
private void doPause()
{
SP.edit().putString("lastDirectory", getCanonicalPath(cd)).commit();
}
////////////////////////////////////////////////////////////
public void onResume()
{
super.onResume();
doResume();
}
////////////////////////////////////////////////////////////
private void doResume()
{
makeView();
}
////////////////////////////////////////////////////////////
private void swapTheme()
{
switch(theme)
{
case android.R.style.Theme: theme=android.R.style.Theme_Light; break;
case android.R.style.Theme_Light: theme=android.R.style.Theme; break;
default: return;
}
SP.edit().putInt("theme", theme).commit();
startActivityForResult(getIntent().addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT), -1);
finish();
}
////////////////////////////////////////////////////////////
private String ifAvailable(String goTo)
{
if(goTo.startsWith(extSdCard))
{
String s=Environment.getExternalStorageState();
if(s.equals(Environment.MEDIA_MOUNTED)
|| s.equals(Environment.MEDIA_MOUNTED_READ_ONLY)
)
{
return(goTo);
}
toast(getString(R.string.fsnavigator_no_external_storage), 1);//"External storage not available", 1);
return(extSdCard);
}
return(goTo);
}
////////////////////////////////////////////////////////////
private File chdir(File file)
{
String path=ifAvailable(getCanonicalPath(file));
System.setProperty("user.dir", path);
return(cd=new File(path));
}
private File chdir(String path)
{
return(chdir(new File(path)));
}
////////////////////////////////////////////////////////////
private TextView entryDividerH()
{
TextView tv;
if(countDividerView<cachedDividerView.size())
{
tv=cachedDividerView.get(countDividerView);
}
else
{
tv=new TextView(context);
tv.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, 1
, 1
)
);
cachedDividerView.put(countDividerView, tv);
}
++countDividerView;
return(tv);
}
////////////////////////////////////////////////////////////
View.OnClickListener fileListener=new View.OnClickListener()
{
public void onClick(View view)
{
String path=(String)view.getTag();
if(path!=null)
{
setResult(RESULT_OK, getIntent().setData(Uri.fromFile(new File(cd, path))));
finish();
}
}
};
////////////////////////////////////////////////////////////
private LinearLayout fileView(boolean entryWindow)
{
LinearLayout ll=new LinearLayout(context);
ll.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, LinearLayout.LayoutParams.WRAP_CONTENT
, 1
)
);
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.setGravity(android.view.Gravity.FILL);
final TextView tv;
if(entryWindow)
{
tv=new EditText(context);
tv.setHint(getString(R.string.fsnavigator_optional_enter_path));
tv.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, LinearLayout.LayoutParams.FILL_PARENT
, 2
)
);
tv.setOnKeyListener(
new EditText.OnKeyListener()
{
public boolean onKey(View v, int keyCode, KeyEvent event)
{
if(keyCode==KeyEvent.KEYCODE_ENTER)
{
String path=tv.getText().toString();
File file=new File(getCanonicalPath(path));
chdir(file.getParentFile()==null?file:file.getParentFile());
if(file.isFile())
{
setResult(RESULT_OK, getIntent().setData(Uri.fromFile(file)));
finish();
}
else
{
chdir(file);
makeView();
}
return(true);
}
return(false);
}
}
);
ll.addView(tv);
}
else
{
tv=new TextView(context);
tv.setClickable(true);
tv.setLongClickable(true);
tv.setOnClickListener(fileListener);
tv.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, LinearLayout.LayoutParams.FILL_PARENT
, 1
)
);
HorizontalScrollView hv=new HorizontalScrollView(context);
hv.setFillViewport(true);
hv.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, BUTTON_SIZE
, 7
)
);
hv.addView(tv);
ll.addView(hv);
}
tv.setFocusable(true);
tv.setSingleLine();
tv.setTextSize(textLg);
tv.setTypeface(Typeface.SERIF, Typeface.BOLD);
tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
tv.setPadding(10, 5, 10, 5);
tv.setId(R.id.textview);//1);
return(ll);
}
////////////////////////////////////////////////////////////
private LinearLayout fileEntry(final String entry)
{
LinearLayout ll;
if(entry==null) ll=fileView(entry==null);
else
{
if(countFileView<cachedFileView.size()) ll=cachedFileView.get(countFileView);
else cachedFileView.put(countFileView, ll=fileView(entry==null));
++countFileView;
}
TextView tv=(TextView)ll.findViewById(R.id.textview);
tv.setText(entry==null?"":entry);
tv.setTag(entry==null?"":entry);
return(ll);
}
////////////////////////////////////////////////////////////
private ImageView imageViewFolder(boolean up)
{
ImageView b1=new ImageView(context);
b1.setClickable(true);
b1.setFocusable(true);
b1.setId(R.id.imageview);
b1.setLayoutParams(
new LinearLayout.LayoutParams(
120
, 120
, 1
)
);
b1.setImageResource(up?R.drawable.ic_folderup:R.drawable.ic_folder);
b1.setOnClickListener(directoryListener);
b1.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
return(b1);
}
////////////////////////////////////////////////////////////
View.OnClickListener directoryListener=new View.OnClickListener()
{
public void onClick(View view)
{
String path=(String)view.getTag();
if(path!=null)
{
File file=new File(path);
if(file.isFile())
{
setResult(RESULT_OK, getIntent().setData(Uri.fromFile(file)));
finish();
}
else chdir(file);
makeView();
}
}
};
////////////////////////////////////////////////////////////
private LinearLayout directoryView(boolean up)
{
ImageView b1=imageViewFolder(up);
TextView tv=new TextView(context);
if(up) tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);//Gravity.CENTER);
else tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
tv.setClickable(true);
tv.setLongClickable(true);
tv.setFocusable(true);
tv.setOnClickListener(directoryListener);
tv.setMaxLines(1);
tv.setTextSize(textLg);
tv.setPadding(10, 5, 10, 5);
tv.setId(R.id.textview);
tv.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, BUTTON_SIZE
, 1
)
);
HorizontalScrollView hv=new HorizontalScrollView(context);
hv.addView(tv);
hv.setFillViewport(true);
hv.setFocusable(true);
hv.setOnClickListener(directoryListener);
hv.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, BUTTON_SIZE
, 7
)
);
LinearLayout ll=new LinearLayout(context);
ll.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, BUTTON_SIZE
, 2
)
);
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.setGravity(android.view.Gravity.FILL);
ll.setOnClickListener(directoryListener);
ll.addView(b1);
ll.addView(hv);
return(ll);
}
////////////////////////////////////////////////////////////
private LinearLayout directoryEntry(final String name)
{
boolean up=name.equals("..");
LinearLayout ll;
if(up) {ll=directoryView(up);}
else
{
if(countDirectoryView<cachedDirectoryView.size()) {ll= cachedDirectoryView.get(countDirectoryView);}
else {ll=directoryView(up); cachedDirectoryView.put(countDirectoryView, ll);}
++countDirectoryView;
}
TextView tv=((TextView)ll.findViewById(R.id.textview));
tv.setTag(name);
tv.setText(up ? "["+cd.getPath()+"]"
: name
);
((ImageView)ll.findViewById(R.id.imageview)).setTag(name);
return(ll);
}
////////////////////////////////////////////////////////////
public boolean onKeyUp(int keyCode, KeyEvent event)
{
if((keyCode == KeyEvent.KEYCODE_BACK)) {finish(); return(true);}
else return(super.onKeyUp(keyCode, event));
}
////////////////////////////////////////////////////////////
private LinearLayout makeContentView()
{
final LinearLayout ll=new LinearLayout(context);
ll.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, LinearLayout.LayoutParams.WRAP_CONTENT
, 1
)
);
ll.setId(R.id.mainview);
ll.setOrientation(LinearLayout.VERTICAL);
ll.setGravity(android.view.Gravity.FILL);
final ScrollView sv=new ScrollView(context);
sv.setId(R.id.scrollview);
sv.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, LinearLayout.LayoutParams.WRAP_CONTENT
, 1
)
);
sv.addView(ll);
final LinearLayout bg=new LinearLayout(context);
bg.setLayoutParams(
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT
, LinearLayout.LayoutParams.WRAP_CONTENT
, 1
)
);
bg.setOrientation(LinearLayout.VERTICAL);
bg.setGravity(android.view.Gravity.FILL);
bg.setTag(ll);
bg.addView(
titleView
, android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT
);
bg.addView(sv);
bg.addView(
pathEntryView
, android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT
);
return(bg);
}
////////////////////////////////////////////////////////////
private void makeView()
{
countDirectoryView=countFileView=0;
ScrollView sv=(ScrollView)contentView.findViewById(R.id.scrollview);
LinearLayout ll=(LinearLayout)sv.findViewById(R.id.mainview);
ll.removeAllViews();
if(cd == null) chdir("/");
String path=getCanonicalPath(cd);
if(path.equals("")) {chdir(path="/");}
if(path.equals("/"))
{
titleView.setVisibility(View.GONE);
}
else
{
titleView.setVisibility(View.VISIBLE);
titleView.requestLayout();
((TextView)titleView.findViewById(R.id.textview)).setText("["+cd.getPath()+"]");
}
String zd[]=cd.list(new java.io.FilenameFilter(){public boolean accept(File file, String name){return( new File(file, name).isDirectory() );}});
if(zd!=null)
{
java.util.Arrays.sort(zd, 0, zd.length, stringSortComparator);
for(int i=0, n=zd.length; i<n; i++)
{
if(zd[i].equals(".")) continue;
ll.addView(directoryEntry(zd[i]));
ll.addView(entryDividerH());
}
}
String zf[]=cd.list(new java.io.FilenameFilter(){public boolean accept(File file, String name){return(!(new File(file, name).isDirectory()));}});
if(zf!=null)
{
java.util.Arrays.sort(zf, 0, zf.length, stringSortComparator);
for(int i=0, n=zf.length; i<n; i++)
{
ll.addView(fileEntry(zf[i]));
ll.addView(entryDividerH());
}
}
((TextView)pathEntryView.findViewById(R.id.textview)).setText("");
sv.scrollTo(0, 0);
// titleView.setSelected(true);
setContentView(contentView);
}
//////////////////////////////////////////////////////////////////////
java.util.Comparator<String> stringSortComparator=new java.util.Comparator<String>()
{
public int compare(String a, String b) {return(a.toLowerCase().compareTo(b.toLowerCase()));}
};
//////////////////////////////////////////////////////////////////////
String getCanonicalPath(String path)
{
return(getCanonicalPath(new File(path)));
}
String getCanonicalPath(File file)
{
try{return(file.getCanonicalPath());}catch(IOException e){return(file.getPath());}
}
//////////////////////////////////////////////////////////////////////
public boolean onCreateOptionsMenu(Menu menu)
// public boolean onPrepareOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
// super.onPrepareOptionsMenu(menu); menu.clear();
menu.add(0, ACTION_THEME_SWAP, 0, getString(R.string.fsnavigator_change_theme));//"Change theme");
return(true);
}
//////////////////////////////////////////////////////////////////////
public boolean onOptionsItemSelected(MenuItem item)
{
super.onOptionsItemSelected(item);
return(doOptionsItem(item.getItemId()));
}
//////////////////////////////////////////////////////////////////////
private boolean doOptionsItem(int itemId)
{
switch(itemId)
{
case ACTION_THEME_SWAP: swapTheme(); return(true);
}
return(false);
}
//////////////////////////////////////////////////////////////////////
// private void toast(final String message){toast(message, 0);}
private void toast(final String message, final int duration)
{
runOnUiThread(
new Runnable()
{
public void run()
{
Toast.makeText(context, message, duration == 0 ?Toast.LENGTH_SHORT: Toast.LENGTH_LONG).show();
}
}
);
}
//////////////////////////////////////////////////////////////////////
}