JSR-179 Location API para J2ME: Posicionamiento geográfico en nuestras aplicaciones.

17
31082

JSR-179 Location API para J2ME: Posicionamiento geográfico en nuestras aplicaciones (GPS)

Introducción.

En este tutorial vamos a hacer una introducción teórico/práctica al API definido por la Location API JSR 179 (para terminales móviles) mediante el cual
podremos realizar aplicaciones con funcionalidad relacionada con la posición geográfica del dispositivo.

Posteriormente, después de hacer una introducción sobre las características más importantes de la misma, realizaremos una aplicación que podremos instalar
en nuestro dispositivo móvil que nos ofrecerá nuestra posición geográfica así como la velicidad a la que nos movemos y la distancia que vamos recorriendo
.

Antes de proseguir decir que para poder obtener la posición de un dispositivo móvil, este no tiene por que tener GPS, existen otrás tecnologías o servicios para conseguirlo.
Por ejemplo,
las operadoras pueden ofrecer este servicio previo pago: Este API te abstrae del método y es válido para todos.

Otra información interesante:

Características funcionales

  • A través de la clase LocationProvider el usuario puede obtener la posición geográfica del terminal (objetos Location que contienen las coordenadas geográficas Coordinates).
  • Los objetos Location contienen las coordenadas representadas como longitud, latitud y opcionalmente otros datos como la altitud, la calle, el país, la ciudad, etc. (objetos AddressInfo).
  • El usuario puede registrar en LocationProvider una o varias clases que implementen la interfaz LocationListener para ser notificados cuando la posición geográfica del terminal cambie.
  • El usuario puede conocer la orientación del terminal respecto al norte, clase Orientation.
  • El usuario puede registrar en LocationProvider una o varias clases que implementen la interfaz ProximityListener para ser notificados cuando la posición geográfica del terminal se acerque a una determinada posición que especificaquemos.
  • El usuario puede leer, escribir, crear y eliminar posiciones geográficas Coordinates asociadas a un nombre LandMark y clasificarlos en categorías (colegios, restaurantes, etc)
  • El usuario puede saber la velocidad de desplazamiento del terminal Location.getSpeed()

Aspectos de seguridad:

Los siguientes permisos están realizacionados con la localización (sólo es necesario especificar el primero de ellos para la aplicación de ejemplo que veremos a continuación)

  1. javax.microedition.localizacion.Location
  2. javax.microedition.localizacion.Orientation
  3. javax.microedition.localizacion.ProximityListener
  4. javax.microedition.localizacion.LandmarkStore.management
  5. javax.microedition.localizacion.LandmarkStore.read
  6. javax.microedition.localizacion.LandmarkStore.write
  7. javax.microedition.localizacion.LandmarkStore.category

Un ejemplo

Ampliar imagen

Ampliar imagen

Como complemento teórico de lo expuesto anteriormente vamos a realizar una pequeña aplicación autocomentada que nos proporcione la siguiente información cada 5 segundos:

  1. Estado actual del proveedor de localización (Disponible, fuera de servicio, etc).
  2. Distancia recorrida (en metros) desde que se inicio la aplicación.
  3. La velocidad (en metros/segundo) a la que nos desplazamos.
  4. Nombre de la calle actual en la que nos encontramos.
  5. Longitud y latitud en la que nos encontramos.

A continuación os dejo el código fuente para que realices tus pruebas. Código fuente del proyecto (Netbeans).

 

Aunque no todas las implementaciones devuelven información textual sobre la posición geográfica (calle xxxxxxx, nº xxx, ciudad: xxxx, …). Gracias a otras herramientas como Google Maps es posible obtener esta información a partir de la latitud y longitud (las implementaciones están obligadas a proporcionarnos).

Observe la imagen de la derecha para ver como conseguirlo.

La clase principal de la aplicación (MIDlet):

package com.autentia.tutoriales.jsr179;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

/**
 * MIDlet en donde se muestra la siguiente información:
 *      a) Estado actual del proveedor de localización (Disponible, fuera de servicio, etc).
 *      b) Distancia recorrida (en metros) desde que se inicio la aplicación.
 *      c) La velocidad (en metros/segundo) a la que nos desplazamos. 
 *      d) Nombre de la calle actual en la que nos encontramos.
 *      e) Longitud y latitud en la que nos encontramos.
 * @author Carlos García. Autentia
 */
public class LocationMidlet extends MIDlet {

    private Form main;

