/*
* Copyright ThinkTank Maths Limited 2006 - 2008
*
* This file is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this file. If not, see <http://www.gnu.org/licenses/>.
*/
package javax.microedition.location;
/**
* This is the starting point for applications using this API and represents a source of
* the location information. A LocationProvider represents a location-providing module,
* generating Locations.
* <p>
* Applications obtain LocationProvider instances (classes implementing the actual
* functionality by extending this abstract class) by calling the factory method. It is
* the responsibility of the implementation to return the correct LocationProvider-derived
* object.
* <p>
* Applications that need to specify criteria for the location provider selection, must
* first create a Criteria object, and pass it to the factory method. The methods that
* access the location related information shall throw SecurityException if the
* application does not have the relevant permission to access the location information.
*/
public abstract class LocationProvider {
/**
* Wrapper class that takes a user-written LocationListener and covers it with
* OpenLAPI's API.
*
* @author Samuel Halliday, ThinkTank Maths Limited
*/
static class OpenLAPIWrappedLocationListener implements
com.openlapi.LocationListener {
final LocationListener wrappedLis;
OpenLAPIWrappedLocationListener(LocationListener wrappedLis) {
this.wrappedLis = wrappedLis;
}
public void locationUpdated(com.openlapi.LocationProvider provider,
com.openlapi.Location location) {
wrappedLis.locationUpdated(new OpenLAPIWrapperProvider(provider),
new Location(location));
}
public void providerStateChanged(
com.openlapi.LocationProvider provider, int newState) {
wrappedLis.providerStateChanged(new OpenLAPIWrapperProvider(
provider), newState);
}
}
/**
* Wrapper class that takes a user-written ProximityListener and covers it with
* OpenLAPI's API.
*
* @author Samuel Halliday, ThinkTank Maths Limited
*/
static class OpenLAPIWrappedProximityListener implements
com.openlapi.ProximityListener {
final ProximityListener wrappedLis;
OpenLAPIWrappedProximityListener(ProximityListener wrappedLis) {
this.wrappedLis = wrappedLis;
}
public void monitoringStateChanged(boolean isMonitoringActive) {
wrappedLis.monitoringStateChanged(isMonitoringActive);
}
public void proximityEvent(com.openlapi.Coordinates coordinates,
com.openlapi.Location location) {
wrappedLis.proximityEvent(new Coordinates(coordinates),
new Location(location));
}
}
/**
* Wrapper for the OpenLAPI LocationProvider so that we can use it as the backend.
*
* @author Samuel Halliday, ThinkTank Maths Limited
*/
static class OpenLAPIWrapperProvider extends LocationProvider {
final com.openlapi.LocationProvider wrappedProv;
public OpenLAPIWrapperProvider(com.openlapi.LocationProvider wrappedProv) {
super(wrappedProv);
this.wrappedProv = wrappedProv;
}
public Location getLocation(int timeout) throws LocationException,
InterruptedException, SecurityException,
IllegalArgumentException {
try {
return new Location(wrapped.getLocation(timeout));
} catch (com.openlapi.LocationException e) {
throw new LocationException(e);
}
}
public int getState() {
return wrapped.getState();
}
public void reset() {
wrapped.reset();
}
public void setLocationListener(LocationListener listener,
int interval, int timeout, int maxAge) {
OpenLAPIWrappedLocationListener lis = new OpenLAPIWrappedLocationListener(
listener);
wrapped.setLocationListener(lis, interval, timeout, maxAge);
}
}
/**
* Availability status code: the location provider is available.
*/
public static final int AVAILABLE = 1;
/**
* Availability status code: the location provider is out of service. Being out of
* service means that the method is unavailable and the implementation is not able to
* expect that this situation would change in the near future. An example is when
* using a location method implemented in an external device and the external device
* is detached.
*/
public static final int OUT_OF_SERVICE = 3;
/**
* Availability status code: the location provider is temporarily unavailable.
* Temporary unavailability means that the method is unavailable due to reasons that
* can be expected to possibly change in the future and the provider to become
* available. An example is not being able to receive the signal because the signal
* used by the location method is currently being obstructed, e.g. when deep inside a
* building for satellite based methods. However, a very short transient obstruction
* of the signal should not cause the provider to toggle quickly between
* TEMPORARILY_UNAVAILABLE and AVAILABLE.
*/
public static final int TEMPORARILY_UNAVAILABLE = 2;
/**
* Adds a ProximityListener for updates when proximity to the specified coordinates is
* detected. If this method is called with a ProximityListener that is already
* registered, the registration to the specified coordinates is added in addition to
* the set of coordinates it has been previously registered for. A single listener can
* handle events for multiple sets of coordinates.
* <p>
* If the current location is known to be within the proximity radius of the specified
* coordinates, the listener shall be called immediately.
* <p>
* Detecting the proximity to the defined coordinates is done on a best effort basis
* by the implementation. Due to the limitations of the methods used to implement
* this, there are no guarantees that the proximity is always detected; especially in
* situations where the terminal briefly enters the proximity area and exits it
* shortly afterwards, it is possible that the implementation misses this. It is
* optional to provide this feature as it may not be reasonably implementable with all
* methods used to implement this API.
* <p>
* If the implementation is capable of supporting the proximity monitoring and has
* resources to add the new listener and coordinates to be monitored but the
* monitoring can't be currently done due to the current state of the method used to
* implement it, this method shall succeeed and the monitoringStateChanged method of
* the listener shall be immediately called to notify that the monitoring is not
* active currently.
*
* @param listener
* the listener to be registered
* @param coordinates
* the coordinates to be registered
* @param proximityRadius
* the radius in meters that is considered to be the threshold for being in
* the proximity of the specified coordinates
* @throws LocationException
* if the platform does not have resources to add a new listener and
* coordinates to be monitored or does not support proximity monitoring at
* all
* @throws IllegalArgumentException
* if the proximity radius is 0 or negative* or Float.NaN
* @throws NullPointerException
* if the listener or coordinates parameter is null
* @throws SecurityException
* if the application does not have the permission to register a proximity
* listener
*/
public static void addProximityListener(ProximityListener listener,
Coordinates coordinates, float proximityRadius)
throws LocationException, IllegalArgumentException,
NullPointerException, SecurityException {
try {
com.openlapi.LocationProvider.addProximityListener(
new OpenLAPIWrappedProximityListener(listener),
coordinates.wrapped, proximityRadius);
} catch (com.openlapi.LocationException e) {
throw new LocationException(e);
}
}
/**
* This factory method is used to get an actual LocationProvider implementation based
* on the defined criteria. The implementation chooses the LocationProvider so that it
* best fits the defined criteria, taking into account also possible implementation
* dependent preferences of the end user. If no concrete LocationProvider could be
* created that typically can match the defined criteria but there are other location
* providers not meeting the criteria that could be returned for a more relaxed
* criteria, null is returned to indicate this. The LocationException is thrown, if
* all supported location providers are out of service. A LocationProvider instance is
* returned if there is a location provider meeting the criteria in either the
* available or temporarily unavailable state. Implementations should try to select
* providers in the available state before providers in temporarily unavailable state,
* but this can't be always guaranteed because the implementation may not always know
* the state correctly at this point in time. If a LocationProvider meeting the
* criteria can be supported but is currently out of service, it shall not be
* returned.
* <p>
* When this method is called with a Criteria that has all fields set to the default
* values (i.e. the least restrictive criteria possible), the implementation shall
* return a LocationProvider if there is any provider that isn't in the out of service
* state. Passing null as the parameter is equal to passing a Criteria that has all
* fields set to the default values, i.e. the least restrictive set of criteria.
* <p>
* This method only makes the selection of the provider based on the criteria and is
* intended to return it quickly to the application. Any possible initialization of
* the provider is done at an implementation dependent time and MUST NOT block the
* call to this method.
* <p>
* This method may, depending on the implementation, return the same LocationProvider
* instance as has been returned previously from this method to the calling
* application, if the same instance can be used to fulfil both defined criteria. Note
* that there can be only one LocationListener associated with a LocationProvider
* instance.
*
* @param criteria
* the criteria for provider selection or null to indicate the least
* restrictive criteria with default values
* @return a LocationProvider meeting the defined criteria or null if a
* LocationProvider that meets the defined criteria can't be returned but
* there are other supported available or temporarily unavailable providers
* that do not meet the criteria.
* @throws LocationException
* if all LocationProviders are currently out of service
*/
public static LocationProvider getInstance(Criteria criteria)
throws LocationException {
try {
com.openlapi.LocationProvider provider;
if (criteria == null){
provider = com.openlapi.LocationProvider.getInstance(null);
} else {
provider = com.openlapi.LocationProvider.getInstance(criteria.wrapped);
}
return new OpenLAPIWrapperProvider(provider);
} catch (com.openlapi.LocationException e) {
throw new LocationException(e);
}
}
/**
* Returns the last known location that the implementation has. This is the best
* estimate that the implementation has for the previously known location.
* Applications can use this method to obtain the last known location and check the
* timestamp and other fields to determine if this is recent enough and good enough
* for the application to use without needing to make a new request for the current
* location.
*
* @return a location object. null is returned if the implementation doesn't have any
* previous location information.
* @throws SecurityException
* if the calling application does not have a permission to query the
* location information
*/
public static Location getLastKnownLocation() throws SecurityException {
return new Location(com.openlapi.LocationProvider
.getLastKnownLocation());
}
/**
* Removes a ProximityListener from the list of recipients for updates. If the
* specified listener is not registered or if the parameter is null, this method
* silently returns with no action.
* <p>
* <i>NOTE: the specification conflicts with itself on how to handle null parameter.
* We throw the exception.</i>
*
* @param listener
* the listener to remove
* @throws NullPointerException
* if the parameter is null
*/
public static void removeProximityListener(ProximityListener listener)
throws NullPointerException {
com.openlapi.LocationProvider
.removeProximityListener(new OpenLAPIWrappedProximityListener(
listener));
}
final com.openlapi.LocationProvider wrapped;
/**
* Empty constructor to help implementations and extensions. This is not intended to
* be used by applications. Applications should not make subclasses of this class and
* invoke this constructor from the subclass.
*/
protected LocationProvider() {
throw new RuntimeException("Sorry, I can't let you do that Dave...");
}
LocationProvider(com.openlapi.LocationProvider wrapped) {
this.wrapped = wrapped;
}
/**
* Retrieves a Location with the constraints given by the Criteria associated with
* this class. If no result could be retrieved, a LocationException is thrown. If the
* location can't be determined within the timeout period specified in the parameter,
* the method shall throw a LocationException. If the provider is temporarily
* unavailable, the implementation shall wait and try to obtain the location until the
* timeout expires. If the provider is out of service, then the LocationException is
* thrown immediately.
* <p>
* Note that the individual Location returned might not fulfil exactly the criteria
* used for selecting this LocationProvider. The Criteria is used to select a location
* provider that typically is able to meet the defined criteria, but not necessarily
* for every individual location measurement.
*
* @param timeout
* a timeout value in seconds. -1 is used to indicate that the
* implementation shall use its default timeout value for this provider.
* @return
* @throws LocationException
* if the location couldn't be retrieved or if the timeout period expired
* @throws InterruptedException
* if the operation is interrupted by calling reset() from another thread
* @throws SecurityException
* if the calling application does not have a permission to query the
* location information
* @throws IllegalArgumentException
* if the timeout = 0 or timeout < -1
*/
public abstract Location getLocation(int timeout) throws LocationException,
InterruptedException, SecurityException, IllegalArgumentException;
/**
* Returns the current state of this LocationProvider. The return value shall be one
* of the availability status code constants defined in this class.
*
* @return the availability state of this LocationProvider
*/
public abstract int getState();
/**
* Resets the LocationProvider. All pending synchronous location requests will be
* aborted and any blocked getLocation method calls will terminate with
* InterruptedException.
* <p>
* Applications can use this method e.g. when exiting to have its threads freed from
* blocking synchronous operations.
*/
public abstract void reset();
/**
* Adds a LocationListener for updates at the defined interval. The listener will be
* called with updated location at the defined interval. The listener also gets
* updates when the availablilty state of the LocationProvider changes. Passing in -1
* as the interval selects the default interval which is dependent on the used
* location method. Passing in 0 as the interval registers the listener to only
* receive provider status updates and not location updates at all.
* <p>
* Only one listener can be registered with each LocationProvider instance. Setting
* the listener replaces any possibly previously set listener. Setting the listener to
* null cancels the registration of any previously set listener.
* <p>
* The implementation shall initiate obtaining the first location result immediately
* when the listener is registered and provide the location to the listener as soon as
* it is available. Subsequent location updates will happen at the defined interval
* after the first one. If the specified update interval is smaller than the time it
* takes to obtain the first result, the listener shall receive location updates with
* invalid Locations at the defined interval until the first location result is
* available. Note that prior to getting the first valid location result, the timeout
* parameter has no effect. When the first valid location result is obtained, the
* implementation may return it to the application immediately, i.e. before the next
* interval is due. This implies that in the beginning when starting to obtain
* location results, the listener may first get updates with invalid location results
* at the defined interval and when the first valid location result is obtained, it
* may be returned to the listener as soon as it is available before the next interval
* is due. After the first valid location result is delivered to the application the
* timeout parameter is used and the next update is delivered between the time defined
* by the interval and time interval+timeout after the previous update.
* <p>
* The timeout parameter determines a timeout that is used if it's not possible to
* obtain a new location result when the update is scheduled to be provided. This
* timeout value indicates how many seconds the update is allowed to be provided late
* compared to the defined interval. If it's not possible to get a new location result
* (interval + timeout) seconds after the previous update, the update will be made and
* an invalid Location instance is returned. This is also done if the reason for the
* inability to obtain a new location result is due to the provider being temporarily
* unavailable or out of service. For example, if the interval is 60 seconds and the
* timeout is 10 seconds, the update must be delivered at most 70 seconds after the
* previous update and if no new location result is available by that time the update
* will be made with an invalid Location instance.
* <p>
* The maxAge parameter defines how old the location result is allowed to be provided
* when the update is made. This allows the implementation to reuse location results
* if it has a recent location result when the update is due to be delivered. This
* parameter can only be used to indicate a larger value than the normal time of
* obtaining a location result by a location method. The normal time of obtaining the
* location result means the time it takes normally to obtain the result when a
* request is made. If the application specifies a time value that is less than what
* can be realized with the used location method, the implementation shall provide as
* recent location results as are possible with the used location method. For example,
* if the interval is 60 seconds, the maxAge is 20 seconds and normal time to obtain
* the result is 10 seconds, the implementation would normally start obtaining the
* result 50 seconds after the previous update. If there is a location result
* otherwise available that is more recent than 40 seconds after the previous update,
* then the maxAge setting to 20 seconds allows to return this result and not start
* obtaining a new one.
* <p>
* The requirements for the intervals hold while the application is executing. If the
* application environment or the device is suspended so that the application will not
* execute at all and then the environment is later resumed, the periodic updates MUST
* continue at the defined interval but there may be a shift after the suspension
* period compared to the original interval schedule.
*
* @param listener
* the listener to be registered. If set to null the registration of any
* previously set listener is cancelled.
* @param interval
* the interval in seconds. -1 is used for the default interval of this
* provider. 0 is used to indicate that the application wants to receive
* only provider status updates and not location updates at all.
* @param timeout
* timeout value in seconds, must be greater than 0. if the value is -1,
* the default timeout for this provider is used. Also, if the interval is
* -1 to indicate the default, the value of this parameter has no effect
* and the default timeout for this provider is used. If timeout == -1 and
* interval > 0 and the default timeout of the provider is greater than the
* specified interval, then the timeout parameter is handled as if the
* application had passed the same value as timeout as the interval (i.e.
* timeout is considered to be equal to the interval). If the interval is
* 0, this parameter has no effect.
* @param maxAge
* maximum age of the returned location in seconds, must be greater than 0
* or equal to -1 to indicate that the default maximum age for this
* provider is used. Also, if the interval is -1 to indicate the default,
* the value of this parameter has no effect and the default maximum age
* for this provider is used.
*/
public abstract void setLocationListener(LocationListener listener,
int interval, int timeout, int maxAge);
}