miércoles, 7 de marzo de 2012

Android: pasando datos entre Actividades

En muchas ocasiones al iniciar una actividad necesitamos enviar información extra. Se podría asimilar con un parámetro de una función, pero no disponemos de ellos.

Objetivo
El usuario indica la ruta de un fichero en una actividad y se pasa la ruta a la actividad siguiente.

Pasando los datos
Para poder enviar los datos a otra actividad debemos hacerlo mediante un Bundle. A grandes rasgos un  Bundle es un contenedor de tipos primitivos, y su uso es bastante sencillo.

1:  Intent player = new Intent(this, Player.class);  
2:    
3:  String path = "/sdcard/clip.avi"  
4:              
5:  Bundle bundle = new Bundle();  
6:  bundle.putString("filePath", path);  
7:    
8:  player.putExtras(bundle);  

Con un par de lineas esta todo hecho. Se crea un Bundle se le agregan todos los datos que queramos (en mi caso solo preciso un String) y finalmente se agrega el Bundle al Intent mediante putExtras.


Recibiendo los datos
Y para ir finalizando solo queda recuperar los datos desde la actividad recién iniciada.

 Bundle bundle = getIntent().getExtras();  
 String filePath = bundle.getString("filePath");  

Y colorín colorado este cuento se ha acabado.

martes, 6 de marzo de 2012

Android: Emular tarjeta SD con Eclipse

Muchas veces no tenes un dispositivo a mano para poder desplegar nuestra aplicación, por lo que tenemos que usar el emular para ir depurando. Y en alguno de esos caso necesitamos depurar el acceso a una tarjeta SD. Para poder emular una tarjeta SD hay que crear una imagen, montarla, copiar el contenido y finalmente usarla con el emulador.

Creando la imagen
El SDK de Android contiene varias herramientas una de ellas es mksdcard, de la ayuda del ejecutable podemos ver:

mksdcard: create a blank FAT32 image to be used with the Android emulator.
usage: mksdcard [-l label] <size> <file>
if <size> is a simple integer, it specifies a size in bytes
if <size> is an integer followed by 'K', it specifies a size in KiB
if <size> is an integer followed by 'M', it specifies a size in MiB
if <size> is an integer followed by 'G', it specifies a size in GiB
Minimum size is 9M. The Android emulator cannot use smaller images.
Maximum size is 1099511627264 bytes, 1073741823K, 1048575M or 1023G

Sino tenemos el SDK de android como variable de entorno nos desplazamos a android-sdk-linux/tools y ejecutamos

./mksdcard 512M droidcard

Montando la tarjeta en Linux
Una de las maneras de pasar ficheros a la tarjeta es haciendo un push mediante adb pero para mi gusto es mas fácil montar la tarjeta y copiar todo lo queramos como si fuera una carpeta mas. Para eso es necesario crear un punto de montaje para luego poder montar la tarjeta.


sudo mkdir /media/droidcard
sudo mount -o loop droidcard /media/droidcard


Nota: el nombre del fichero de la tarjeta no tiene porque coincidir con el punto de montaje.

Agregando ficheros a la tarjeta
A estas alturas ya podríamos estar copiando (como root) cosas a nuestra tarjeta sin ningún problema. Una vez terminado hay que desmontarla para poder usarla con el emulador.

sudo umount /media/droidcard

Usando la tarjeta en el emulador

En Eclipse dentro de Run configuration, vamos a la opción target, y en Additional configuration command line options agregamos el siguiente comando:


-sdcard /ruta/a/tu/tarjeta

Y listo, eso es todo.

miércoles, 1 de febrero de 2012

XAMPP + NetBeans + Symfony

Para tener Symfony funcionando al 100% con XAMPP y Netbeans hay que hacer unas pequeñas configuraciones.

Symfony
Simplemente bajar el .tar de la pagina web de symfony y descomprimirlo. En mi caso esta en
/home/alexis/programas/symfony