    public void startApp() {
        if (main == null){
            // ¿Está el API de localización disponible?
            if (System.getProperty("microedition.location.version") != null) {
                main = new LocationMainForm(this);
            } else {
                main = new Form("Location API");
                main.append("El API de localización no está disponible");
            }
        }

        Display.getDisplay(this).setCurrent(main);
    }

    public void pauseApp() {
        // Nada que hacer
    }

    public void destroyApp(boolean unconditional) {
        this.notifyDestroyed();
    }
}
    

Ventana principal de la aplicación

package com.autentia.tutoriales.jsr179;

import javax.microedition.lcdui.*;
import javax.microedition.location.*;
import javax.microedition.midlet.MIDlet;

/**
 * Ventana principal de la aplicación
 * @author Carlos García. Autentia.
 */
public class LocationMainForm extends Form implements CommandListener,  LocationListener {

    // Distancia total recorrida actualmente
    private double totalCurrentDistance;
    private MIDlet midlet;

    // Coordenadas de la última posición consultada
    private QualifiedCoordinates lastCoord;

    // Controles del interfaz gráfico
    private Command   cmdStartClick;
    private Command   cmdExitClick;

    private TextField txtEstadoProveedor;
    private TextField txtLongitud;
    private TextField txtLatitud;
    private TextField txtDistanciaRecorrida;
    private TextField txtVelocidad;
    private TextField txtCalle;


    public LocationMainForm(MIDlet    midlet){
        super("Location API Ejemplo");

        this.totalCurrentDistance = 0;
        this.midlet               = midlet;

        this.createUI();
    }

    /**
     *  Contruimos y configuramos el interfaz gráfico
     */
    private void createUI(){
        this.cmdStartClick = new Command("Empezar", Command.OK,   1);
        this.cmdExitClick  = new Command("Salir",   Command.EXIT, 1);

        this.txtCalle      = new TextField("Calle:",           null, 50,  TextField.ANY);
        this.txtEstadoProveedor     = new TextField("Proveedor:",       null, 50,  TextField.ANY);
        this.txtDistanciaRecorrida  = new TextField("Metros recorridos:", null, 50,   TextField.ANY);
        this.txtVelocidad  = new TextField("Velocidad:", null, 20,   TextField.ANY);
        this.txtLongitud   = new TextField("Longitud:",        null, 50,   TextField.ANY);
        this.txtLatitud    = new TextField("Latitud:",         null, 50,   TextField.ANY);

        this.append(txtEstadoProveedor);
        this.append(txtDistanciaRecorrida);
        this.append(txtVelocidad);
        this.append(txtCalle);
        this.append(txtLongitud);
        this.append(txtLatitud);

        this.addCommand(cmdStartClick);
        this.addCommand(cmdExitClick);
        this.setCommandListener(this);
    }

    /**
     * Configuramos e iniciamos el proveedor de localización
     */
    private void cmdStartClick_click() throws LocationException   {
        // Establecemos los criterios del proveedor de localizacion deseado.
        Criteria criteria = new Criteria();

        // No queremos usar un proveedor de pago
        criteria.setCostAllowed(false);

        // Nos gustaría que el proveedor además de longitud y latitud nos diera
        // información sobre la calle, país, ciudad, etc. en la que me encuentro.
        criteria.setAddressInfoRequired(true);

        // Quiero datos de velocidad
        criteria.setSpeedAndCourseRequired(true);

        // Solicitamos el proveedor de localización
        LocationProvider provider = LocationProvider.getInstance(criteria);

        // ¿La implementación nos ha proporcionado un proveedor con esas características?
        if (provider  == null){
            // Lo intentamos de nuevo sin requerir datos textuales de localización
            criteria.setAddressInfoRequired(false);

            // Solicitamos el proveedor de localización
            provider = LocationProvider.getInstance(criteria);
        }

        // si tenemos proveedor inicializamos
        if (provider  != null){
            try {
                // Método bloqueante
                Location location = provider.getLocation(-1);

                // Si hay datos de localización continuamos ponemos un timer
                // que nos de los datos de localizacion cada 5 segundos (llamará
                // al método locationUpdated)
                if (location != null){
                    this.lastCoord    = location.getQualifiedCoordinates();

                    // LocationListener, interval, timeout, maxAge)
                    provider.setLocationListener(this, 5, -1, -1);
                }

                // Inicializamos el UI con los datos del estado del proveedor.
                this.providerStateChanged(provider, provider.getState());
            } catch (java.lang.InterruptedException ex){
                this.append(ex.getMessage());
            }
        }
    }

