lunes, 17 de enero de 2011

TUTORIAL: Desarrollo de aplicaciones para bada (XIII)

El servidor bada
El servicio Location

Ahora que tenemos una idea general de los servicios asociados al servidor bada, es hora de aprender a utilizarlos. Empezaremos con los servicios de localización (Location).

Lo que distingue las aplicaciones para dispositivos móviles de las convencionales es la característica de la localización. La mayoría de smartphones de hoy en día incorporan GPS, y los desarrolladores de aplicaciones pueden aprovechar los datos de localización en tiempo real que proporcionan para realizar aplicaciones con interesantes funcionalidades, como FourSquare o Loopt.

La plataforma bada proporciona varios tipos de servicios basados en Location, como hemos comentado. Ahora examinaremos cada uno de ellos. Antes de empezar, imagina que que quieres hacer una aplicación que dé a un usuario las direcciones de las cafeterías Starbucks más cercanas a su posición actual, y que las muestre en un mapa.
Para buscar un lugar en particular, se pueden utilizar los servicios de directorio de bada. 
En bada, como proveedor de servicios usaremos la interface IDirectoryServiceProvider, como listener la interface IDirectoryServiceListener y como gestor de eventos el método OnDirectoryRequestReceivedN.

Paso 1: Instanciar el objeto del proveedor del DirectoryService  

String providerName = L”deCarta”; 
String extraInfo = 
    L”ClientName=username;
    ClientPassword=pwd; 
    HostUrl=http://developer.kr.dz.decarta.com:80/openls”; 
IDirectoryServiceProvider *pProvider = dynamic_cast(ProviderManager::ConnectToServiceProviderN( providerName, LOC_SVC_PROVIDER_TYPE_DIRECTORY, extraInfo) );

Para instanciar el objeto proveedor, debes especificar el nombre de cliente, la contraseña y la URL del proveedor de mapas. Pero recuerda solicitar tus propias credenciales de la página web de desarrolladores de deCarta para utilizar deCarta como proveedor de servicios (las condiciones de uso para los desarrolladores bada las puedes encontrar aquí).

Paso 2: Obtener las preferencias del objeto del proveedore del DirectoryService, y establecer las propiedades de las preferencias

DirectoryServicePreferences *pPreferences = null; 
pPreferences = static_cast( pProvider->GetServicePreferencesN(false) ); 
//si se pone en true, se usaran los valores por def. del proveedor 
pPreferences->SetSortBy(&String(L”Name”)); 
pPreferences->SetSortOrder(Osp::Base::SORT_ORDER_ASCENDING);

Después de obtener el objeto DirectoryService, puedes ajustar sus preferencias, como se hace arriba. 
Por ejemplo, puedes escoger el criterio de búsqueda para buscar por nombre. 
También puedes hacer que se ordenen los resultados de manera ascendente o descendente. En este ejemplo, usamos el modo ascendente.

Paso 3: Obtener el filtro del directorio y añadir palabras clave de búsqueda

DirectoryFilter es el criterio de búsqueda. En el código de arriba, usamos GetFilterN() para obtener el objeto criterio del objeto proveedor, y luego establecemos el criterio para que use palabras clave específicas, como "Starbucks" en nuestro ejemplo.

DirectoryFilter *pFilter = null; 
pFilter = pProvider->GetFilterN(); 
pFilter->AddFilter(DirectoryFilter::SEARCH_FILTER_KEYWORD, L”Starbucks”);

NOTA: los puntos de interés (POI) de deCarta se pueden buscar también con subcadenas. Si buscamos “Star” encontraremos por ejemplo “Star Donuts”, “Nightstar restaurant”, y cualquier otro punto de interés (POI) que contenga“star” en su nombre.

Paso 4: Implementar el listener para gestionar los resultados

class MyDirectoryServiceListener; 
//resultados devueltos como lista de marcas de posicion (landmark) 
MyDirectoryServiceListener::OnDirectoryRequestResultReceivedN
(RequestId requestId, 
const IDirectoryServiceProvider& provider, 
IList* pLandmarks, 
result r, 
const String& errorCode, 
const String& errorMsg) 

   switch(r) 
   { 
      //gestionar los diferentes casos 
      if(pLandmarks) 
      { 
          IEnumerator* pEnumerator = pLandmarks->GetEnumeratorN(); 
          While(!IsFailed(pEnumerator->MoveNext()) 
          { 
             const Landmark* item = static_cast( pEnumerator->GetCurrent());                                                                          String name = item->GetName(); 
             AppLog(“Landmark Retrieved(%s)”, name.GetPointer()); 
          } 
       } 
       delete pEnumerator; 
       pLandmarks->RemoveAll(true); 
       delete pLandmarks; 
   } 
}