XAMPP
Para que el servidor sea capaz de acceder al contenido de Symfony y evitar que los archivos que no estén en la carpeta web de nuestro proyecto sean visibles hay que modificar dos ficheros de configuracion


  • /opt/lampp/etc/httpd.conf


<VirtualHost 127.0.0.1:80>
    ServerName www.nuestraapp.com.localhost
    DocumentRoot "/home/alexis/NetBeansProjects/nuestraapp/web"
    DirectoryIndex index.php
    <Directory "/home/alexis/NetBeansProjects/nuestraapp/web">
        AllowOverride All
        Allow from All
    </Directory>
    Alias /sf /home/alexis/programas/symfony/data/web/sf
    <Directory "/home/alexis/programas/symfony/data/web/sf">
        AllowOverride All
        Allow from All
    </Directory>
</VirtualHost>


  • /etc/hosts

127.0.0.1 www.nuestraapp.com.localhost



Netbeans
Hay que indicar donde esta el interprete PHP, agregar Symfony al path por defecto y indicarle a nuestro proyecto la URL del mismo.

Interprete PHP

Inclusión de Symfony en el path.

URL de nuestro proyecto












martes, 6 de diciembre de 2011

Broadcast en una LAN

Varias veces me he topado con tener que hacer un pequeño servicio de descubrimiento para localizar un servicio en una LAN. Siempre caigo en la trampa de enviar los datos a las dirección de broadcast predeterminada. Y en cada uno de los intentos el broadcast no se llevaba a cabo.

El siguiente ejemplo esta hecho para Android, pero la idea es la misma para todas las plataformas, obtener la dirección IP donde se esta ejecutando nuestra aplicación y la mascara de red, con esos datos se aplica un AND y vamos obteniendo byte a byte la dirección IP.

1:  DhcpInfo dhcp = wifi.getDhcpInfo();  
2:  int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;  
3:  byte[] ip = new byte[4];  
4:  for (int i = 0; i < 4; i++)  
5:    ip[i] = (byte) ((broadcast >> i * 8) & 0xFF);  



Otra metida de pata basten comun es usar el mismo puerto en el cliente y en el servidor, por lo que al hacer el broadcast detectamos que nos llegan datos al puerto donde estamos esperando la respuesta cuando en realidad es el mensaje que acabamos de difundir por la red.

sábado, 3 de diciembre de 2011

Permisos de acceso en hilos (.Net MF)

Trabajando para un proyecto de la universidad me toco implementar el refresco automático de la interfaz de usuario de la aplicación. Básicamente era llamar a un método que recogiera las medidas de los diferentes sensores conectados a una placa Tahoe II y actualizar los valores en pantalla. Hasta ahí todo bien, una tarea que a priori no debería llevar mucho tiempo.

Lo raro era que cuando la obtención de datos se hacia solo una vez funcionaba todo correctamente, pero al introducir el Timer para realizar la actualización cada 10 segundos, empezó a generarse el error InvalidOperationException. Mi primera reacción fue alguna condición de carrera estaba jodiendo todo, pero al mirar bien la documentación me di cuenta que no era eso. Sino que desde el Timer no se tenían los permisos de acceso adecuados para llamar a un objeto de otro Thread, en este caso el hilo principal.

Resulta que usar un Thread o un Timer fue una mala elección, en su lugar la mejor opcion es usar la clase DispatcherTimer, en la que los permisos de acceso son totalmente transparentes para el programador. Y todo el problema se reduce a las siguientes lineas

1:  refreshTimer = new DispatcherTimer(currentView.Dispatcher);  
2:  refreshTimer.Interval = new TimeSpan(0, 0, periodTime);  
3:  refreshTimer.Tick +=new EventHandler(refreshRoutine);  
4:  refreshTimer.Start();  

En este caso currentView es el objeto al que queremos acceder, y refreshRoutine es el método que queremos ejecutar para actualizar la pantalla.

martes, 8 de noviembre de 2011

