546 lines
16 KiB
Java
546 lines
16 KiB
Java
package com.reicast.emulator;
|
|
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.FilenameFilter;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
import android.app.Activity;
|
|
import android.app.AlertDialog;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.SharedPreferences;
|
|
import android.graphics.Typeface;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.net.Uri;
|
|
import android.os.AsyncTask;
|
|
import android.os.Bundle;
|
|
import android.os.Environment;
|
|
import android.os.Vibrator;
|
|
import android.preference.PreferenceManager;
|
|
import android.support.v4.app.Fragment;
|
|
import android.view.LayoutInflater;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.view.View.OnClickListener;
|
|
import android.view.View.OnTouchListener;
|
|
import android.view.ViewGroup;
|
|
import android.widget.ImageView;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.ScrollView;
|
|
import android.widget.TextView;
|
|
import android.widget.Toast;
|
|
|
|
import com.android.util.FileUtils;
|
|
import com.reicast.emulator.config.Config;
|
|
import com.reicast.emulator.emu.JNIdc;
|
|
|
|
public class FileBrowser extends Fragment {
|
|
|
|
private Vibrator vib;
|
|
private Drawable orig_bg;
|
|
private Activity parentActivity;
|
|
private boolean ImgBrowse;
|
|
private boolean games;
|
|
private OnItemSelectedListener mCallback;
|
|
|
|
private SharedPreferences mPrefs;
|
|
private File sdcard = Environment.getExternalStorageDirectory();
|
|
private String home_directory = sdcard.getAbsolutePath().replace("emulated/0", "sdcard0");
|
|
private String game_directory = sdcard.getAbsolutePath().replace("emulated/0", "sdcard0");
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
mPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
|
home_directory = mPrefs.getString(Config.pref_home, home_directory);
|
|
game_directory = mPrefs.getString(Config.pref_games, game_directory);
|
|
|
|
Bundle b = getArguments();
|
|
if (b != null) {
|
|
ImgBrowse = b.getBoolean("ImgBrowse", true);
|
|
if (games = b.getBoolean("games_entry", false)) {
|
|
if (b.getString("path_entry") != null) {
|
|
home_directory = b.getString("path_entry");
|
|
}
|
|
} else {
|
|
if (b.getString("path_entry") != null) {
|
|
game_directory = b.getString("path_entry");
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public static HashSet<String> getExternalMounts() {
|
|
final HashSet<String> out = new HashSet<String>();
|
|
String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4|fuse).*rw.*";
|
|
String s = "";
|
|
try {
|
|
final Process process = new ProcessBuilder().command("mount")
|
|
.redirectErrorStream(true).start();
|
|
process.waitFor();
|
|
final InputStream is = process.getInputStream();
|
|
final byte[] buffer = new byte[1024];
|
|
while (is.read(buffer) != -1) {
|
|
s = s + new String(buffer);
|
|
}
|
|
is.close();
|
|
} catch (final Exception e) {
|
|
|
|
}
|
|
|
|
final String[] lines = s.split("\n");
|
|
for (String line : lines) {
|
|
if (StringUtils.containsIgnoreCase(line, "secure"))
|
|
continue;
|
|
if (StringUtils.containsIgnoreCase(line, "asec"))
|
|
continue;
|
|
if (line.matches(reg)) {
|
|
String[] parts = line.split(" ");
|
|
for (String part : parts) {
|
|
if (part.startsWith("/"))
|
|
if (!StringUtils.containsIgnoreCase(part, "vold"))
|
|
out.add(part);
|
|
}
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
// Container Activity must implement this interface
|
|
public interface OnItemSelectedListener {
|
|
void onGameSelected(Uri uri);
|
|
void onFolderSelected(Uri uri);
|
|
}
|
|
|
|
@Override
|
|
public void onAttach(Activity activity) {
|
|
super.onAttach(activity);
|
|
|
|
// This makes sure that the container activity has implemented
|
|
// the callback interface. If not, it throws an exception
|
|
try {
|
|
mCallback = (OnItemSelectedListener) activity;
|
|
} catch (ClassCastException e) {
|
|
throw new ClassCastException(activity.toString()
|
|
+ " must implement OnItemSelectedListener");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
Bundle savedInstanceState) {
|
|
return inflater.inflate(R.layout.activity_main, container, false);
|
|
}
|
|
|
|
@Override
|
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
|
// setContentView(R.layout.activity_main);
|
|
parentActivity = getActivity();
|
|
try {
|
|
File buttons = null;
|
|
String theme = mPrefs.getString(Config.pref_theme, null);
|
|
if (theme != null) {
|
|
buttons = new File(theme);
|
|
}
|
|
File file = new File(home_directory, "data/buttons.png");
|
|
if (buttons != null && buttons.exists()) {
|
|
InputStream in = new FileInputStream(buttons);
|
|
OutputStream out = new FileOutputStream(file);
|
|
|
|
// Transfer bytes from in to out
|
|
byte[] buf = new byte[1024];
|
|
int len;
|
|
while ((len = in.read(buf)) > 0) {
|
|
out.write(buf, 0, len);
|
|
}
|
|
in.close();
|
|
out.close();
|
|
} else if (!file.exists()) {
|
|
file.createNewFile();
|
|
OutputStream fo = new FileOutputStream(file);
|
|
InputStream png = parentActivity.getAssets()
|
|
.open("buttons.png");
|
|
|
|
byte[] buffer = new byte[4096];
|
|
int len = 0;
|
|
while ((len = png.read(buffer)) != -1) {
|
|
fo.write(buffer, 0, len);
|
|
}
|
|
fo.close();
|
|
png.close();
|
|
}
|
|
} catch (IOException ioe) {
|
|
ioe.printStackTrace();
|
|
}
|
|
|
|
vib = (Vibrator) parentActivity
|
|
.getSystemService(Context.VIBRATOR_SERVICE);
|
|
|
|
/*
|
|
* OnTouchListener viblist=new OnTouchListener() {
|
|
*
|
|
* public boolean onTouch(View v, MotionEvent event) { if
|
|
* (event.getActionMasked()==MotionEvent.ACTION_DOWN) vib.vibrate(50);
|
|
* return false; } };
|
|
*
|
|
* findViewById(R.id.config).setOnTouchListener(viblist);
|
|
* findViewById(R.id.about).setOnTouchListener(viblist);
|
|
*/
|
|
|
|
File home = new File(mPrefs.getString(Config.pref_home, home_directory));
|
|
if (!home.exists() || !home.isDirectory()) {
|
|
MainActivity.showToastMessage(getActivity(),
|
|
getActivity().getString(R.string.config_home),
|
|
Toast.LENGTH_LONG);
|
|
}
|
|
|
|
if (!ImgBrowse && !games) {
|
|
new LocateGames(R.array.flash).execute(home_directory);
|
|
} else {
|
|
new LocateGames(R.array.images).execute(game_directory);
|
|
}
|
|
}
|
|
|
|
private final class LocateGames extends AsyncTask<String, Integer, List<File>> {
|
|
|
|
private int array;
|
|
|
|
public LocateGames(int arrayType) {
|
|
this.array = arrayType;
|
|
}
|
|
|
|
@Override
|
|
protected List<File> doInBackground(String... paths) {
|
|
File storage = new File(paths[0]);
|
|
|
|
// array of valid image file extensions
|
|
String[] mediaTypes = parentActivity.getResources().getStringArray(array);
|
|
FilenameFilter[] filter = new FilenameFilter[mediaTypes.length];
|
|
|
|
int i = 0;
|
|
for (final String type : mediaTypes) {
|
|
filter[i] = new FilenameFilter() {
|
|
|
|
public boolean accept(File dir, String name) {
|
|
if (dir.getName().equals("obb") || dir.getName().equals("cache")
|
|
|| dir.getName().startsWith(".") || name.startsWith(".")) {
|
|
return false;
|
|
} else {
|
|
return StringUtils.endsWithIgnoreCase(name, "." + type);
|
|
}
|
|
}
|
|
|
|
};
|
|
i++;
|
|
}
|
|
|
|
FileUtils fileUtils = new FileUtils();
|
|
int recurse = 2;
|
|
if (array != R.array.images) {
|
|
recurse = 4;
|
|
}
|
|
Collection<File> files = fileUtils.listFiles(storage, filter, recurse);
|
|
return (List<File>) files;
|
|
}
|
|
|
|
@Override
|
|
protected void onPostExecute(List<File> items) {
|
|
if (items != null && !items.isEmpty()) {
|
|
final LinearLayout list = (LinearLayout) parentActivity.findViewById(R.id.game_list);
|
|
if (list != null) {
|
|
list.removeAllViews();
|
|
}
|
|
|
|
String heading = parentActivity.getString(R.string.games_listing);
|
|
createListHeader(heading, list, array == R.array.images);
|
|
for (int i = 0; i < items.size(); i++) {
|
|
createListItem(list, items.get(i), i, array == R.array.images);
|
|
}
|
|
list.invalidate();
|
|
} else {
|
|
browseStorage(array == R.array.images);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void browseStorage(boolean images) {
|
|
if (images) {
|
|
navigate(new File(home_directory));
|
|
} else {
|
|
if (game_directory.equals(sdcard.getAbsolutePath().replace("emulated/0", "sdcard0"))) {
|
|
HashSet<String> extStorage = FileBrowser.getExternalMounts();
|
|
if (extStorage != null && !extStorage.isEmpty()) {
|
|
for (Iterator<String> sd = extStorage.iterator(); sd.hasNext();) {
|
|
String sdCardPath = sd.next().replace("mnt/media_rw", "storage");
|
|
if (!sdCardPath.equals(sdcard.getAbsolutePath())) {
|
|
if (new File(sdCardPath).canRead()) {
|
|
navigate(new File(sdCardPath));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
navigate(new File(game_directory));
|
|
}
|
|
}
|
|
|
|
private static final class DirSort implements Comparator<File> {
|
|
|
|
@Override
|
|
public int compare(File filea, File fileb) {
|
|
|
|
return ((filea.isFile() ? "a" : "b") + filea.getName().toLowerCase(
|
|
Locale.getDefault()))
|
|
.compareTo((fileb.isFile() ? "a" : "b")
|
|
+ fileb.getName().toLowerCase(Locale.getDefault()));
|
|
}
|
|
}
|
|
|
|
private void createListHeader(String header_text, View view, boolean hasBios) {
|
|
if (hasBios) {
|
|
final View childview = parentActivity.getLayoutInflater().inflate(
|
|
R.layout.bios_list_item, null, false);
|
|
|
|
((TextView) childview.findViewById(R.id.item_name))
|
|
.setText(R.string.boot_bios);
|
|
|
|
childview.setTag(null);
|
|
|
|
orig_bg = childview.getBackground();
|
|
|
|
childview.findViewById(R.id.childview).setOnClickListener(
|
|
new OnClickListener() {
|
|
public void onClick(View view) {
|
|
File f = (File) view.getTag();
|
|
vib.vibrate(50);
|
|
mCallback.onGameSelected(f != null ? Uri
|
|
.fromFile(f) : Uri.EMPTY);
|
|
vib.vibrate(250);
|
|
}
|
|
});
|
|
|
|
childview.findViewById(R.id.childview).setOnTouchListener(
|
|
new OnTouchListener() {
|
|
@SuppressWarnings("deprecation")
|
|
public boolean onTouch(View view, MotionEvent arg1) {
|
|
if (arg1.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
|
view.setBackgroundColor(0xFF4F3FFF);
|
|
} else if (arg1.getActionMasked() == MotionEvent.ACTION_CANCEL
|
|
|| arg1.getActionMasked() == MotionEvent.ACTION_UP) {
|
|
view.setBackgroundDrawable(orig_bg);
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
});
|
|
((ViewGroup) view).addView(childview);
|
|
}
|
|
|
|
final View headerView = parentActivity.getLayoutInflater().inflate(
|
|
R.layout.head_list_item, null, false);
|
|
((ImageView) headerView.findViewById(R.id.item_icon))
|
|
.setImageResource(R.drawable.open_folder);
|
|
((TextView) headerView.findViewById(R.id.item_name))
|
|
.setText(header_text);
|
|
((TextView) headerView.findViewById(R.id.item_name))
|
|
.setTypeface(Typeface.DEFAULT_BOLD);
|
|
((ViewGroup) view).addView(headerView);
|
|
|
|
}
|
|
|
|
private void createListItem(LinearLayout list, final File game, final int index, final boolean isGame) {
|
|
final View childview = parentActivity.getLayoutInflater().inflate(
|
|
R.layout.app_list_item, null, false);
|
|
|
|
XMLParser xmlParser = new XMLParser(game, index, mPrefs);
|
|
xmlParser.setViewParent(parentActivity, childview, mCallback);
|
|
orig_bg = childview.getBackground();
|
|
|
|
childview.findViewById(R.id.childview).setOnClickListener(
|
|
new OnClickListener() {
|
|
public void onClick(View view) {
|
|
if (isGame) {
|
|
vib.vibrate(50);
|
|
mCallback.onGameSelected(game != null ? Uri
|
|
.fromFile(game) : Uri.EMPTY);
|
|
vib.vibrate(250);
|
|
} else {
|
|
vib.vibrate(50);
|
|
mCallback.onFolderSelected(game != null ? Uri
|
|
.fromFile(game) : Uri.EMPTY);
|
|
home_directory = game.getAbsolutePath().substring(0,
|
|
game.getAbsolutePath().lastIndexOf(File.separator)).replace("/data", "");
|
|
if (!DataDirectoryBIOS()) {
|
|
MainActivity.showToastMessage(getActivity(),
|
|
getActivity().getString(R.string.config_data, home_directory),
|
|
Toast.LENGTH_LONG);
|
|
}
|
|
mPrefs.edit().putString("home_directory", home_directory).commit();
|
|
JNIdc.config(home_directory.replace("/data", ""));
|
|
}
|
|
}
|
|
});
|
|
|
|
childview.findViewById(R.id.childview).setOnTouchListener(
|
|
new OnTouchListener() {
|
|
@SuppressWarnings("deprecation")
|
|
public boolean onTouch(View view, MotionEvent arg1) {
|
|
if (arg1.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
|
view.setBackgroundColor(0xFF4F3FFF);
|
|
} else if (arg1.getActionMasked() == MotionEvent.ACTION_CANCEL
|
|
|| arg1.getActionMasked() == MotionEvent.ACTION_UP) {
|
|
view.setBackgroundDrawable(orig_bg);
|
|
}
|
|
return false;
|
|
|
|
}
|
|
});
|
|
list.addView(childview);
|
|
xmlParser.execute(game.getName());
|
|
}
|
|
|
|
void navigate(final File root_sd) {
|
|
LinearLayout v = (LinearLayout) parentActivity
|
|
.findViewById(R.id.game_list);
|
|
v.removeAllViews();
|
|
|
|
ArrayList<File> list = new ArrayList<File>();
|
|
|
|
final String heading = root_sd.getAbsolutePath();
|
|
createListHeader(heading, v, false);
|
|
|
|
File flist[] = root_sd.listFiles();
|
|
File parent = root_sd.getParentFile();
|
|
|
|
list.add(null);
|
|
|
|
if (parent != null) {
|
|
list.add(parent);
|
|
}
|
|
|
|
if (flist != null) {
|
|
Arrays.sort(flist, new DirSort());
|
|
Collections.addAll(list, flist);
|
|
}
|
|
|
|
for (final File file : list) {
|
|
if (file != null && !file.isDirectory() && !file.getAbsolutePath().equals("/data"))
|
|
continue;
|
|
final View childview = parentActivity.getLayoutInflater().inflate(
|
|
R.layout.app_list_item, null, false);
|
|
|
|
if (file == null) {
|
|
((TextView) childview.findViewById(R.id.item_name)).setText(R.string.folder_select);
|
|
} else if (file == parent)
|
|
((TextView) childview.findViewById(R.id.item_name)).setText("..");
|
|
else
|
|
((TextView) childview.findViewById(R.id.item_name)).setText(file.getName());
|
|
|
|
((ImageView) childview.findViewById(R.id.item_icon))
|
|
.setImageResource(file == null ? R.drawable.config
|
|
: file.isDirectory() ? R.drawable.open_folder
|
|
: R.drawable.disk_unknown);
|
|
|
|
childview.setTag(file);
|
|
|
|
orig_bg = childview.getBackground();
|
|
|
|
// vw.findViewById(R.id.childview).setBackgroundColor(0xFFFFFFFF);
|
|
|
|
childview.findViewById(R.id.childview).setOnClickListener(
|
|
new OnClickListener() {
|
|
public void onClick(View view) {
|
|
if (file != null && file.isDirectory()) {
|
|
navigate(file);
|
|
ScrollView sv = (ScrollView) parentActivity
|
|
.findViewById(R.id.game_scroller);
|
|
sv.scrollTo(0, 0);
|
|
vib.vibrate(50);
|
|
} else if (view.getTag() == null) {
|
|
vib.vibrate(50);
|
|
|
|
mCallback.onFolderSelected(Uri
|
|
.fromFile(new File(heading)));
|
|
vib.vibrate(250);
|
|
|
|
if (games) {
|
|
game_directory = heading;
|
|
mPrefs.edit()
|
|
.putString(Config.pref_games,
|
|
heading).commit();
|
|
} else {
|
|
home_directory = heading.replace("/data", "");
|
|
mPrefs.edit()
|
|
.putString(Config.pref_home,
|
|
heading).commit();
|
|
if (!DataDirectoryBIOS()) {
|
|
MainActivity.showToastMessage(getActivity(),
|
|
getActivity().getString(R.string.config_data, home_directory),
|
|
Toast.LENGTH_LONG);
|
|
}
|
|
JNIdc.config(heading);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
childview.findViewById(R.id.childview).setOnTouchListener(
|
|
new OnTouchListener() {
|
|
@SuppressWarnings("deprecation")
|
|
public boolean onTouch(View view, MotionEvent event) {
|
|
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
|
view.setBackgroundColor(0xFF4F3FFF);
|
|
} else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
|
|
|| event.getActionMasked() == MotionEvent.ACTION_UP) {
|
|
view.setBackgroundDrawable(orig_bg);
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
});
|
|
v.addView(childview);
|
|
}
|
|
v.invalidate();
|
|
}
|
|
|
|
private boolean DataDirectoryBIOS() {
|
|
File data_directory = new File(home_directory, "data");
|
|
if (!data_directory.exists() || !data_directory.isDirectory()) {
|
|
data_directory.mkdirs();
|
|
File bios = new File(home_directory, "dc_boot.bin");
|
|
boolean success = bios.renameTo(new File(home_directory, "data/dc_boot.bin"));
|
|
File flash = new File(home_directory, "dc_flash.bin");
|
|
success = flash.renameTo(new File(home_directory, "data/dc_flash.bin"));
|
|
return success;
|
|
} else {
|
|
File bios = new File(home_directory, "data/dc_boot.bin");
|
|
File flash = new File(home_directory, "data/dc_flash.bin");
|
|
if (bios.exists() && flash.exists()) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|