Para obtener el resultado de una solicitud al directorio, también tienes que implementar la función OnDirectoryRequestResultReceivedN(),un método virtual. El código de arriba muestra una implementación común de este método. Como los resultados son devuletos como una lista de marcas de posición (landmarks), debes iterar pLandmarks para mostrar la información del directorio.

Paso 5: Definir el área de búsqueda

Para definir el área de búsqueda, utiliza la clase GeographicArea (se encuentra en el namespace Osp::Location). Se trata de una clase abstracta que proporciona métodos que simulan formas en un área geográfica. Por ejemplo, nosotros usamos el CircleGeographicArea (área geográfica circular).
Para obtener información de ubicación actualizada, primero debemos implementar la interface ILocationListener:

Class MyListener : public ILocationListener 

   public: MyListener(); 
   ~MyListener(); 


   virtual void OnLocationUpdated(Location& location); 
   virtual void OnProviderStateChanged(LocProviderState newState){}; 
}; 


void MyListener::OnLocationUpdated(Location& location) 

   LocationProvider* pLocationProvider; 
   const QualifiedCoordinates* pCoordinate =    location.GetQualifiedCoordinates(); 
   if(pCoordinate != null) 
   { 
      CircleGeographicaArea* pArea; 
      //Declarada como local para mejor entendimiento. 
      //En tu proyecto es mejor que la declares como variable
      //"member" 
      pArea = new CircleGeographicArea(); 
      pArea->Set(*pCoordinate, 2000); 
   } 
   // Parar la actualización de localización 
   pLocationProvider->CancelLocationUpdates(); 
};

Ahora tenemos que obtener el objeto LocationProvider y actualizar nuestra posición:

LocationProvider* pLocationProvider; 
pLocationProvider = new LocationProvider(); 
MyListener* pLocationListener = new MyListener(); 
result r = pLocationProvider->Construct(LOC_METHOD_HYBRID); 
if(!(IsFailed(r))) 

   int interval = 5; 
   pLocationProvider->RequestLocationUpdates(*pLocationListener, interval, false); 
}

Lo que hace el código de arriba es instanciar un objeto LocationProvider mediante un enfoque híbrido, y solicitar la ubicación actualizada con un intervalo de 5 segundos. Una vez actualizada la ubicación, se invocará el método OnLocationUpdated() que se implementó en la clase MyListener.

Paso 6: Enviar la solicitud de búsqueda

RequestId reqId; 
MyDirectorServiceListener *pListener; 
//You have to implement by yourself per step 5 CircleGeographicArea *pArea; 
Coordinates center; 
//Normally it is your current coordinates from GPS 
pArea = new CircleGeographicArea(); 
pArea->Set(center, 2000); 
pFilter->AddFilter(DirectoryFilter::SEARCH_FILTER_KEYWORD, L”Starbucks”); 
result r = pProvider->Search(*pFilter, *pArea, pPreferences, *pListener, reqId);

Para enviar la solicitud de búsqueda, puedes usar el método Search() definido en la clase DirectoryServiceProvider declarada en el paso 1. Debes pasar 5 parámetros a este método: las preferencias de resultados de búsqueda recibidos pPreferences declaradas en el paso 2, el criterio de búsqueda pFilter definido en el paso 3, el listener pListener para recibir respuestas del servidor que definido en el paso 4, el identificador de solicitud reqID que identifica la búsqueda y el área de búsqueda pArea.
El parámetro pArea es el área dada donde quieres buscar las marcas de posición. En e4ste ejemplo se usa un área circular, en la que el centro del círculo corresponde a nuestra ubicación. El centro de coordenadas se actualiza constantemente dentro de un intervalo dado. la implementación se describe en el paso 5.
Hasta ahora has aprendido a implementar las clases necesarias  y como enviar la solicitud de búsqueda. Una vez hayas encontrado tu "Starbucks" favorito, seguramente querrás saber como llegar allí. En este caso, necesitarás el servicio de rutas para encontrar la ruta. Ahora veamos como encontrar una ruta mediante el servicio de bada "Route Service". 
Partiremos de nuevo la implementación en varios pasos. Algunos pasos son muy similares a los del servicio de directorios descrito arriba. Los dos primeros pasos son casi iguales, solo tienes que cambiar el nombre de servicio a LOC_SVC_PROVIDER_TYPE_ROUTE en el paso 1. Y en el paso 2, establecerás las preferencias para el servicio de rutas:

