Programación

Truco Android: como hacer que tus aplicaciones aparezcan en el Market para los HTC Tattoo

Desde Android 1.6 se introdujeron nuevos tamaños de pantalla como la QVGA del Tattoo (240 x 320). Muchas aplicaciones no se ven bien a esta resolución (el tamaño normal es HVGA de 320 x 480) , por eso debemos indicar específicamente en el AndroidManifest.xml las resoluciones que soporta nuestra aplicación.

<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="4" />
<supports-screens android:smallScreens="true" android:largeScreens="true" android:normalScreens="true"/>

La primera línea indica que desarrollamos para Android 1.6, pero que damos soporte a la 1.5 (cuanta más gente la use mejor)

La segunda, indica las resoluciones que soportamos. Asegúrate de probarlas todas en el emulador antes de subirla al Market.

Tienes la explicación completa en la esta guía.

Jugando con Java y el API de Twitter

Twitter tiene un API muy completa que nos permite interactuar con su servicio desde nuestras aplicaciones. Esta tarde he estado enredando un poco con ella y la verdad es que se me ocurren un montón de aplicaciones prácticas(logueos, análisis automáticos, integración en servicios de noticias, estadísticas, seguimiento de usuarios, actualizaciones automáticas del perfil, etc…)

Existen librerías en un montón de lenguajes que facilitan aún mas su uso. Pero en este caso yo he preferido programar un servicio desde cero (lo cual, gracias a la documentación del API no ha sido nada complicado).

El siguiente ejemplo es una aproximación sencilla que permite actualizar nuestro estado (enviar un post) desde aplicación Java.

/*
 *   http://creativecommons.org/licenses/by-nc/3.0/deed.es
 */

package org.francho.java.twitter;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
// http://commons.apache.org/codec/
import org.apache.commons.codec.binary.Base64;

/**
 *
 * @author francho - http://francho.org/lab/
 */
public class Twitter {

    private String username;
    private String pass;
    private String response;

    Twitter(String username, String pass) {
        setCredentials(username, pass);
    }

