/**************************************************************************** * Copyright (C) 2013 HS Coburg. * All rights reserved. * Contact: ecsec GmbH (info@ecsec.de) * * This file is part of the Open eCard App. * * GNU General Public License Usage * This file may be used under the terms of the GNU General Public * License version 3.0 as published by the Free Software Foundation * and appearing in the file LICENSE.GPL included in the packaging of * this file. Please review the following information to ensure the * GNU General Public License version 3.0 requirements will be met: * http://www.gnu.org/copyleft/gpl.html. * * Other Usage * Alternatively, this file may be used in accordance with the terms * and conditions contained in a signed written agreement between * you and ecsec GmbH. * ***************************************************************************/ package org.openecard.gui.android; import android.app.AlertDialog; import android.app.ListActivity; import android.content.DialogInterface; import android.os.Bundle; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.TreeMap; import org.openecard.common.I18n; import org.openecard.gui.file.AcceptAllFilesFilter; import org.openecard.gui.file.FileDialogResult; import org.openecard.gui.file.FileFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This Activity is used by {@link AndroidMessageDialog} to show a MessageDialog. It uses the parameters given in the * calling Intent to adapt the representation according to them. * * @author Dirk Petrautzki <petrautzki@hs-coburg.de> */ public class FileDialogActivity extends ListActivity { private final I18n lang = I18n.getTranslation("gui"); private static final Logger logger = LoggerFactory.getLogger(FileDialogActivity.class); private static final String ITEM_FILENAME = "key"; private static final String ITEM_IMAGE = "image"; private static final String ROOT_DIRECTORY = "/"; public static final String RESULT = "RESULT"; public static final int RESULT_CODE = 3; private TextView textViewCurrentPath; private EditText mFileName; private ArrayList<HashMap<String, Object>> listItems = new ArrayList<HashMap<String, Object>>(); private Button selectButton; private LinearLayout layoutSelect; private LinearLayout layoutCreate; private InputMethodManager inputManager; private String parentPath; private File currentPath; private File selectedFile; private Boolean folderSelectable; private Boolean showHiddenFiles; private String title; private ArrayList<FileFilter> fileFilters; private FileDialogType dialogType; private String approveButtonText; private TextView textViewFileName; private SimpleAdapter listItemsAdapter; // TODO pre- and multiselection are currently not supported private ArrayList<File> selectedFiles; private Boolean multiSelectionEnabled; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setResult(RESULT_CODE, getIntent()); // set up the layout setContentView(R.layout.file_dialog); textViewCurrentPath = (TextView) findViewById(R.id.path); textViewFileName = (TextView) findViewById(R.id.textViewFilename); textViewFileName.setText(lang.translationForKey("file_name")); mFileName = (EditText) findViewById(R.id.fdEditTextFile); inputManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); getParameters(); setTitle(title); setupButtons(); // set up the list adapter String[] from = new String[] { ITEM_FILENAME, ITEM_IMAGE }; int[] to = new int[] { R.id.fdrowtext, R.id.fdrowimage }; listItemsAdapter = new SimpleAdapter(this, listItems, R.layout.file_dialog_row, from, to); setListAdapter(listItemsAdapter); // show contents of initial directory or root showDirectoryContents(currentPath); } /** * Set the text and OnClickListeners for the buttons of this Activity. */ private void setupButtons() { selectButton = (Button) findViewById(R.id.fdButtonSelect); selectButton.setEnabled(false); selectButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (selectedFile != null) { ArrayList<File> files = new ArrayList<File>(); files.add(selectedFile); FileDialogResult res = new FileDialogResult(files); getIntent().putExtra(RESULT, res); setResult(RESULT_CODE, getIntent()); finish(); } } }); if (FileDialogType.OPEN.equals(dialogType)) { selectButton.setText(lang.translationForKey("button.open")); } else if (FileDialogType.SAVE.equals(dialogType)) { selectButton.setText(lang.translationForKey("button.save")); } else { selectButton.setText(approveButtonText); } final Button newButton = (Button) findViewById(R.id.fdButtonNew); newButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { setCreateVisible(v); inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0); mFileName.setText(""); mFileName.requestFocus(); } }); newButton.setText(lang.translationForKey("button.new")); layoutSelect = (LinearLayout) findViewById(R.id.fdLinearLayoutSelect); layoutCreate = (LinearLayout) findViewById(R.id.fdLinearLayoutCreate); layoutCreate.setVisibility(View.GONE); final Button cancelButton = (Button) findViewById(R.id.fdButtonCancel); cancelButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { setSelectVisible(v); inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0); } }); cancelButton.setText(lang.translationForKey("button.cancel")); final Button createButton = (Button) findViewById(R.id.fdButtonCreate); createButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mFileName.getText().length() > 0) { File f = new File(currentPath.getPath() + File.separator + mFileName.getText()); ArrayList<File> files = new ArrayList<File>(); files.add(f); FileDialogResult res = new FileDialogResult(files); getIntent().putExtra(RESULT, res); setResult(RESULT_CODE, getIntent()); finish(); } } }); createButton.setText(lang.translationForKey("button.save")); } /** * Load and show the contents of the given directory. * * @param directory Directory to show the contents for */ private void showDirectoryContents(File directory) { currentPath = directory; listItems.clear(); File[] files = currentPath.listFiles(); if (files == null) { currentPath = new File(ROOT_DIRECTORY); files = currentPath.listFiles(); } try { textViewCurrentPath.setText(lang.translationForKey("location") + ": " + currentPath.getCanonicalPath()); } catch (IOException e) { logger.error("Couldn't get canonical file", e); } if (! ROOT_DIRECTORY.equals(currentPath.getAbsolutePath())) { // add items for the root and the parent directory addItem(ROOT_DIRECTORY, R.drawable.folder); addItem("../", R.drawable.folder); parentPath = currentPath.getParent(); } filterAndAddFiles(files); listItemsAdapter.notifyDataSetChanged(); } /** * Adds the given file to the list of items using the given imageId as icon. * * @param fileName name of the file * @param imageId id of the icon to use */ private void addItem(String fileName, int imageId) { HashMap<String, Object> item = new HashMap<String, Object>(); item.put(ITEM_FILENAME, fileName); item.put(ITEM_IMAGE, imageId); listItems.add(item); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { File file = new File(currentPath + File.separator + listItems.get(position).get(ITEM_FILENAME)); setSelectVisible(v); inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0); if (file.isDirectory()) { selectButton.setEnabled(false); if (file.canRead()) { showDirectoryContents(file); if (folderSelectable) { try { selectedFile = file.getCanonicalFile(); } catch (IOException e) { logger.error("Couldn't get canonical file", e); } v.setSelected(true); selectButton.setEnabled(true); } } else { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setIcon(R.drawable.openecard); builder.setTitle(lang.translationForKey("no_read_access", file.getName())); builder.setPositiveButton(lang.translationForKey("button.ok"), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // just close } }); builder.show(); } } else { try { selectedFile = file.getCanonicalFile(); } catch (IOException e) { logger.error("Couldn't get canonical file", e); } v.setSelected(true); selectButton.setEnabled(true); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Overridden to change the behavior if the user presses the BACK-key. if ((keyCode == KeyEvent.KEYCODE_BACK)) { selectButton.setEnabled(false); if (layoutCreate.getVisibility() == View.VISIBLE) { layoutCreate.setVisibility(View.GONE); layoutSelect.setVisibility(View.VISIBLE); } else { if (! currentPath.equals(ROOT_DIRECTORY)) { showDirectoryContents(new File(parentPath)); } else { return super.onKeyDown(keyCode, event); } } return true; } else { return super.onKeyDown(keyCode, event); } } /** * Alter the layout to enable the user to create a new file. */ private void setCreateVisible(View v) { layoutCreate.setVisibility(View.VISIBLE); layoutSelect.setVisibility(View.GONE); selectButton.setEnabled(false); } /** * Alter the layout to enable the user to select an existing file. */ private void setSelectVisible(View v) { layoutCreate.setVisibility(View.GONE); layoutSelect.setVisibility(View.VISIBLE); selectButton.setEnabled(false); } /** * Filters the directory contents according to the parameters and adds the remaining dirs and files to the item * list. * * @param filesn content of the directory */ private void filterAndAddFiles(File[] files) { TreeMap<String, String> dirsMap = new TreeMap<String, String>(); TreeMap<String, String> filesMap = new TreeMap<String, String>(); for (File file : files) { if (file.getName().startsWith(".") && ! showHiddenFiles) { continue; } if (file.isDirectory()) { String dirName = file.getName(); dirsMap.put(dirName, dirName); } else { String fileName = file.getName(); for (FileFilter fileFilter : fileFilters) { if (fileFilter.accept(file)) { filesMap.put(fileName, fileName); break; } } } } for (String dir : dirsMap.tailMap("").values()) { addItem(dir, R.drawable.folder); } for (String file : filesMap.tailMap("").values()) { addItem(file, R.drawable.file); } } /** * Extract the parameters from the calling intent. */ private void getParameters() { Bundle extras = getIntent().getExtras(); Serializable serializable = extras.getSerializable(AndroidFileDialog.CURRENT_DIR); if (serializable != null) { currentPath = (File) serializable; } else { currentPath = new File(ROOT_DIRECTORY); } title = extras.getString(AndroidFileDialog.TITLE); showHiddenFiles = extras.getBoolean(AndroidFileDialog.SHOW_HIDDEN_FILES, false); multiSelectionEnabled = extras.getBoolean(AndroidFileDialog.MULTI_SELECTION_ENABLED, false); folderSelectable = extras.getBoolean(AndroidFileDialog.FOLDER_SELECTABLE, false); fileFilters = (ArrayList<FileFilter>) extras.getSerializable(AndroidFileDialog.FILE_FILTERS); if (fileFilters.isEmpty()) { fileFilters.add(new AcceptAllFilesFilter()); } selectedFiles = (ArrayList<File>) extras.getSerializable(AndroidFileDialog.SELECTED_FILES); dialogType = (FileDialogType) extras.getSerializable(AndroidFileDialog.FILE_DIALOG_TYPE); approveButtonText = extras.getString(AndroidFileDialog.APPROVE_BUTTON_TEXT); } }