String providerName = L”deCarta”; 
String extraInfo = L”ClientName=username;
ClientPassword=pwd; HostUrl=http://developer.kr.dz.decarta.com:80/openls”; IRouteServiceProvider *pProvider = dynamic_cast( ProviderManager::ConnectToServiceProviderN(providerName, LOC_SVC_PROVIDER_TYPE_ROUTE, extraInfo) );

Puedes utilizar los ajustes por defecto de deCarta insertando el siguiente código:

RouteServicePreferences *pPreferences = null; pPreferences = static_cast(pProvider->GetServicePreferencesN(true)); 
//pon false si quieres usar tus ajustes

El siguiente paso es solicitar la ruta de tu posición actual (coordenadas) a la ubicación del "Starbucks" que recibiste de la clase ILocationListener en el paso 5:

//pLandmark es la variable definida en las coordenadas del paso 4 *pPerferredStarbucksLocation = pLandmark->GetQualifiedCoordinates(); 
//location es el parámetro utilizado en el paso 5
Coordinates *pCurrentLocation = location.GetQualifiedCoordinates(); 
ArrayList* pWaypoints = null; 
pWayPonints = new ArrayList(); 
pWaypoints->Construct(2); 
pWaypoints->InsertAt(*pCurrentLocation, 0); 
pWaypoints->InsertAy(*pPerferredStarbucksLocation, 1); 
pProvider->GetRoute(*pWaypoints, pPreferences, *pListener, reqId);

Para recibir los resultados de la ruta, debes implementar la interface IRouteServiceListener y sobrescribir el método virtual puro definido en esta clase:

Class MyListener : public IRouteServiceListener 

public: 
   MyListener(); 
   ~MyListener(); 


   virtual void OnRouteReceived
   (RequestId reqId, 
    const IRouteServiceProvider& pProvider, 
    IList* pRoute, result r, const String& errorCode, 
    const String& errorMsg); 
}; 


void OnRouteReceived(RequestId reqId, const IRouteServiceProvider& pProvider, IList* pRoute, result r, const String& errorCode, const String& errorMsg) 

   //Para ver este codigo en detalle, consulta el ejemplo
   //correpondiente en el bada SDK 
};

NOTA: los resultados devueltos por OnRouteReceived() son una lista de rutas calculadas. Si el cálculo de rutas alternativas no está disponible, solo se incluirá una ruta en la lista.

Una vez encuentres la ruta al "Starbucks", podrías invitar a tus amigos allí, ¿no? Vamos a ver que podemos hacer con los servicios que nos ofrece bada...



Vía: Introduction to bada - A developer's guide

4 comentarios:

Frezeer dijo...

Hola, puedes hacer un ejemplo de leer un xml en bada completo, esto me parece muy util y no logro encontrar ejemplos.

Gracias.

Byron dijo...

Sí, no hay problema.
En cuanto tenga un rato lo publico.

Saludos

Bernon dijo...

Hola de nuevo Byron,

Estoy intentando hacer un ejemplo parecido a este, pero con la API de Google, y te quería preguntar si sabes como recupero la longitud y la latitud del GPS que estoy poniendo a través del Event Injector.

He visto que existen dos funciones dentro de la API de Bada llamadas GetLatitude() y GetLongitude(), pero no soy capaz de recogerlas

¿Alguna experiencia intentando capturar estos parametros?

Muchas gracias

Byron dijo...

Creo que lo mejor será que haga un post con un ejemplo completo sobre el tema del GPS. Seguramente pondré el código del proyecto para que podáis copiar el código, que el editor de blogger es un poco flojo para poner código.

En cuanto pueda lo publico.

De nada!

Publicar un comentario