    /**
     * Finalizamos la aplicación
     */
    private void cmdExitClick(){
        this.midlet.notifyDestroyed();
    }

    /**
     * javax.microedition.lcdui.CommandListener
     */
    public void commandAction(Command c, Displayable d) {
        try {
            if (c == this.cmdStartClick){
                this.cmdStartClick_click();
            } else if (c == this.cmdExitClick){
                this.cmdExitClick();
            }
        } catch (Exception ex){
            this.append(ex.getMessage());
        }
    }

    /**
     * javax.microedition.location.LocationListener
     * Recalculamos la posición (Este método se llama cada X segundos)
     */
    public void locationUpdated(LocationProvider provider, Location location)  {
        try {
            QualifiedCoordinates coord     = location.getQualifiedCoordinates();
            AddressInfo          addr      = null;
            
            if (coord != null){
                this.txtLongitud.setString(String.valueOf(coord.getLongitude()));
                this.txtLatitud.setString(String.valueOf(coord.getLatitude()));
                
                addr = location.getAddressInfo();
            }

            if (addr != null){
                this.txtCalle.setString(addr.getField(AddressInfo.STREET));
            } else {
                this.txtCalle.setString("INFO NO DISPONIBLE");
            }

            // Hacemos el valor absoluto por que podemos ir para adelante y para detrás.
            totalCurrentDistance += Math.abs(coord.distance(lastCoord));

            // Actualizamos el interfaz gráfico
            this.txtDistanciaRecorrida.setString(String.valueOf(totalCurrentDistance));

            this.txtVelocidad.setString(String.valueOf(location.getSpeed()));
            this.lastCoord = coord;
        } catch (Exception ex){
            this.append(ex.getMessage());
            // Nada
        }
    }

    /**
     * javax.microedition.location.LocationListener
     * El estado del proveedor ha sido actualizado
     */
    public void providerStateChanged(LocationProvider provider, int newState) {
        String stateDesc = null;

        if (newState == LocationProvider.AVAILABLE){
            stateDesc = "DISPONIBLE";
        } else if (newState == LocationProvider.OUT_OF_SERVICE){
            stateDesc = "FUERA DE SERVICIO";
        } else if (newState == LocationProvider.TEMPORARILY_UNAVAILABLE){
            stateDesc = "TEMPORALMENTE FUERA DE SERVICIO";
        } else {
            stateDesc = "DESCONOCIDO";
        }

        this.txtEstadoProveedor.setString(stateDesc);
    }
}
    
    

Referencias

Conclusiones

Como podeis ver con poco esfuerzo se puede realizar aplicaciones en donde es necesaria la posición geográfica del terminal.
El API es bastante ligero en cuento número de clases e interfaces, está bien documentado por lo su aprendizate es bastante sencillo.

Fusionando esta y otras tecnologías como las que se enumeran a continuación se pueden crear todo tipo de aplicaciones, por ejemplo, podríamos crear fácilmente una aplicación que al recibir un sms enviará la posición geográfica del receptor (cierta similitud con Google Latitude e Ipoki).

  1. J2ME Push Registry. Activación automática de MIDlets.
  2. J2ME, Java Wireless Message API (WMA).
  3. J2ME, FileConnection API. Acceso a tarjetas de memorias desde MIDlets.
  4. LWUIT: Una librería gráfica tipo AWT o Swing para J2ME.
  5. J2ME. Internacionalización de aplicaciones para móviles.
  6. Establecimiento de conexiones HTTP desde un MIDLET.

Y como no, pensando un poco en el futuro… seguramente en poco tiempo todos tendremos un GPS en nuestro bolsillo.

Bueno eso es todo, un saludo,

Carlos García. Creador de MobileTest, un complemento educativo para los profesores y sus alumnos.

cgpcosmad@gmail.com, Autentia

