/* Tibisay Movil Copyright (C) 2013 Antonio Araujo (aaraujo@cenditel.gob.ve), Jose Ruiz (jruiz@cenditel.gob.ve), Fundacion Centro Nacional de Desarrollo e Investigacion en Tecnologias Libres - CENDITEL. La Fundación CENDITEL concede permiso para usar, copiar, distribuir y/o modificar este programa, reconociendo el derecho que la humanidad posee al libre acceso al conocimiento, bajo los términos de la licencia de software GPL versión 2.0 de la Free Software Foundation. Este programa se distribuye con la esperanza de que sea util, pero SIN NINGUNA GARANTIA; tampoco las implicitas garantias de MERCANTILIDAD o ADECUACION A UN PROPOSITO PARTICULAR. Para mayor información sobre los términos de la licencia ver el archivo llamado "gpl-2.0.txt" en ingles. */ package ve.gob.cenditel.tibisaymovil; import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import ve.gob.cenditel.tibisaymovil.R; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.DialogInterface.OnCancelListener; import android.content.DialogInterface.OnDismissListener; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.view.Window; import android.webkit.MimeTypeMap; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Toast; public class FilesToPDFSignActivity extends KeyChainClientActivity implements OnItemClickListener, OnClickListener { private File cwd; private List selected; private FileBrowserView viewHolder; private FileListAdapter listAdapter; private int requestCode; private int resultCode; private Intent data; private String privateKeyAlias; private String filterMImeType = "application/pdf"; @Override protected void onCreate(Bundle savedInstanceState) { //Estilando la barra de titulo final boolean customTitleSupported = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); super.onCreate(savedInstanceState); this.viewHolder = new FileBrowserView(); if (savedInstanceState != null) { this.selected = TypeUtils.convertToFileList(savedInstanceState.getStringArrayList("selected")); if (this.selected.size() > 0) { FilesToPDFSignActivity.this.updateButton (FilesToPDFSignActivity.this.viewHolder.accept,true); } this.cwd = new File(savedInstanceState.getString("cwd")); this.viewHolder.fileList.setAdapter(this.listAdapter = new FileListAdapter(this.cwd.getAbsolutePath(), filterMImeType)); } else { this.selected = new ArrayList(); this.viewHolder.fileList.setAdapter(this.listAdapter = new FileListAdapter()); } boolean enabled = false; if (!this.selected.isEmpty()) enabled = this.viewHolder.accept.isEnabled(); FilesToPDFSignActivity.this.updateButton(FilesToPDFSignActivity.this.viewHolder.accept,enabled); FilesToPDFSignActivity.this.updateButton (FilesToPDFSignActivity.this.viewHolder.accept,enabled); //Estilando Barra de titulo if(customTitleSupported) getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.title_bar); //Obtiene o crea un instancia de en keyChain y le asigna la actividad que lo genera KeyChainStrategy.getInstance().setClientActivity(this); } /** * Provides the data to be shown in the file browser ListView. * * @author José M. Prieto (jmprieto@emergya.com) */ private class FileListAdapter extends BaseAdapter { private final ArrayList directories; private final ArrayList files; private FileListAdapter() { this("/",filterMImeType); } private FileListAdapter(String location) { this(location, ""); } private FileListAdapter(String location, String filterMimeType) { directories = new ArrayList(); files = new ArrayList(); //Obtiene etiqueta que se colocará antes del path que visualizará el usuario String toPathText = FilesToPDFSignActivity.this.getString(R.string.pathstring)+": "; //Coloca el texto de la etiqueta en la vista FilesToPDFSignActivity.this.viewHolder.pathString.setText(toPathText); //Coloca el texto con el path actual FilesToPDFSignActivity.this.viewHolder.path.setText(location); //Crea un objeto file cwd con la ubicacion dada en location FilesToPDFSignActivity.this.cwd = new File(location); //Obtiene el directorio padre del objeto file cwd File parent = FilesToPDFSignActivity.this.cwd.getParentFile(); //Si tiene un padre, lo agrega en la posición cero de la lista de directorios if (parent != null) { directories.add(0, parent); } //Crea un arreglo con las lista de archivos contenidos en el directorio cwd File[] ls = FilesToPDFSignActivity.this.cwd.listFiles(); if (ls != null) { for (File f : ls) { //recorre todos los archivos contenidos en el directorio if (FsUtils.isHiddenOrNotReadable(f)) { // Si son ocultos no hace nada continue; } // Si son directorios los agrega a la lista de directorios a partir de la posición 1 // En la posición 0 se encuentra el directorio padre if (f.isDirectory()) { directories.add(f); } else // De lo contrario lo agrega a la lista de archivos { //Valida tipo de archivo a mostrar Uri selectedUri = Uri.fromFile(f); String fileExtension = MimeTypeMap.getFileExtensionFromUrl(selectedUri.toString()); String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension); // Toast.makeText(FileToSignHandwrittenSignatureActivity.this, // "FileExtension: " + fileExtension + "\n" + // "MimeType: " + mimeType, // Toast.LENGTH_LONG).show(); //Filtra por mimeType if(filterMimeType.isEmpty() || filterMimeType == mimeType) files.add(f); } } } Collections.sort(directories); // Ordena los directorios alfabeticamente Collections.sort(files); // Ordena los archivos alfabeticamente } /** * Retorna cantidad total de elementos que se listarán en el directorio. */ @Override public int getCount() { return directories.size() + files.size(); } /** * Dada una posición en el listado del directorio, retorna un archivo o directorio * según corresponda. */ @Override public File getItem(int position) { if (position < directories.size()) { return directories.get(position); } else { return files.get(position - directories.size()); } } /** * Retorna un código hash para el archivo, permite comparar si dos archivos son los mismos */ @Override public long getItemId(int position) { return getItem(position).hashCode(); } /** * Crea la visualización de cada item del fileBrowser */ @Override public View getView(int position, View convertView, ViewGroup parent) { //Crea la vista de cada fila del filebrowser a partir del layout if (convertView == null) { LayoutInflater inflater = LayoutInflater.from(FilesToPDFSignActivity.this); convertView = inflater.inflate(R.layout.files_to_pdf_sign_item, parent, false); } // Se enlaza a cada componente del layout ImageView image = (ImageView) convertView.findViewById(R.id.type_image); TextView fileName = (TextView) convertView.findViewById(R.id.filename_text); TextView modified = (TextView) convertView.findViewById(R.id.filename_modified); // Se obtiene el archivo ubicado en position File file = getItem(position); //RadioButton CheckBox check = (CheckBox) convertView.findViewById(R.id.file_check); check.setFocusable(false); // Se asignan los iconos según el tipo de archivo y se oculta el radio en los directorios if (file.isDirectory()) { image.setImageResource(R.drawable.ic_carpeta_verde); check.setVisibility(View.INVISIBLE); check.setChecked(false); } else { image.setImageResource(R.drawable.ic_archivo_verde); check.setVisibility(View.VISIBLE); if (!FilesToPDFSignActivity.this.selected.contains(file)){ check.setChecked(false); } else{ check.setChecked(true); } } // Si es el directorio que hace referencia al padre le coloca como nombre ".." if (file.isDirectory() && position == 0 && ! "/".equals(FilesToPDFSignActivity.this.cwd.getAbsolutePath())) { fileName.setText(".."); } else { fileName.setText(file.getName()); } //Datos de modificación del archivo SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); Date date = new Date(file.lastModified()); String dateString = FilesToPDFSignActivity.this.getString(R.string.modified)+": "; if (file.lastModified()>0) modified.setText(dateString+sdf.format(date)); else modified.setText(dateString+"-"); return convertView; } /** * Controla la selección de cada item del fileBrowser */ public void select(ListView parent, int position) { File item = getItem(position); //Si es un directorio el seleccionado se hace un llamado del fileBrowser del directorio if (item.isDirectory()) { parent.setAdapter(FilesToPDFSignActivity.this.listAdapter = new FileListAdapter(item.getAbsolutePath(), filterMImeType)); } else { // Si es un archivo //Se agrega el archivo a la lista de seleccionados si no se encuentra en la misma if (!FilesToPDFSignActivity.this.selected.contains(item)){ FilesToPDFSignActivity.this.selected.add(item); FilesToPDFSignActivity.this.updateButton(FilesToPDFSignActivity.this.viewHolder.accept,true); } else{ // De lo contrario se elimina de la lista de seleccionados FilesToPDFSignActivity.this.selected.remove(item); if (FilesToPDFSignActivity.this.selected.isEmpty()){ FilesToPDFSignActivity.this.updateButton(FilesToPDFSignActivity.this.viewHolder.accept,false); }else { FilesToPDFSignActivity.this.updateButton(FilesToPDFSignActivity.this.viewHolder.accept,true); } } notifyDataSetChanged(); } } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable("intent", this.getIntent()); outState.putString("cwd", this.cwd.getAbsolutePath()); outState.putStringArrayList("selected", TypeUtils.convertToStringArrayList(this.selected)); outState.putParcelable("intent", this.data); outState.putInt("requestCode", this.requestCode); outState.putInt("resultCode", this.resultCode); } private void updateButton(View v, boolean bool) { try{ v.setEnabled(bool); if (v instanceof TextView){ Drawable icon = ((TextView)v).getCompoundDrawables()[1]; if (icon!=null) if (bool) icon.setAlpha(255); else icon.setAlpha(127); } if (v instanceof ImageView){ ImageView result = (ImageView) v; if (bool) result.setAlpha(255); else result.setAlpha(127); } }catch(NullPointerException e){} } private void updateButton(LinearLayout layout, boolean bool) { try{ layout.setEnabled(bool); for (int i=0; i parent, View view, int position, long id) { if (parent.getId() == R.id.file_list) { // user selects a file this.listAdapter.select((ListView) parent, position); } else { // user de-selects a file //this.listAdapter.addIfSameDirectory(selectedAdapter.doUnselect((ListView) parent, position)); } //this.viewHolder.numSelected.setText(Integer.toString(this.selected.size())); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button_clear_zone: this.selected.clear(); this.listAdapter.notifyDataSetChanged(); //this.viewHolder.numSelected.setText(""+this.selected.size()); this.updateButton(this.viewHolder.accept, false); break; case R.id.button_accept_zone: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH || this.getFileStreamPath(DirectKeyChain.keyStoreFilename).exists()){ Intent intent = new Intent(this, FilesToPDFSignConfirmationActivity.class); intent.putStringArrayListExtra(IntentExtraField.FILES, TypeUtils.convertToStringArrayList(this.selected)); startActivityForResult(intent, ActivityResult.FILES_CONFIRMATED); }else{ this.createNoKeyStoreDialog(); } break; } } private void createNoKeyStoreDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setCancelable(false); builder.setMessage(R.string.error_keystore_file); builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); } }); AlertDialog dialog = builder.create(); dialog.show(); } @Override protected void onActivityResult(int requestCode, int resultCode, final Intent data) { //Toast.makeText(this, "result", Toast.LENGTH_LONG).show(); this.requestCode = requestCode; this.resultCode = resultCode; this.data=data; //Toast.makeText(this, "request_code="+this.requestCode+" result="+this.resultCode, Toast.LENGTH_LONG).show(); if (resultCode == RESULT_CANCELED && requestCode!=ActivityResult.FILES_CONFIRMATED && requestCode!=ActivityResult.IMPORT_CERTIFICATE) { //Removed to fix task error #73085 /*setResult(RESULT_CANCELED); finish(); return; */ if (this.selected.size()>0){ Intent intent = new Intent(this, FilesToPKCS7SignConfirmationActivity.class); intent.putStringArrayListExtra(IntentExtraField.FILES, TypeUtils.convertToStringArrayList(this.selected)); startActivityForResult(intent, ActivityResult.FILES_CONFIRMATED); } } switch (requestCode) { case ActivityResult.CHECK_CERTIFICATE_VALIDITY: if (resultCode == RESULT_OK) { //Toast.makeText(FilesToPDFSignActivity.this, "aqui", Toast.LENGTH_LONG).show(); boolean embedSignature = data.getBooleanExtra(IntentExtraField.EMBED_SIGNATURE_IN_PDF, false); Intent intent = new Intent(this, SignActivity.class); intent.putExtra(IntentExtraField.EMBED_SIGNATURE_IN_PDF, embedSignature); intent.putExtra(IntentExtraField.ALIAS, this.privateKeyAlias); intent.putParcelableArrayListExtra(IntentExtraField.FILES, TypeUtils.convertToUriArrayList(this.selected)); startActivity(intent); //Finish only in this branch to fix error #73085 finish(); } break; case ActivityResult.FILES_CONFIRMATED: if (resultCode == RESULT_OK){ this.selected.clear(); List paths = data.getStringArrayListExtra(IntentExtraField.FILES); for (String s: paths) this.selected.add(new File(s)); this.listAdapter.notifyDataSetChanged(); KeyChainStrategy.getInstance().choosePrivateKeyAlias(); } break; } // if (requestCode == ActivityResult.IMPORT_CERTIFICATE && resultCode == Activity.RESULT_OK) { // //this.launchPasswordDialog(data); // } } private void launchPasswordDialog(final Intent data) { //TODO: Setting boolean to false instead of true. Disables "New KeyStore" option. final PasswordDialog dialog = new PasswordDialog(this, R.string.certificate_password, false); dialog.setAcceptListener(new OnClickListener() { @Override public void onClick(View v) { try { DirectKeyChain direct = DirectKeyChain.getInstance(); int imported = direct.importCertificate(data.getData(), dialog.getPassword()); String text = FilesToPDFSignActivity.this.getResources().getQuantityString(R.plurals.number_imported_certificates, imported, imported); Toast.makeText(FilesToPDFSignActivity.this, text, Toast.LENGTH_LONG).show(); direct.saveKeystore(); direct.refreshAdapter(); } catch (IncorrectPasswordException e) { Toast toast = Toast.makeText(FilesToPDFSignActivity.this, R.string.incorrect_password, Toast.LENGTH_LONG); toast.show(); } catch (Exception e) { Toast toast = Toast.makeText(FilesToPDFSignActivity.this, R.string.error_reading_p12, Toast.LENGTH_LONG); toast.show(); } dialog.dismiss(); FilesToPDFSignActivity.this.requestCode=Integer.MIN_VALUE; FilesToPDFSignActivity.this.resultCode=Integer.MIN_VALUE; FilesToPDFSignActivity.this.data=null; } }); //TODO: dialog.setOnDismissListener(new OnDismissListener(){ @Override public void onDismiss(DialogInterface arg0) { FilesToPDFSignActivity.this.data=null; FilesToPDFSignActivity.this.requestCode=Integer.MIN_VALUE; FilesToPDFSignActivity.this.resultCode=Integer.MIN_VALUE; }}); dialog.setOnCancelListener(new OnCancelListener(){ @Override public void onCancel(DialogInterface dialog) { FilesToPDFSignActivity.this.data=null; FilesToPDFSignActivity.this.requestCode=Integer.MIN_VALUE; FilesToPDFSignActivity.this.resultCode=Integer.MIN_VALUE; }}); dialog.show(); } @Override public void setAlias(String alias) { if (alias == null) { Toast.makeText(CustomKeyChain.activity, "alias null", Toast.LENGTH_LONG).show(); finish(); return; } // Toast.makeText(this, "setAlias="+alias, Toast.LENGTH_LONG).show(); this.privateKeyAlias = alias; Intent intent = new Intent(this, CertValidatorActivity.class); intent.putExtra(IntentExtraField.ALIAS, alias); intent.putExtra(IntentExtraField.EMBED_SIGNATURE_IN_PDF, true); intent.putParcelableArrayListExtra(IntentExtraField.FILES, TypeUtils.convertToUriArrayList(this.selected)); startActivityForResult(intent, ActivityResult.CHECK_CERTIFICATE_VALIDITY); } }