Académique Documents
Professionnel Documents
Culture Documents
• English
• Español
• Português
Una de las funcionalidades especiales de los equipos Nextel es que incluyen un chip GPS, el cual
permite obtener la latitud y la longitud en la que se ubica el equipo. En este artículo, vamos a
analizar en detalle una aplicación Java ME (J2ME) que hace uso no sólo de los APIs de
localización disponibles en los equipos Motorola iDEN que ofrece Nextel, sino también de un
mecanismo de manejo de hilos adecuado para que la experiencia de uso sea óptima.
Como por más documentación que exista, un ejemplo vale mucho, este artículo se basa casi en
su totalidad en un análisis de código fuente. Si bien no se supone que conozca cómo funciona
Java ME en su totalidad, en algo servirá para entender cuales funciones son parte de cualquier
aplicación y cuáles son parte del proceso de localización -- por lo tanto, si requiere un resumen
básico de qué es y cómo funciona Java ME, recomendamos que lea el artículo "Introducción a
La primera parte, y podríamos decir la más importante, presenta las inclusiones de los paquetes
import javax.microedition.io.*;
import java.io.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.lang.System;
import java.util.*;
import com.motorola.iden.position.*;
Las seis inclusiones iniciales son en general esenciales para toda aplicación Java ME que hace
caso el código fuente sería bastante distinto y será parte de otra discusión).
Luego, viene la declaración del MIDlet propio, la cual es común a todas las aplicaciones JavaME
y una lista que utilizaremos más tarde para determinar el tipo de localización aGPS que queremos
Vale hablar un poco más sobre esta lista. Cada uno de los valores (delay=no, delay=low,
delay=high) se utiliza para indicarle al API de localización si queremos una localización que
requiere la precisión que proporciona el chip GPS o si podemos valernos con las coordenadas de
la celda que está dándole servicio al equipo en el momento determinado. El parámetro delay=high
le indica al API que la aplicación está dispuesta a esperar un tiempo para una coordenada precisa
-- lo que indica el uso de GPS; usando delay=no determina que, al contrario, la aplicación
requiere de un dato de manera inmediata y por lo tanto sólo recibirá las coordenadas de la celda
Seguimos con declaraciones del Canvas, el hilo que utilizaremos para pedir las coordenadas,
// Menú principal
List myList;
En el método startApp(), a continuación, el cual es requerido por el modelo Java ME, es el que
llama el equipo cada vez que la aplicación inicia o vuelve de una pausa. El método se puede
llamar muchas veces, así que es importante que la inicialización que exista sólo se haga cuando
se requiera.
myDisplay.setCurrent(myList);
}
}
Sigue el método pauseApp() el cual es llamado cada vez que la aplicación se suspende. Este
método es esencial, ya que le permite a la aplicación soltar recursos y asegurar que pueda entrar
El método final del ciclo de vida de un MIDlet, destroyApp(), viene a continuación. destroyApp()
que termine por completo su operación y que entre al estado Destroyed. Éste se llama cuando el
usuario termina la aplicación de manera forzosa (oprimiendo la tecla END dos veces, por
En el estado Destroyed, la aplicación debe soltar todos los recursos (conexiones de red,
conexiones al GPS, al sistema de memoria, hilos, etc.) y guardar cualquier información que deba
persistir. Este método puede ser llamado desde los estados Paused ó Active.
/**
* @param unconditional Si este parámetro es verdadero al ser llamado
A seguir, el código que maneja los comandos y las actividades que éstos iniciarán.
if (d == myList) {
switch (((List)d).getSelectedIndex()) {
case 0:
case 1:
case 2:
// Mostrar una barra de progreso al usuario
myDisplay.setCurrent(myPC);
} else {
// Mostrar menu principal
myDisplay.setCurrent(myList);
}
}
El comando más importante para los propósitos de servicios de localización es el que inicializa un
nuevo hilo (gpsTread = new Thread(...)). Las funciones de localización pueden tardar, y es
importante que la aplicación continúe siendo accesible mientras las funciones de localización
retornan.
El hilo recibe como parámetro el índice escogido de la lista que definimos en el encabezado del
código. Como indicamos antes, este índice incluye un parametro que indica la tolerancia a
Seguimos con el corazón de la aplicación, el cual usa ese parámetro y las funciones de las clases
}
// Notificar al usuario del progreso
myPC.updateMessage("Obteniendo ubicación...");
pos = posCon.getPosition();
...
El posCon, de tipo PositionConnection es el que nos permite obtener los datos de localización del
equipo. La cadena de conexión que se le pasa al método open() de PositionConnection indica dos
cosas: primero, que la conexión es de tipo mposition, lo que le indica al equipo que debe
establecer una conexión con el chip GPS del equipo, y segundo, el parámetro delay, que indica
qué tipos de respuestas son aceptables y qué cantidad de demora se puede esperar.
En general, el equipo siempre intentará dar los datos más posibles que tenga disponibles y que
pueda obtener en tiempo menor al indicado por "delay". El parámetro "delay=no" indica que los
datos tienen que estar ya en el equipo y que sea sólo cosa de leerlos de la memoria. Esto implica
que la aplicación siempre recibira las coordenadas de la torre que le brinda servicio al equipo y
en ningún momento le dará acceso al chip GPS. Cuando el equipo está fuera de cobertura, la
Cuando el parámetro es "delay=low", el equipo utilizará los datos de asistencia que haya recibido
el equipo si estos existen, y los pedirá a la red nuevamente si están caducos o no existen. Este
tipo de localización funciona dentro o fuera de la red de datos, pero tendrá más posibilidad de
obtener una localización dentro de cobertura de red. Tiene un tiempo máximo de operación de 32
segundos.
El parámetro "delay=high" le permite al equipo intentar hasta por 180 segundos el obtener una
localización GPS, sea que el equipo esté dentro o fuera de la red. El equipo en este caso utiliza
los datos de asistencia sólo si estos existen y están válidos en el equipo, y si no lo están el
equipo no intentará pedirlos a la red. Cuando se requiere de una localización autónoma (por
ejemplo, en caso donde definitivamente no hay cobertura o donde pueda demorar más de 32
segundos obtener una localización por visibilidad limitada al firmamento), éste es el método a
utilizar.
Una vez que obtenemos un resultado, debemos extraerlo del objeto AggregatePosition, donde se
introducen los valores. El objeto AggregatePosition tiene un mundo de funciones, así que para
manejarlo con más facilidad, definimos una función printPosition() que nos permite darle acceso a
...
// Imprimir los datos de localización
printPosition(posCon, pos);
}catch(Exception e) {
// Notificación en caso de error
myPC.updateMessage("Excepción "+e);
}
}
/**
* Imprimir posición y otra informaciǿn
*/
private void printPosition(PositionConnection posCon,
AggregatePosition pos) {
myPC.updateMessage("Abriendo conexión...");
try {
// Revisa para asegurar que AggregatePosition no esté nulo.
if(pos == null) {
myDisplay.setCurrent(myOutput);
qué acceso tiene una aplicación a las coordenadas GPS, usando la opción de privacidad en
(En ciertos modelos, existen funciones administrativas que permiten establecer contraseñas para
A seguir, verificamos los códigos de respuesta que genera el sistema en caso de errores:
myDisplay.setCurrent(myOutput);
switch(pos.getResponseCode()){
case PositionDevice.FIX_NOT_ATTAINABLE:
myOutput.append("No se pudo obtener localización:
FIX_NOT_ATTAINABLE");
break;
case PositionDevice.ACCURACY_NOT_ATTAINABLE:
myOutput.append("No se pudo obtener grado de
exactitud: ACCURACY_NOT_ATTAINABLE");
break;
case PositionDevice.FIX_NOT_ATTAIN_ASSIST_DATA_UNAV:
myOutput.append("No se pudo obtener localización;
datos de asistencia no disponibles:
FIX_NOT_ATTAINABLE_ASSIST_DATA_UNAVAILBLE");
break;
case PositionDevice.ACC_NOT_ATTAIN_ASSIST_DATA_UNAV:
myOutput.append("No se pudo obtener grado de
exactitud; datos de asistencia no disponibles:
ACC_NOT_ATTAINABLE_ASSIST_DATA_UNAVAILBLE");
break;
case PositionDevice.BATTERY_TOO_LOW:
myOutput.append("Nivel de batería muy bajo:
BATTERY_TOO_LOW");
break;
case PositionDevice.GPS_CHIPSET_MALFUNCTION:
myOutput.append("Falla en el chip GPS:
GPS_CHIPSET_MALFUNCTION");
break;
case PositionDevice.ALMANAC_OUT_OF_DATE:
myOutput.append("Alamanaque GPS caduco:
ALMANAC_OUT_OF_DATE");
break;
case PositionDevice.UNAVAILABLE:
myOutput.append("Error desconocido. Si vé esto,
por favor informar a Nextel y Motorola");
break;
default:
myOutput.append("Error improbable...");
break;
}
return;
}
tenemos una localización completa (es decir, una con aGPS), entonces podemos intentar extraer
todos los valores que nos brinda el objeto AggregatePosition. Si tenemos una localización de
celda, podemos extraer las coordenadas de la torre para, por lo menos, poder usar esa
información.
if(pos.hasLatLon() ) {
// Variables de instancia usadas para generar información
para imprimir
int ano, mes, dia, hora, minuto, segundo, longD, latD,
longM, latM;
String LAT = pos.getLatitude(Position2D.DEGREES);
String LONG = pos.getLongitude(Position2D.DEGREES);
String mihora;
String horaSys;
Date mifecha= new Date(pos.getTimeStamp());
Date fechaSys = new Date(System.currentTimeMillis());
// Notificación de progreso
myPC.updateMessage("Verificación completa");
Thread.currentThread().sleep(500);
else {
// Notificación de progreso
myPC.updateMessage("Verificación completa");
Thread.currentThread().sleep(500);
}catch(Exception e) {
// Imprimir error
myOutput.append("Excepción " + e);
}finally{
// Mostrar progreso
myDisplay.setCurrent(myOutput);
}
}
Lo último que nos falta en términos de los servicios de localización es la creación de la interfaz
para el hilo que ejecutará la conexión con el sistema de localización del equipo -- SRunnable.
/**
* Hilo que usamos para obtener coordenadas de GPS.
* Usando un hilo, la interfaz permanece activa,
* evitando crear la impresión que se colgó la aplicación.
*/
class SRunnable implements Runnable {
// Modo usado para la operación del API de localización.
int mode = 0;
Por último, declaramos una clase interna, ProgressCanvas, que nos permite mostrar una barra de
progreso al usuario cuando estamos haciendo una operación que puede tomar tiempo.
/**
* Pantalla de progreso
*/
class ProgressCanvas extends Canvas implements Runnable{
boolean active;
private String message = null;
Thread t = null;
int x, y, limit, counter;
boolean expand;
ProgressCanvas(){
x = getWidth()/2;
y = getHeight()/3;
limit = 14;
expand = true;
}
// Limpiar la pantalla
g.setColor(0x000000);
g.fillRect(0, 0, getWidth(), getHeight());
if(expand){
if(counter >= limit){
expand = false;
}
counter += 2;
}else{
if(counter < 1) {
expand = true;
}
counter -= 2;
}
// Mostrar el mensaje
g.setColor(0xffffff);
g.setFont(Font.getFont(Font.FACE_PROPORTIONAL,
Font.STYLE_PLAIN, Font.SIZE_SMALL));
g.drawString(message, getWidth()/2, (getHeight()* 2)/3,
Graphics.HCENTER|Graphics.BASELINE);
while(active){
try{
/**
* Dibujar en la pantalla mientras el Canvas todavía
sea
* visible
*/
t.sleep(100);
if(isShown())
repaint();
}catch(Exception e){
}
}
}
}
El código completo en inglés y español se adjunta, junto con un projecto listo para compilar con el
SDK de Motorola.
Adjunto Tamaño
Adjunto Tamaño
GPS_position_sample.zip 39.55 KB
Average:
0
Your rating: Ninguno
• Java ME
• Localización y geoinformación
IR