Introducción a DPWS

El estándar DPWS es el acrónimo de Devices Profile for Web Services, define las funcionalidades mínimas para garantizar :
  • comunicación bidireccional y de manera segura con un servicio web
  • descubrimiento dinámico de un servicio web
  • descripción de un servicio web
  • suscribirse y recibir eventos de un servicio web.
Como podemos ver en la figura 1, un dispositivo (terminal que brinda servicios) podrá albergar mas de un servicio web, y podrá manejar múltiples conexiones con diferentes clientes.

Figura 1: clientes y dispositivos.
La comunicación se hace a través de mensaje. Siempre contienen un mensaje SOAP y generalmente transportan encabezados HTTP, TCP y de IP.

Descubrimiento
El descubrimiento es el mecanismo por el que el cliente es capaz de detectar un servicio que se encuentre en su propia red. Sin embargo si el cliente y el servicio estén en redes distintas, la comunicación sera posible siempre y cuando el cliente tenga una IP y un puerto al que enviar la petición.

Los mensajes Hello, Bye, Probe y Resolve, son los que definen y hacen posible el servicio de descubrimiento. Cuando un dispositivo que brinda un servicio se conecta a la red, envía un mensaje Hello, notificando al resto de equipos de la red que esta brindando un servicio. Por otra parte si el cliente no sabe a quien acudir para hacer uso de un servicio, enviara un mensaje Probe (o Resolve en caso de estar en redes distintas). Y por ultimo si el dispositivo deja la red enviara un mensaje Bye, para que el resto se enteren de su marcha.

Los servicios se agrupan en dispositivos para evitar la saturación de redes con capacidad limitada. Por ejemplo si un dispositivo tiene 15 servicios, se enviara un solo mensaje Hello a la red anunciando que el dispositivo tiene dichos servicios, en lugar de enviar 15 mensajes, uno para cada servicio.

Descripción
Cada dispositivo tiene la habilidad de describirse a si mismo, en otras palabras, sabe que servicios brinda y es capaz de comunicárselo a los clientes.

Cuando un cliente envía la petición WS-Transfer Get SOAP ENVELOPE a un dispositivo obtendrá una respuesta con la siguiente información:
  •  Modelo (modelo, numero de modelo, fabricante, etc)
  • Dispositivo (firmware, numero de serie, etc)
  • Servicios (tipo, dirección, etc)
Los servicios también tiene la habilidad de describirse, esto podemos hacerlo una vez que sepamos los datos del dispositivo. Para saber que funcionalidades brinda un servicio lo hacemos con GetMetadata.

Eventos
Como cualquier lenguaje orientado a objetos, el DPWS nos brinda la posibilidad de sincronizar los clientes y los dispositivos mediante eventos. Los eventos son lanzados por los dispositivos y los clientes que estén suscritos podrán manejar los eventos y realizar las acciones que sean necesarias. Si por algún casual lo que nos interesa es suscribirnos a un tipo determinado de eventos, se pueden aplicar filtrados para conseguirlo.

Seguridad
El estándar no especifica una política de seguridad especifica sino que da un serie de pautas a seguir. Se recomienda:
  • firma: para validar la información de los mensajes enviados sin encriptar
  • canal seguro: comunicación punto a punto a través de TLS/SSL
  • certificado: credencial usada por un cliente o dispositivo para autentificarse
Para la próxima un ejemplo de como se crea y configura todo esto con .Net Micro Framework.

jueves, 3 de noviembre de 2011

Primeros pasos con Android

Se podría decir que en toda aplicación Android (con interfaz gráfica) tendremos tres elementos básicos: Views, Layouts y Events.

Los objetos de tipo View son todos aquellos que el usuario puede ver, es decir, texto, imágenes o botones por nombrar algunos. Los layouts nos brindaran la infraestructura necesaria para poder organizar como queremos mostrar los diferentes objetos de tipo View en la pantalla de nuestro Android. Y por ultimo los Events, son los encargados de capturar las acciones realizadas por el usuario y llevar a cabo alguna acción, por ejemplo al tocar un botón emitir un sonido.