    /**
     * Ejemplo de acción implementada.
     *
     * Actualiza el estado de Twitter con el texto que recibe
     *
     * @param status
     */
    public void statusesUpdate(String status) {
        try {
            URL url = new URL("http://twitter.com/statuses/update.xml");
            status = URLEncoder.encode(status, "UTF-8");
            String parametros = "status=" + status;
            doTwitterRequest(url, parametros);
        } catch (MalformedURLException ex) {
            Logger.getLogger(Twitter.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(Twitter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Se encarga de la conexión con Twitter.
     * Necesita tener precargada los datos de autentificación (constructor), la url y los parámetros
     */
    private void doTwitterRequest(URL url, String parametros) {
        response = "";
        try {
            // Creamos una conexión
            URLConnection conn;
            conn = url.openConnection();
            conn.setAllowUserInteraction(false);
            conn.setDoOutput(true);

            // Configuramos la autentificación (sencilla basada en HTTP)
            conn.setRequestProperty("Authorization", "Basic " + getBasicCredentials());

            // Preparamos la conexión con el servidor (vamos a mandar un formulario por post)
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            // Abrimos el canal de comunicación de envío
            DataOutputStream out = new DataOutputStream(conn.getOutputStream());
            // Mandamos los parámetros de la acción que (los ha tenido que precargar el método correspondiente)
            out.writeBytes(parametros.toString());
            // Nos aseguramos de que todo se envíe
            out.flush();
            // Ya hemos dicho lo que teníamos que decir, así que cerramos la conexión de envio
            out.close();

            // Capturamos la respuesta
            BufferedReader input = new BufferedReader(new InputStreamReader(conn.getInputStream()));

            String l = "";
            while ((l = input.readLine()) != null) {
                response += l + "\n";
            }

        } catch (IOException ex) {
            Logger.getLogger(Twitter.class.getName()).log(Level.SEVERE, null, ex);

        }

    }

    public void setCredentials(String username, String pass) {
        this.username = username;
        this.pass = pass;
    }

    public String getBasicCredentials() {
        byte[] credentialsBytes = (username + ":" + pass).getBytes();
        byte[] encodedBytes = Base64.encodeBase64(credentialsBytes);
        return new String(encodedBytes);
    }

    public String getResponse() {
        return response;
    }
}

Este sería un ejemplo de uso de nuestra clase:

/*
 *   http://creativecommons.org/licenses/by-nc/3.0/deed.es
 */

package org.francho.java.twitter;

import java.util.Date;

/**
 *
 * @author francho - http://francho.org/lab/
 */
public class Test {
    public static void main(String[] args) {
        Twitter twitter = new Twitter("yoEnTwitter", "miclave");

        Date ahora = new Date();

        twitter.statusesUpdate("Jugando con Java y el API de Twitter " + ahora);
        System.out.println(twitter.getResponse());
    }
}

Java: Ejemplo de uso de tipos enumerados (enum)

Los tipos enumerados sirven para restringir el contenido de una variable a una serie de valores predefinidos. Esto suele ayudar a reducir los errores en nuestro código.

A partir de Java SE 5.0 se incluyo una modalidad de tipos enumerados que mantiene la seguridad de los tipos. En la práctica viene a ser como si definiéramos nuestros propios tipos de variables.

En Java, los tipos enumerados se pueden definir fuera o dentro de una clase. Otra ventaja que traen los tipos enum de Java es que al ser una “especie de clase” podemos añadirles métodos, variables de instancia, constructores, etc… lo que los hace muy potentes.

A continuación os dejo un pequeño ejemplo que ilustra todos estos conceptos.

/*
 *   http://creativecommons.org/licenses/by-nc/3.0/deed.es
 */
package org.francho.java.ejemplos;

/*
 *
 * @author francho - http://francho.org/lab/
 */

/*
 * Un tipo enumerado "complejo", tiene sus propios métodos y constructor
 */

enum Vaso {
    // Tipos de vaso disponibles. Pasan al constructor su capacidad en cc.
    JARRA(500), TUBO(250), TERCIO(333), CAÑA(200);

    private int cc; // Variable interna donde almacenaremos la capacidad

    // Nuestro constructor nos fuerza a pasar parámetros al definir un nuevo tipo
    Vaso(int cc) {
        this.cc = cc;
    }

    // Devuelve la capacidad del vaso
    public int getCentimetrosCubicos() {
        return cc;
    }
}

/*
 * Definimos un tipo de bebida
 */

class BebidaCerveza {
    enum MarcaCerveza { AMBAR, GUINNESS, HEINEKEN } // Tipos enumerados sencillos. Solo tenemos estas marcas

    private Vaso vaso;
    private MarcaCerveza marca;

    BebidaCerveza(MarcaCerveza marca, Vaso vaso) {
        this.marca = marca;
        this.vaso = vaso;
    }

    public void servir() {
        System.out.println("Sirviendo " + vaso.getCentimetrosCubicos() + "cc. de cerveza " + marca);
    }
}

/*
 * Clase pública que prueba todo esto
 */

public class PruebaEnum {
    public static void main(String[] args) {
        BebidaCerveza birra = new BebidaCerveza(BebidaCerveza.MarcaCerveza.AMBAR, Vaso.JARRA);

        birra.servir();
    }
}

Android: Datos de configuración APN para Orange España

Tras liberar mi móvil Android (un HTC Dream de Movistar) he tenido que configurar a mano los APN (nombre de punto de acceso) para poder aprovechar la tarifa plana de datos que tengo con Orange y para poder enviar y recibir mensajes MMS.

Estos son los pasos necesarios:

Entramos en el menú “Ajustes / Conexiones inalámbricas / Redes móviles / APN”

Creamos un APN para conectar a internet por la red telefónica

Nombre: orange internet
APN: internet
Proxy: <No establecido>
Puerto: <No establecido>
Nombre de usuario: orange
Contraseña: orange
Servidor: <No establecido>
MMSC: <No establecido>
Proxy MMS: <No establecido>
Puerto MMS: <No establecido>
MCC: 214
MNC: 03
Tipo de APN: default

Creamos otro APN para poder mandar/descargar MMS

Nombre: orange MMS
APN: orangemms
Proxy: <No establecido>
Puerto: <No establecido>
Nombre de usuario: orange
Contraseña: orange
Servidor: <No establecido>
MMSC: http://mms.orange.es
Proxy MMS: 172.022.188.025
Puerto MMS: 8080
MCC: 214
MNC: 03
Tipo APN: mms

Una vez creados hay que apagar y volver a encender el móvil para que la nueva configuración funcione.

Hola mundo en Flash (Flex) desde Linux

Para un experimento que quiero hacer tengo que retocar un código hecho en Flex. Como nunca he programado Flex ni ActionScript  me ha tocado bucear en la red. Siguiendo este post y este otro, he conseguido montar el entorno de desarrollo.

Eclipse ya lo tenía instalado desde el aptitude de mi Ubuntu 9.10 así que solo he tenido que añadirle los plugins que me faltaban (AXDT).

Este es el código con el que he probado que todo funciona:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="vertical">
	<mx:Script>
<![CDATA[
         public function about():void {
              texto.text = "http://francho.org/lab/";
         }

         public function hola():void {
         	texto.text = "Hola";
         }

]]></mx:Script>
	<mx:Label id="texto">
		<mx:text>pulsa</mx:text>
	</mx:Label>
	<mx:Button id="btnHola" label="Hola" click="hola()" />
	<mx:Button id="btnAbout" label="About" click="about()" />
</mx:Application>

y esta es resultado del programa una vez compilado: MxmlHelloWorld