2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
6 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7 * Other names may be trademarks of their respective owners.
9 * The contents of this file are subject to the terms of either the GNU
10 * General Public License Version 2 only ("GPL") or the Common
11 * Development and Distribution License("CDDL") (collectively, the
12 * "License"). You may not use this file except in compliance with the
13 * License. You can obtain a copy of the License at
14 * http://www.netbeans.org/cddl-gplv2.html
15 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16 * specific language governing permissions and limitations under the
17 * License. When distributing the software, include this License Header
18 * Notice in each file and include the License file at
19 * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
20 * particular file as subject to the "Classpath" exception as provided
21 * by Oracle in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the
23 * License Header, with the fields enclosed by brackets [] replaced by
24 * your own identifying information:
25 * "Portions Copyrighted [year] [name of copyright owner]"
29 * The Original Software is NetBeans. The Initial Developer of the Original
30 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
32 * If you wish your version of this file to be governed by only the CDDL
33 * or only the GPL Version 2, indicate your decision by adding
34 * "[Contributor] elects to include this software in this distribution
35 * under the [CDDL or GPL Version 2] license." If you do not indicate a
36 * single choice of license, a recipient has the option to distribute
37 * your version of this file under either the CDDL, the GPL Version 2 or
38 * to extend the choice of license to its licensees as provided above.
39 * However, if you add GPL Version 2 code and therefore, elected the GPL
40 * Version 2 license, then the option applies only if the new code is
41 * made subject to such option by the copyright holder.
43 package net.java.html.geo;
45 import java.util.logging.Level;
46 import java.util.logging.Logger;
47 import org.netbeans.html.geo.impl.JsG;
49 /** Class that represents a geolocation position provided as a callback
50 * to {@link Handle#onLocation(net.java.html.geo.Position)} method. The
51 * class getters mimic closely the structure of the position object as
52 * specified by <a href="http://www.w3.org/TR/geolocation-API/">
53 * W3C's Geolocation API</a>.
55 * @author Jaroslav Tulach
57 public final class Position {
58 static final Logger LOG = Logger.getLogger(Position.class.getName());
59 private final long timestamp;
60 private final Coordinates coords;
62 Position(Object position) {
63 Object obj = JsG.get(position, "timestamp");
64 timestamp = obj instanceof Number ? ((Number)obj).longValue() : 0L;
65 coords = new Coordinates(JsG.get(position, "coords"));
68 /** The actual location of the position.
69 * @return non-null coordinates
71 public Coordinates getCoords() {
75 /** The time when the position has been recorded.
76 * @return time in milliseconds since era (e.g. Jan 1, 1970).
78 public long getTimestamp() {
82 /** Actual location of a {@link Position}.
83 * Mimics closely <a href="http://www.w3.org/TR/geolocation-API/">
84 * W3C's Geolocation API</a>.
86 public static final class Coordinates {
87 private final Object data;
89 Coordinates(Object data) {
94 * @return geographic coordinate specified in decimal degrees.
96 public double getLatitude() {
97 return ((Number)JsG.get(data, "latitude")).doubleValue(); // NOI18N
101 * @return geographic coordinate specified in decimal degrees.
103 public double getLongitude() {
104 return ((Number)JsG.get(data, "longitude")).doubleValue(); // NOI18N
108 * The accuracy attribute denotes the accuracy level of the latitude
109 * and longitude coordinates. It is specified in meters.
110 * The value of the accuracy attribute must be a non-negative number.
112 * @return accuracy in meters
114 public double getAccuracy() {
115 return ((Number)JsG.get(data, "accuracy")).doubleValue(); // NOI18N
118 /** Denotes the height of the position, specified in meters above the ellipsoid.
119 * If the implementation cannot provide altitude information,
120 * the value of this attribute must be null.
121 * @return value in meters, may return null, if the information is not available
123 public Double getAltitude() {
124 return (Double)JsG.get(data, "altitude"); // NOI18N
127 /** The altitude accuracy is specified in meters.
128 * If the implementation cannot provide altitude information,
129 * the value of this attribute must be null. Otherwise, the value
130 * must be a non-negative real number.
131 * @return value in meters; may return null, if the information is not available
133 public Double getAltitudeAccuracy() {
134 return (Double)JsG.get(data, "altitudeAccuracy"); // NOI18N
137 /** @return may return null, if the information is not available */
138 public Double getHeading() {
139 return (Double)JsG.get(data, "heading"); // NOI18N
142 /** @return may return null, if the information is not available */
143 public Double getSpeed() {
144 return (Double)JsG.get(data, "speed"); // NOI18N
146 } // end of Coordinates
148 /** Rather than subclassing this class directly consider using {@link OnLocation}
149 * annotation. Such annotation will generate a subclass for you automatically
150 * with two static methods <code>createQuery</code> and <code>createWatch</code>
151 * which can be used to obtain instance of this class.
153 public static abstract class Handle {
154 private final boolean oneTime;
155 private boolean enableHighAccuracy;
156 private long timeout;
157 private long maximumAge;
160 /** Creates new instance of this handle.
162 * @param oneTime <code>true</code> if the handle represents one time
163 * <em>query</em>. <code>false</code> if it represents a <em>watch</em>
165 protected Handle(boolean oneTime) {
167 this.oneTime = oneTime;
170 /** Callback from the implementation when a (new) position has been
171 * received and identified
172 * @param p the position
173 * @throws Throwable if an exception is thrown, it will be logged by the system
175 protected abstract void onLocation(Position p) throws Throwable;
177 /** Callback when an error occurs.
178 * @param ex the exception describing what went wrong
179 * @throws Throwable if an exception is thrown, it will be logged by the system
181 protected abstract void onError(Exception ex) throws Throwable;
183 /** Check whether the location API is supported.
184 * @return true, if one can call {@link #start}.
186 public final boolean isSupported() {
187 return JsG.hasGeolocation();
190 /** Turns on high accuracy mode as specified by the
191 * <a href="http://www.w3.org/TR/2012/PRgeolocationAPI20120510/">
192 * W3C's Geolocation API</a>. By default the mode is disabled.
193 * @param enable <code>true</code> or <code>false</code>
195 public final void setHighAccuracy(boolean enable) {
196 this.enableHighAccuracy = enable;
199 /** The amount of milliseconds to wait for a result.
200 * By default infinity.
201 * @param timeout time in milliseconds to wait for a result.
203 public final void setTimeout(long timeout) {
204 this.timeout = timeout;
207 /** Sets maximum age of cached results which are acceptable to be
208 * returned. By default maximum age is set to zero.
209 * @param age time in milliseconds of acceptable cached results
211 public final void setMaximumAge(long age) {
212 this.maximumAge = age;
215 /** Initializes the <em>query</em> or <em>watch</em> request(s) and
216 * returns immediately. Has no effect if the query has already been
217 * started. If a problem appears while starting the system,
218 * it is immediately reported via the {@link #onError(java.lang.Exception)}
219 * callback. For example, if the {@link #isSupported()} method
220 * returns <code>false</code> an IllegalStateException is created
221 * and sent to the {@link #onError(java.lang.Exception) callback} method.
223 public final void start() {
224 if (handle != null) {
229 if (!isSupported()) {
230 throw new IllegalStateException("geolocation API not supported");
233 } catch (Exception ex) {
236 } catch (Throwable thr) {
237 LOG.log(Level.INFO, "Problems delivering onError report", thr);
242 /** Stops all pending requests. After this call no further callbacks
243 * can be obtained. Does nothing if no query or watch was in progress.
245 public final void stop() {
254 private final class JsH extends JsG {
258 public void onLocation(Object position) {
259 if (handle != this) {
266 Handle.this.onLocation(new Position(position));
267 } catch (Throwable ex) {
268 LOG.log(Level.SEVERE, null, ex);
273 public void onError(final String message, int code) {
274 if (handle != this) {
281 final Exception err = new Exception(message + " errno: " + code) {
283 public String getLocalizedMessage() {
287 Handle.this.onError(err);
288 } catch (Throwable ex) {
289 LOG.log(Level.SEVERE, null, ex);
294 watch = start(oneTime, enableHighAccuracy, timeout, maximumAge);
297 protected final void stop() {