A esto es a lo que queremos llegar:

Imagen usada de fondo fue obtenida de 140geek

Nuestro hola mundo, contiene una imagen sobre la cual se escribe el mensaje "¡Hola Mundo!" y en la parte inferior tenemos la leyenda "Tocar la pantalla para salir.".

Cuando generemos el proyecto con Eclipse o Motodev (un eclipse tuneado para desarrollar en Android), únicamente tendremos el método onCreate (nuestro "main")

1:  public class HelloWorld extends Activity {  
2:    /** Called when the activity is first created. */  
3:    @Override  
4:    public void onCreate(Bundle savedInstanceState) {  
5:      super.onCreate(savedInstanceState);  
6:    }  
7:  }  

A excepción del ultimo fragmento de código y del fichero xml, todos los fragmentos siguientes deben ir dentro del método onCreate.

Para mostrar texto en pantalla, tenemos que usar objetos de tipo TextView. En las lineas 2 y 8 obtenemos el texto con id hello y msgExit respectivamente desde el gestor de recursos. Sino queremos usar el gestor de recursos y poner una cadena de texto normal entre comillas también es valido.

1:  TextView tvHello = new TextView(this);  
2:  tvHello.setText(R.string.hello);     //obtenemos el string con id hello
3:  tvHello.setGravity(Gravity.CENTER);  //centramos el texto en la pantalla
4:  tvHello.setTextColor(Color.BLACK);   //cambiamos el color de la fuente
5:  tvHello.setTextSize(20);             //cambiamos el tamaño de la fuente
6:    
7:  TextView tvExit = new TextView(this);  
8:  tvExit.setText(R.string.msgExit);  
9:  tvExit.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);  
10:  tvExit.setTextColor(Color.BLACK);  




En el explorador de paquetes, nos encontramos con la carpeta res, donde estarán los recursos contenidos en el gestor de recursos. Si queremos agregar alguna imagen basta con copiarla a alguna de las carpetas drawable y el identificador sera el nombre del fichero. En cambio para agregar cadenas de texto, tenemos que modificar el fichero strings.xml



1:  <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
2:  <resources>  
3:    <string name="hello">¡Hola Mundo!</string>  
4:    <string name="app_name">Hola Mundo</string>  
5:    <string name="title">/dev/kmem - Hola Mundo</string>  
6:    <string name="msgExit">Tocar la pantalla para salir.</string>  
7:  </resources>  

Para no distorsionar la imagen es mejor usa un ImageView en lugar de la propiedad Background de los Layouts, porque esta ultima estrecha o estira la imagen sin respetar las proporciones.

1:  ImageView ivAndroid = new ImageView(this);  
2:  ivAndroid.setImageDrawable(getResources().getDrawable(R.drawable.android));  

Ya que tenemos creados los tres objetos que queremos mostrar al usuario, ahora tenemos que crear un layout , agregar los elementos y establecer como contenido principal el layout. Como la imagen no ocupa toda la pantalla y para evitar que queden franjas negras por encima y por debajo, cambiamos el color de fondo del layout al mismo que el de la imagen.

1:  FrameLayout layout = new FrameLayout (this);  
2:  layout.setBackgroundColor(Color.WHITE);  
3:  layout.addView(ivAndroid);  
4:  layout.addView(tvHello);  
5:  layout.addView(tvExit);  
6:    
7:  setContentView(layout);  

Y por ultimo, onTouchEvent se activa cuando el usuario toca la pantalla, y el método finish termina la ejecución del programa, por lo que cuando el usuario toque la pantalla se cerrara la aplicación.

1:    @Override  
2:    public boolean onTouchEvent(MotionEvent ev)  
3:    {  
4:        this.finish();  
5:        return true;  
6:    }  

Y con eso, tenemos nuestra primera aplicación en Android.