17 COMENTARIOS

  1. Gran tutorial, me ha servido de mucho. Quería preguntarte si tienes otro tutorial de como acceder desde el móvil, en j2me, a una base de datos (sql) para bajar o subir información. Te lo agradecería.

    Un saludo y gracias por compartir tus conocimientos

  2. Excelente y muchas gracias por el ejemplo.
    realice pruebas con mi bb se pego, despues de un rato arrojo el error \\\»time out while waiting for gps location\\\».
    Bueno seguire intentando, cuando tenga una respuesta se las haré llegar…. y si alguien descubre el problema antes.. bienvenido será

  3. Hola Coipinho, me alegro que te haya parecido bueno el tutorial..

    Asegurate de que tienes cobertura de GPS donde estés ejecutando la aplicación…

    Saludos

  4. Gracias carlos por la considerancion al responderme, te cuento que ejecute la aplicacion en una bb sin gps y la como te comente arrojo un error.
    Tengo una gran duda con respecto a ese tema, cuando ejecuto google maps funciona perfecto, tratare de seguir buscando para dar con la solucion.
    Mañana probare con una bb que si cuenta con GPS y les comento como me fue.

  5. Hola Carlos primeramente te felicito por tu aplicacion es muy buena, quisiera saber si me podrias ayudar con un proyecto Universitario que no encuentro ejemplos, se trata de realizar una aplicacion movil (j2me) que presente por pantalla un mapa de una ciudad determinada pero desde una base de datos; es muy parecido al google maps pero yo tengo que tener guardada en una base de datos los mapas.

  6. Muy bueno el tutorial muchas gracias un buen aporte.

    Tengo un problema en el Emulador del PC funciona correctamente pero cuando lo paso al Movil N85 ejecuta la aplicacion y al cabo de unos segundos me sale el siguiente mensaje \\\»LOCATION REQUEST TIMED OUT\\\» alguna idea?? he estado buscando por internet pero no encuentro nada.
    gracias de ante mano.

  7. Buenos dias. estimado Carlos García Pérez la aplicacion Location API para J2ME no me funciona, tengo el netbeans 6.8 y lanzo la aplicacion pero no pasa nada….solo me salen los textfield en blanco sin ninguna informacion..

  8. Hola akakso.

    Imagino te habrás despistado del contexto… es una aplicación que debe ser ejecutada en un dispositivo móvil con GPS y no en un emulador de PC.

    Un saludo

  9. Buenos dias a todos, mmmm creo que si tienes razon… mira termine una aplicacion de pedidos censilla pero solo esta probada en emulador, sera que me puede dar alguna informacion sobre como localizar a un cliente osea en este caso son farmacias a lascuales se le toma el pedido por movil..y quiero hacer en el menu una opcion mas que me localice la posicion geografica de ese cliente…ya sea localizando algun movil qe tenga el cliente o con la direccion del mismo..ando buscando un ejemplo sencillo…y probarlo en netbeans..

    muchas gracias..

  10. Hola Carlos, muchas gracias por este tutorial, mira necesito saber que teléfono usaste cuando estabas desarrollando la aplicación? ya que la estoy necesitando para un proyecto de tesis de la universidad.. O se me puedes orientar sobre cuales tlfs soportan JSR-179?

    Muchas gracias de antemano..
    Espero tu respuesta por favor!

  11. Hola Nivaldo1988

    Use un Nokia Navigator,.. pero casi con total seguridad cualquier móvil con J2ME y GPS implemente esa especificación.

    Un salud

  12. Hola Carlos,
    Antes que nada me gustaría agradecerte por todos tus aportes, que sin duda me han sido de gran ayuda en mis estudios universitarios.-
    Quería preguntarte que tecnologías debería fusionar (de las que mensionas en este tutorial) para crear una aplicación cliente-servidor, en donde el cliente manda un mensaje al servidor indicando las coordenadas de su posición. El servidor debe recibirlas y marcarlas en Google Maps para luego descargarlo.-
    Espero puedas ayudarme, desde ya muchas gracias.
    Saludos, Mery.-

  13. Hola Carlos, muy bueno el tutorial! te hago una consulta, al principio decis que el móvil no tiene porque tener gps, entonces mi pregunta es, hay alguna forma de especificar que saque la info de location de las celdas (cell id) en vez del GPS?

    Gracias

  14. gracias por estos tutoriales. que sdk o emulador usas en netbeans. probe la aplicacion en el sdk de lg y al moverle en external events en locaion no hace ningn cambio.

  15. Antes te agradezco por los aportes de gran ayuda, te comento que he buscado por muchos medios de como enviar sms desde mi celular a un servidor pero te agradeceria si me ayudaase , tambien de como enviar datos de posicionamiento de mi celular en movimiento a un celular en tiempo real

  16. HOLA Carlos me parecen fabulosos tus tutoriales que bueno que compartas lo que sabes o tus conoscimientos con los demas .
    bueno una pregunta se puede aser que la aplicacion dea posisiones en tiempo real , si fuera asi como seria el codigo fuente ayudame te lo ruego.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad