package com.lfk.justwetools.View.FileExplorer; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.util.AttributeSet; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import com.lfk.justwetools.R; import java.io.File; import java.util.ArrayList; import java.util.Comparator; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.TreeMap; public class FileExplorer extends ListView { private String dir = Environment.getExternalStorageDirectory().getPath(); private String root = Environment.getExternalStorageDirectory().getPath(); private List<Map<String, Object>> fileList = new ArrayList<>(); private OnFolderChosenListener folderChosenListener = null; private OnPathChangedListener pathChangedListener = null; private OnFileChosenListener fileChosenListener = null; private SimpleAdapter listAdapter = null; private Context context; //////////////////////////////////////////////////////////////////////////// ////////////////// Default Constructor /////////////////////// //////////////////////////////////////////////////////////////////////////// public FileExplorer(Context context) { super(context); initList(context); } public FileExplorer(Context context, AttributeSet attrs) { super(context, attrs); initList(context); } public FileExplorer(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initList(context); } //////////////////////////////////////////////////////////////////////////// //////////////// Automatic Constructor /////////////////////// //////////////////////////////////////////////////////////////////////////// /** * 自定义初始化 */ private void initList(Context context) { this.context = context; listAdapter = new SimpleAdapter( context, fileList, R.layout.list_item, new String[]{"image", "filename"}, new int[]{R.id.list_image, R.id.list_text}); initListener(); this.setAdapter(listAdapter); setCurrentDir(dir); } //////////////////////////////////////////////////////////////////////////// ///////////////////////// Listener /////////////////////////// //////////////////////////////////////////////////////////////////////////// private void initListener() { this.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String fileName = ((TextView) view.findViewById(R.id.list_text)).getText().toString(); try { File file = new File(dir + "/" + fileName); if (file.isFile()) { if(fileChosenListener == null) { String mime = getMIMEType(file); if (mime != null) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file://" + file.getPath()), mime); context.startActivity(intent); } } else { fileChosenListener.onFileChosen(Uri.parse("file://" + file.getPath())); } } else if (file.isDirectory()) { setCurrentDir(file.getPath()); } } catch (Exception e) { e.printStackTrace(); } } }); this.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(final AdapterView<?> parent, View view, int position, long id) { final String fileName = ((TextView) view.findViewById(R.id.list_text)).getText().toString(); if(new File(dir + "/" + fileName).isDirectory()) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setMessage("确认选择该文件夹吗?"); builder.setTitle("提示"); builder.setPositiveButton("确认", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); if (folderChosenListener != null) folderChosenListener.onItemChosen(dir + "/" + fileName); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } return true; } }); } public void setOnItemChosenListener(OnFolderChosenListener listener) { this.folderChosenListener = listener; } public void setOnPathChangedListener(OnPathChangedListener listener) { this.pathChangedListener = listener; } public void setOnFileChosenListener(OnFileChosenListener fileChosenListener) { this.fileChosenListener = fileChosenListener; } //////////////////////////////////////////////////////////////////////////// //////////////////////// File Utils /////////////////////////// //////////////////////////////////////////////////////////////////////////// /** * 获取文件的后缀名 * * @param file 接受一个文件,返回该文件的后缀名,如果是目录则返回null */ public String getType(File file){ if(file.isDirectory()) return null; int dotIndex = file.getName().lastIndexOf("."); if(dotIndex < 0) return ""; return file.getName().substring(dotIndex).toLowerCase(); } /** * 获取文件的MIME类型 * * @param file 接受一个文件,返回该文件的MIME,如果是目录则返回null */ private String getMIMEType(File file) { String type = getType(file); //在MIME和文件类型的匹配表中找到对应的MIME类型。 if(type != null) { boolean found = false; for (String[] data : MIME_Table) { if (type.equals(data[0])) { type = data[1]; found = true; break; } } if(!found) type = "*/*"; } return type; } //////////////////////////////////////////////////////////////////////////// ///////////////////////// Settings /////////////////////////// //////////////////////////////////////////////////////////////////////////// /** * 设置并刷新浏览目录 */ public void setCurrentDir(String path) { File[] files = (new File(path)).listFiles(); //如果这不是一个路径 if (files == null) return; dir = path; //更新Map fileList.clear(); for (File file : files) { Map<String, Object> fileInfo = new Hashtable<>(); if (file.isFile()) fileInfo.put("image", Images[1]); else fileInfo.put("image", Images[0]); fileInfo.put("filename", file.getName()); fileList.add(fileInfo); } listAdapter.notifyDataSetChanged(); if(pathChangedListener != null) pathChangedListener.onPathChanged(path); } /** * 返回上一级目录 */ public boolean toParentDir() { File file = new File(dir); String parentDir = file.getParent(); if(parentDir != null && !file.getPath().equals(root)) { dir = parentDir; setCurrentDir(dir); return true; } return false; } public void setRootDir(String rootDir) { this.root = rootDir; } /** * 刷新重新载入 */ public void refresh() { setCurrentDir(dir); } /** * 获取当前路径 */ public String getCurrentPath() { return dir; } //////////////////////////////////////////////////////////////////////////// //////////////////////// Extras /////////////////////////// //////////////////////////////////////////////////////////////////////////// /** * 获取文件类型大小比例 */ private void getProportion (TreeMap<String,Long> map,String path) throws Exception { File[] files = new File(path).listFiles(); //如果这不是一个路径 if (files == null) throw new Exception("EMPTY OR ROOT FILE"); for (File file : files) { if (file.isFile()) { String type = getType(file).replace(".", ""); if (map.containsKey(type)) map.put(type, map.get(type) + file.length()); else map.put(type, file.length()); } else if (file.isDirectory()) { getProportion(map, file.getPath()); } } } public TreeMap<String, Long> getPropotionText(String path) throws Exception { TreeMap<String, Long> buf = new TreeMap<>(); getProportion(buf, path); TreeMap<String, Long> map = new TreeMap<>(new SizeComparator(buf)); map.putAll(buf); return map; } class SizeComparator implements Comparator<String> { TreeMap<String, Long> map; SizeComparator(TreeMap<String, Long> map){ this.map = map; } @Override public int compare(String a, String b) { if(map.get(a).equals(map.get(b))) return 0; return map.get(a) > map.get(b) ? 1 : -1; } } //////////////////////////////////////////////////////////////////////////// //////////////////////// Resources /////////////////////////// //////////////////////////////////////////////////////////////////////////// // 文件夹&文件 图片 private int[] Images = {R.drawable.file,R.drawable.afile}; //MIME类型集合,{后缀名,MIME类型} public static final String[][] MIME_Table = { {".3gp", "video/3gp"}, {".apk", "application/vnd.android.package-archive"}, {".asf", "video/x-ms-asf"}, {".avi", "video/x-msvideo"}, {".bin", "application/octet-stream"}, {".bmp", "image/bmp"}, {".c", "text/plain"}, {".class", "application/octet-stream"}, {".conf", "text/plain"}, {".cpp", "text/plain"}, {".doc", "application/msword"}, {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, {".xls", "application/vnd.ms-excel"}, {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, {".exe", "application/octet-stream"}, {".gif", "image/gif"}, {".gtar", "application/x-gtar"}, {".gz", "application/x-gzip"}, {".h", "text/plain"}, {".htm", "text/html"}, {".html", "text/html"}, {".jar", "application/java-archive"}, {".java", "text/plain"}, {".jpeg", "image/jpeg"}, {".jpg", "image/jpeg"}, {".js", "application/x-javascript"}, {".log", "text/plain"}, {".m3u", "audio/x-mpegurl"}, {".m4a", "audio/mp4a-latm"}, {".m4b", "audio/mp4a-latm"}, {".m4p", "audio/mp4a-latm"}, {".m4u", "video/vnd.mpegurl"}, {".m4v", "video/x-m4v"}, {".mov", "video/quicktime"}, {".mp2", "audio/x-mpeg"}, {".mp3", "audio/x-mpeg"}, {".mp4", "video/mp4"}, {".mpc", "application/vnd.mpohun.certificate"}, {".mpe", "video/mpeg"}, {".mpeg", "video/mpeg"}, {".mpg", "video/mpeg"}, {".mpg4", "video/mp4"}, {".mpga", "audio/mpeg"}, {".msg", "application/vnd.ms-outlook"}, {".ogg", "audio/ogg"}, {".pdf", "application/pdf"}, {".png", "image/png"}, {".pps", "application/vnd.ms-powerpoint"}, {".ppt", "application/vnd.ms-powerpoint"}, {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, {".prop", "text/plain"}, {".rc", "text/plain"}, {".rmvb", "audio/x-pn-realaudio"}, {".rtf", "application/rtf"}, {".sh", "text/plain"}, {".tar", "application/x-tar"}, {".tgz", "application/x-compressed"}, {".txt", "text/plain"}, {".wav", "audio/x-wav"}, {".wma", "audio/x-ms-wma"}, {".wmv", "audio/x-ms-wmv"}, {".wps", "application/vnd.ms-works"}, {".xml", "text/plain"}, {".z", "application/x-compress"}, {".zip", "application/x-zip-compressed"}, {"", "*/*"} }; }