/* * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * This file is part of FileExplorer. * * FileExplorer is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * FileExplorer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with SwiFTP. If not, see <http://www.gnu.org/licenses/>. */ package net.micode.fileexplorer; import java.io.File; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import android.app.Activity; import android.app.Fragment; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; import net.micode.fileexplorer.FileExplorerTabActivity.IBackPressedListener; import net.micode.fileexplorer.FileViewInteractionHub.Mode; public class FileViewActivity extends Fragment implements IFileInteractionListener, IBackPressedListener { public static final String EXT_FILTER_KEY = "ext_filter"; private static final String LOG_TAG = "FileViewActivity"; public static final String EXT_FILE_FIRST_KEY = "ext_file_first"; public static final String ROOT_DIRECTORY = "root_directory"; public static final String PICK_FOLDER = "pick_folder"; private ListView mFileListView; // private TextView mCurrentPathTextView; private ArrayAdapter<FileInfo> mAdapter; private FileViewInteractionHub mFileViewInteractionHub; private FileCategoryHelper mFileCagetoryHelper; private FileIconHelper mFileIconHelper; private ArrayList<FileInfo> mFileNameList = new ArrayList<FileInfo>(); private Activity mActivity; private View mRootView; private static final String sdDir = Util.getSdDirectory(); // memorize the scroll positions of previous paths private ArrayList<PathScrollPositionItem> mScrollPositionList = new ArrayList<PathScrollPositionItem>(); private String mPreviousPath; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Log.v(LOG_TAG, "received broadcast:" + intent.toString()); if (action.equals(Intent.ACTION_MEDIA_MOUNTED) || action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) { runOnUiThread(new Runnable() { @Override public void run() { updateUI(); } }); } } }; private boolean mBackspaceExit; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mActivity = getActivity(); // getWindow().setFormat(android.graphics.PixelFormat.RGBA_8888); mRootView = inflater.inflate(R.layout.file_explorer_list, container, false); ActivitiesManager.getInstance().registerActivity(ActivitiesManager.ACTIVITY_FILE_VIEW, mActivity); mFileCagetoryHelper = new FileCategoryHelper(mActivity); mFileViewInteractionHub = new FileViewInteractionHub(this); Intent intent = mActivity.getIntent(); String action = intent.getAction(); if (!TextUtils.isEmpty(action) && (action.equals(Intent.ACTION_PICK) || action.equals(Intent.ACTION_GET_CONTENT))) { mFileViewInteractionHub.setMode(Mode.Pick); boolean pickFolder = intent.getBooleanExtra(PICK_FOLDER, false); if (!pickFolder) { String[] exts = intent.getStringArrayExtra(EXT_FILTER_KEY); if (exts != null) { mFileCagetoryHelper.setCustomCategory(exts); } } else { mFileCagetoryHelper.setCustomCategory(new String[]{} /*folder only*/); mRootView.findViewById(R.id.pick_operation_bar).setVisibility(View.VISIBLE); mRootView.findViewById(R.id.button_pick_confirm).setOnClickListener(new OnClickListener() { public void onClick(View v) { try { Intent intent = Intent.parseUri(mFileViewInteractionHub.getCurrentPath(), 0); mActivity.setResult(Activity.RESULT_OK, intent); mActivity.finish(); } catch (URISyntaxException e) { e.printStackTrace(); } } }); mRootView.findViewById(R.id.button_pick_cancel).setOnClickListener(new OnClickListener() { public void onClick(View v) { mActivity.finish(); } }); } } else { mFileViewInteractionHub.setMode(Mode.View); } mFileListView = (ListView) mRootView.findViewById(R.id.file_path_list); mFileIconHelper = new FileIconHelper(mActivity); mAdapter = new FileListAdapter(mActivity, R.layout.file_browser_item, mFileNameList, mFileViewInteractionHub, mFileIconHelper); boolean baseSd = intent.getBooleanExtra(GlobalConsts.KEY_BASE_SD, !FileExplorerPreferenceActivity.isReadRoot(mActivity)); Log.i(LOG_TAG, "baseSd = " + baseSd); String rootDir = intent.getStringExtra(ROOT_DIRECTORY); if (!TextUtils.isEmpty(rootDir)) { if (baseSd && this.sdDir.startsWith(rootDir)) { rootDir = this.sdDir; } } else { rootDir = baseSd ? this.sdDir : GlobalConsts.ROOT_PATH; } mFileViewInteractionHub.setRootPath(rootDir); String currentDir = FileExplorerPreferenceActivity.getPrimaryFolder(mActivity); Uri uri = intent.getData(); if (uri != null) { if (baseSd && this.sdDir.startsWith(uri.getPath())) { currentDir = this.sdDir; } else { currentDir = uri.getPath(); } } mFileViewInteractionHub.setCurrentPath(currentDir); Log.i(LOG_TAG, "CurrentDir = " + currentDir); mBackspaceExit = (uri != null) && (TextUtils.isEmpty(action) || (!action.equals(Intent.ACTION_PICK) && !action.equals(Intent.ACTION_GET_CONTENT))); mFileListView.setAdapter(mAdapter); mFileViewInteractionHub.refreshFileList(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); intentFilter.addDataScheme("file"); mActivity.registerReceiver(mReceiver, intentFilter); updateUI(); setHasOptionsMenu(true); return mRootView; } @Override public void onDestroyView() { super.onDestroyView(); mActivity.unregisterReceiver(mReceiver); } @Override public void onPrepareOptionsMenu(Menu menu) { mFileViewInteractionHub.onPrepareOptionsMenu(menu); super.onPrepareOptionsMenu(menu); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { mFileViewInteractionHub.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onBack() { if (mBackspaceExit || !Util.isSDCardReady() || mFileViewInteractionHub == null) { return false; } return mFileViewInteractionHub.onBackPressed(); } private class PathScrollPositionItem { String path; int pos; PathScrollPositionItem(String s, int p) { path = s; pos = p; } } // execute before change, return the memorized scroll position private int computeScrollPosition(String path) { int pos = 0; if(mPreviousPath!=null) { if (path.startsWith(mPreviousPath)) { int firstVisiblePosition = mFileListView.getFirstVisiblePosition(); if (mScrollPositionList.size() != 0 && mPreviousPath.equals(mScrollPositionList.get(mScrollPositionList.size() - 1).path)) { mScrollPositionList.get(mScrollPositionList.size() - 1).pos = firstVisiblePosition; Log.i(LOG_TAG, "computeScrollPosition: update item: " + mPreviousPath + " " + firstVisiblePosition + " stack count:" + mScrollPositionList.size()); pos = firstVisiblePosition; } else { mScrollPositionList.add(new PathScrollPositionItem(mPreviousPath, firstVisiblePosition)); Log.i(LOG_TAG, "computeScrollPosition: add item: " + mPreviousPath + " " + firstVisiblePosition + " stack count:" + mScrollPositionList.size()); } } else { int i; boolean isLast = false; for (i = 0; i < mScrollPositionList.size(); i++) { if (!path.startsWith(mScrollPositionList.get(i).path)) { break; } } // navigate to a totally new branch, not in current stack if (i > 0) { pos = mScrollPositionList.get(i - 1).pos; } for (int j = mScrollPositionList.size() - 1; j >= i-1 && j>=0; j--) { mScrollPositionList.remove(j); } } } Log.i(LOG_TAG, "computeScrollPosition: result pos: " + path + " " + pos + " stack count:" + mScrollPositionList.size()); mPreviousPath = path; return pos; } public boolean onRefreshFileList(String path, FileSortHelper sort) { File file = new File(path); if (!file.exists() || !file.isDirectory()) { return false; } final int pos = computeScrollPosition(path); ArrayList<FileInfo> fileList = mFileNameList; fileList.clear(); File[] listFiles = file.listFiles(mFileCagetoryHelper.getFilter()); if (listFiles == null) return true; for (File child : listFiles) { // do not show selected file if in move state if (mFileViewInteractionHub.isMoveState() && mFileViewInteractionHub.isFileSelected(child.getPath())) continue; String absolutePath = child.getAbsolutePath(); if (Util.isNormalFile(absolutePath) && Util.shouldShowFile(absolutePath)) { FileInfo lFileInfo = Util.GetFileInfo(child, mFileCagetoryHelper.getFilter(), Settings.instance().getShowDotAndHiddenFiles()); if (lFileInfo != null) { fileList.add(lFileInfo); } } } sortCurrentList(sort); showEmptyView(fileList.size() == 0); mFileListView.post(new Runnable() { @Override public void run() { mFileListView.setSelection(pos); } }); return true; } private void updateUI() { boolean sdCardReady = Util.isSDCardReady(); View noSdView = mRootView.findViewById(R.id.sd_not_available_page); noSdView.setVisibility(sdCardReady ? View.GONE : View.VISIBLE); View navigationBar = mRootView.findViewById(R.id.navigation_bar); navigationBar.setVisibility(sdCardReady ? View.VISIBLE : View.GONE); mFileListView.setVisibility(sdCardReady ? View.VISIBLE : View.GONE); if(sdCardReady) { mFileViewInteractionHub.refreshFileList(); } } private void showEmptyView(boolean show) { View emptyView = mRootView.findViewById(R.id.empty_view); if (emptyView != null) emptyView.setVisibility(show ? View.VISIBLE : View.GONE); } @Override public View getViewById(int id) { return mRootView.findViewById(id); } @Override public Context getContext() { return mActivity; } @Override public void onDataChanged() { runOnUiThread(new Runnable() { @Override public void run() { mAdapter.notifyDataSetChanged(); } }); } @Override public void onPick(FileInfo f) { try { Intent intent = Intent.parseUri(Uri.fromFile(new File(f.filePath)).toString(), 0); mActivity.setResult(Activity.RESULT_OK, intent); mActivity.finish(); return; } catch (URISyntaxException e) { e.printStackTrace(); } } @Override public boolean shouldShowOperationPane() { return true; } @Override public boolean onOperation(int id) { return false; } //支持显示真实路径 @Override public String getDisplayPath(String path) { if (path.startsWith(this.sdDir) && !FileExplorerPreferenceActivity.showRealPath(mActivity)) { return getString(R.string.sd_folder) + path.substring(this.sdDir.length()); } else { return path; } } @Override public String getRealPath(String displayPath) { final String perfixName = getString(R.string.sd_folder); if (displayPath.startsWith(perfixName)) { return this.sdDir + displayPath.substring(perfixName.length()); } else { return displayPath; } } @Override public boolean onNavigation(String path) { return false; } @Override public boolean shouldHideMenu(int menu) { return false; } public void copyFile(ArrayList<FileInfo> files) { mFileViewInteractionHub.onOperationCopy(files); } public void refresh() { if (mFileViewInteractionHub != null) { mFileViewInteractionHub.refreshFileList(); } } public void moveToFile(ArrayList<FileInfo> files) { mFileViewInteractionHub.moveFileFrom(files); } public interface SelectFilesCallback { // files equals null indicates canceled void selected(ArrayList<FileInfo> files); } public void startSelectFiles(SelectFilesCallback callback) { mFileViewInteractionHub.startSelectFiles(callback); } @Override public FileIconHelper getFileIconHelper() { return mFileIconHelper; } public boolean setPath(String location) { if (!location.startsWith(mFileViewInteractionHub.getRootPath())) { return false; } mFileViewInteractionHub.setCurrentPath(location); mFileViewInteractionHub.refreshFileList(); return true; } @Override public FileInfo getItem(int pos) { if (pos < 0 || pos > mFileNameList.size() - 1) return null; return mFileNameList.get(pos); } @SuppressWarnings("unchecked") @Override public void sortCurrentList(FileSortHelper sort) { Collections.sort(mFileNameList, sort.getComparator()); onDataChanged(); } @Override public ArrayList<FileInfo> getAllFiles() { return mFileNameList; } @Override public void addSingleFile(FileInfo file) { mFileNameList.add(file); onDataChanged(); } @Override public int getItemCount() { return mFileNameList.size(); } @Override public void runOnUiThread(Runnable r) { mActivity.runOnUiThread(r); } }