jaroslav@172
|
1 |
/**
|
jaroslav@358
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
jaroslav@172
|
3 |
*
|
jaroslav@551
|
4 |
* Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
|
jaroslav@172
|
5 |
*
|
jaroslav@358
|
6 |
* Oracle and Java are registered trademarks of Oracle and/or its affiliates.
|
jaroslav@358
|
7 |
* Other names may be trademarks of their respective owners.
|
jaroslav@172
|
8 |
*
|
jaroslav@358
|
9 |
* The contents of this file are subject to the terms of either the GNU
|
jaroslav@358
|
10 |
* General Public License Version 2 only ("GPL") or the Common
|
jaroslav@358
|
11 |
* Development and Distribution License("CDDL") (collectively, the
|
jaroslav@358
|
12 |
* "License"). You may not use this file except in compliance with the
|
jaroslav@358
|
13 |
* License. You can obtain a copy of the License at
|
jaroslav@358
|
14 |
* http://www.netbeans.org/cddl-gplv2.html
|
jaroslav@358
|
15 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
|
jaroslav@358
|
16 |
* specific language governing permissions and limitations under the
|
jaroslav@358
|
17 |
* License. When distributing the software, include this License Header
|
jaroslav@358
|
18 |
* Notice in each file and include the License file at
|
jaroslav@358
|
19 |
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
|
jaroslav@358
|
20 |
* particular file as subject to the "Classpath" exception as provided
|
jaroslav@358
|
21 |
* by Oracle in the GPL Version 2 section of the License file that
|
jaroslav@358
|
22 |
* accompanied this code. If applicable, add the following below the
|
jaroslav@358
|
23 |
* License Header, with the fields enclosed by brackets [] replaced by
|
jaroslav@358
|
24 |
* your own identifying information:
|
jaroslav@358
|
25 |
* "Portions Copyrighted [year] [name of copyright owner]"
|
jaroslav@358
|
26 |
*
|
jaroslav@358
|
27 |
* Contributor(s):
|
jaroslav@358
|
28 |
*
|
jaroslav@358
|
29 |
* The Original Software is NetBeans. The Initial Developer of the Original
|
jaroslav@551
|
30 |
* Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
|
jaroslav@358
|
31 |
*
|
jaroslav@358
|
32 |
* If you wish your version of this file to be governed by only the CDDL
|
jaroslav@358
|
33 |
* or only the GPL Version 2, indicate your decision by adding
|
jaroslav@358
|
34 |
* "[Contributor] elects to include this software in this distribution
|
jaroslav@358
|
35 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a
|
jaroslav@358
|
36 |
* single choice of license, a recipient has the option to distribute
|
jaroslav@358
|
37 |
* your version of this file under either the CDDL, the GPL Version 2 or
|
jaroslav@358
|
38 |
* to extend the choice of license to its licensees as provided above.
|
jaroslav@358
|
39 |
* However, if you add GPL Version 2 code and therefore, elected the GPL
|
jaroslav@358
|
40 |
* Version 2 license, then the option applies only if the new code is
|
jaroslav@358
|
41 |
* made subject to such option by the copyright holder.
|
jaroslav@172
|
42 |
*/
|
jaroslav@172
|
43 |
package net.java.html.geo;
|
jaroslav@172
|
44 |
|
jaroslav@181
|
45 |
import java.util.logging.Level;
|
jaroslav@181
|
46 |
import java.util.logging.Logger;
|
jaroslav@362
|
47 |
import org.netbeans.html.geo.impl.JsG;
|
jaroslav@181
|
48 |
|
jaroslav@181
|
49 |
/** Class that represents a geolocation position provided as a callback
|
jaroslav@181
|
50 |
* to {@link Handle#onLocation(net.java.html.geo.Position)} method. The
|
jaroslav@181
|
51 |
* class getters mimic closely the structure of the position object as
|
jaroslav@181
|
52 |
* specified by <a href="http://www.w3.org/TR/2012/PRgeolocationAPI20120510/">
|
jaroslav@181
|
53 |
* W3C's Geolocation API</a>.
|
jaroslav@172
|
54 |
*
|
jaroslav@172
|
55 |
* @author Jaroslav Tulach <jtulach@netbeans.org>
|
jaroslav@172
|
56 |
*/
|
jaroslav@172
|
57 |
public final class Position {
|
jaroslav@181
|
58 |
static final Logger LOG = Logger.getLogger(Position.class.getName());
|
jaroslav@181
|
59 |
private final long timestamp;
|
jaroslav@181
|
60 |
private final Coordinates coords;
|
jaroslav@181
|
61 |
|
jaroslav@181
|
62 |
Position(Object position) {
|
jaroslav@181
|
63 |
Object obj = JsG.get(position, "timestamp");
|
jaroslav@181
|
64 |
timestamp = obj instanceof Number ? ((Number)obj).longValue() : 0L;
|
jaroslav@181
|
65 |
coords = new Coordinates(JsG.get(position, "coords"));
|
jaroslav@181
|
66 |
}
|
jaroslav@181
|
67 |
|
jaroslav@181
|
68 |
/** The actual location of the position.
|
jaroslav@181
|
69 |
* @return non-null coordinates
|
jaroslav@181
|
70 |
*/
|
jaroslav@181
|
71 |
public Coordinates getCoords() {
|
jaroslav@181
|
72 |
return coords;
|
jaroslav@181
|
73 |
}
|
jaroslav@181
|
74 |
|
jaroslav@181
|
75 |
/** The time when the position has been recorded.
|
jaroslav@181
|
76 |
* @return time in milliseconds since era (e.g. Jan 1, 1970).
|
jaroslav@181
|
77 |
*/
|
jaroslav@181
|
78 |
public long getTimestamp() {
|
jaroslav@181
|
79 |
return timestamp;
|
jaroslav@172
|
80 |
}
|
jaroslav@172
|
81 |
|
jaroslav@181
|
82 |
/** Actual location of a {@link Position}.
|
jaroslav@181
|
83 |
* Mimics closely <a href="http://www.w3.org/TR/2012/PRgeolocationAPI20120510/">
|
jaroslav@181
|
84 |
* W3C's Geolocation API</a>.
|
jaroslav@181
|
85 |
*/
|
jaroslav@172
|
86 |
public static final class Coordinates {
|
jaroslav@181
|
87 |
private final Object data;
|
jaroslav@172
|
88 |
|
jaroslav@181
|
89 |
Coordinates(Object data) {
|
jaroslav@181
|
90 |
this.data = data;
|
jaroslav@181
|
91 |
}
|
jaroslav@181
|
92 |
|
jaroslav@181
|
93 |
public double getLatitude() {
|
jaroslav@181
|
94 |
return ((Number)JsG.get(data, "latitude")).doubleValue(); // NOI18N
|
jaroslav@181
|
95 |
}
|
jaroslav@181
|
96 |
|
jaroslav@181
|
97 |
public double getLongitude() {
|
jaroslav@181
|
98 |
return ((Number)JsG.get(data, "longitude")).doubleValue(); // NOI18N
|
jaroslav@181
|
99 |
}
|
jaroslav@181
|
100 |
|
jaroslav@181
|
101 |
public double getAccuracy() {
|
jaroslav@181
|
102 |
return ((Number)JsG.get(data, "accuracy")).doubleValue(); // NOI18N
|
jaroslav@181
|
103 |
}
|
jaroslav@181
|
104 |
|
jaroslav@181
|
105 |
public Double getAltitude() {
|
jaroslav@181
|
106 |
return (Double)JsG.get(data, "altitude"); // NOI18N
|
jaroslav@181
|
107 |
}
|
jaroslav@181
|
108 |
|
jaroslav@181
|
109 |
public Double getAltitudeAccuracy() {
|
jaroslav@181
|
110 |
return (Double)JsG.get(data, "altitudeAccuracy"); // NOI18N
|
jaroslav@181
|
111 |
}
|
jaroslav@181
|
112 |
|
jaroslav@181
|
113 |
public Double getHeading() {
|
jaroslav@181
|
114 |
return (Double)JsG.get(data, "heading"); // NOI18N
|
jaroslav@181
|
115 |
}
|
jaroslav@181
|
116 |
|
jaroslav@181
|
117 |
public Double getSpeed() {
|
jaroslav@181
|
118 |
return (Double)JsG.get(data, "speed"); // NOI18N
|
jaroslav@181
|
119 |
}
|
jaroslav@181
|
120 |
} // end of Coordinates
|
jaroslav@175
|
121 |
|
jaroslav@179
|
122 |
/** Rather than subclassing this class directly consider using {@link OnLocation}
|
jaroslav@179
|
123 |
* annotation. Such annotation will generate a subclass for you automatically
|
jaroslav@179
|
124 |
* with two static methods <code>createQuery</code> and <code>createWatch</code>
|
jaroslav@179
|
125 |
* which can be used to obtain instance of this class.
|
jaroslav@175
|
126 |
*/
|
jaroslav@175
|
127 |
public static abstract class Handle {
|
jaroslav@175
|
128 |
private final boolean oneTime;
|
jaroslav@175
|
129 |
private boolean enableHighAccuracy;
|
jaroslav@175
|
130 |
private long timeout;
|
jaroslav@175
|
131 |
private long maximumAge;
|
jaroslav@181
|
132 |
volatile JsH handle;
|
jaroslav@175
|
133 |
|
jaroslav@179
|
134 |
/** Creates new instance of this handle.
|
jaroslav@179
|
135 |
*
|
jaroslav@179
|
136 |
* @param oneTime <code>true</code> if the handle represents one time
|
jaroslav@179
|
137 |
* <em>query</em>. <code>false</code> if it represents a <em>watch</em>
|
jaroslav@179
|
138 |
*/
|
jaroslav@175
|
139 |
protected Handle(boolean oneTime) {
|
jaroslav@175
|
140 |
super();
|
jaroslav@175
|
141 |
this.oneTime = oneTime;
|
jaroslav@175
|
142 |
}
|
jaroslav@175
|
143 |
|
jaroslav@179
|
144 |
/** Callback from the implementation when a (new) position has been
|
jaroslav@179
|
145 |
* received and identified
|
jaroslav@179
|
146 |
* @param p the position
|
jaroslav@179
|
147 |
* @throws Throwable if an exception is thrown, it will be logged by the system
|
jaroslav@179
|
148 |
*/
|
jaroslav@178
|
149 |
protected abstract void onLocation(Position p) throws Throwable;
|
jaroslav@175
|
150 |
|
jaroslav@179
|
151 |
/** Callback when an error occurs.
|
jaroslav@179
|
152 |
* @param ex the exception describing what went wrong
|
jaroslav@179
|
153 |
* @throws Throwable if an exception is thrown, it will be logged by the system
|
jaroslav@179
|
154 |
*/
|
jaroslav@179
|
155 |
protected abstract void onError(Exception ex) throws Throwable;
|
jaroslav@193
|
156 |
|
jaroslav@193
|
157 |
/** Check whether the location API is supported.
|
jaroslav@193
|
158 |
* @return true, if one can call {@link #start}.
|
jaroslav@193
|
159 |
*/
|
jaroslav@193
|
160 |
public final boolean isSupported() {
|
jaroslav@193
|
161 |
return JsG.hasGeolocation();
|
jaroslav@193
|
162 |
}
|
jaroslav@175
|
163 |
|
jaroslav@179
|
164 |
/** Turns on high accuracy mode as specified by the
|
jaroslav@179
|
165 |
* <a href="http://www.w3.org/TR/2012/PRgeolocationAPI20120510/">
|
jaroslav@179
|
166 |
* W3C's Geolocation API</a>. By default the mode is disabled.
|
jaroslav@179
|
167 |
* @param enable <code>true</code> or <code>false</code>
|
jaroslav@179
|
168 |
*/
|
jaroslav@181
|
169 |
public final void setHighAccuracy(boolean enable) {
|
jaroslav@175
|
170 |
this.enableHighAccuracy = enable;
|
jaroslav@175
|
171 |
}
|
jaroslav@175
|
172 |
|
jaroslav@179
|
173 |
/** The amount of milliseconds to wait for a result.
|
jaroslav@179
|
174 |
* By default infinity.
|
jaroslav@179
|
175 |
* @param timeout time in milliseconds to wait for a result.
|
jaroslav@179
|
176 |
*/
|
jaroslav@181
|
177 |
public final void setTimeout(long timeout) {
|
jaroslav@175
|
178 |
this.timeout = timeout;
|
jaroslav@175
|
179 |
}
|
jaroslav@175
|
180 |
|
jaroslav@179
|
181 |
/** Sets maximum age of cached results which are acceptable to be
|
jaroslav@179
|
182 |
* returned. By default maximum age is set to zero.
|
jaroslav@179
|
183 |
* @param age time in milliseconds of acceptable cached results
|
jaroslav@179
|
184 |
*/
|
jaroslav@181
|
185 |
public final void setMaximumAge(long age) {
|
jaroslav@175
|
186 |
this.maximumAge = age;
|
jaroslav@175
|
187 |
}
|
jaroslav@193
|
188 |
|
jaroslav@179
|
189 |
/** Initializes the <em>query</em> or <em>watch</em> request(s) and
|
jaroslav@181
|
190 |
* returns immediately. Has no effect if the query has already been
|
jaroslav@193
|
191 |
* started. If a problem appears while starting the system,
|
jaroslav@193
|
192 |
* it is immediately reported via the {@link #onError(java.lang.Exception)}
|
jaroslav@193
|
193 |
* callback. For example, if the {@link #isSupported()} method
|
jaroslav@193
|
194 |
* returns <code>false</code> an IllegalStateException is created
|
jaroslav@193
|
195 |
* and sent to the {@link #onError(java.lang.Exception) callback} method.
|
jaroslav@179
|
196 |
*/
|
jaroslav@181
|
197 |
public final void start() {
|
jaroslav@181
|
198 |
if (handle != null) {
|
jaroslav@181
|
199 |
return;
|
jaroslav@181
|
200 |
}
|
jaroslav@181
|
201 |
handle = new JsH();
|
jaroslav@193
|
202 |
try {
|
jaroslav@193
|
203 |
if (!isSupported()) {
|
jaroslav@193
|
204 |
throw new IllegalStateException("geolocation API not supported");
|
jaroslav@193
|
205 |
}
|
jaroslav@193
|
206 |
handle.start();
|
jaroslav@193
|
207 |
} catch (Exception ex) {
|
jaroslav@193
|
208 |
try {
|
jaroslav@193
|
209 |
onError(ex);
|
jaroslav@193
|
210 |
} catch (Throwable thr) {
|
jaroslav@193
|
211 |
LOG.log(Level.INFO, "Problems delivering onError report", thr);
|
jaroslav@193
|
212 |
}
|
jaroslav@193
|
213 |
}
|
jaroslav@175
|
214 |
}
|
jaroslav@175
|
215 |
|
jaroslav@179
|
216 |
/** Stops all pending requests. After this call no further callbacks
|
jaroslav@181
|
217 |
* can be obtained. Does nothing if no query or watch was in progress.
|
jaroslav@179
|
218 |
*/
|
jaroslav@181
|
219 |
public final void stop() {
|
jaroslav@181
|
220 |
JsH h = handle;
|
jaroslav@181
|
221 |
if (h == null) {
|
jaroslav@181
|
222 |
return;
|
jaroslav@181
|
223 |
}
|
jaroslav@181
|
224 |
handle = null;
|
jaroslav@181
|
225 |
h.stop();
|
jaroslav@181
|
226 |
}
|
jaroslav@181
|
227 |
|
jaroslav@181
|
228 |
private final class JsH extends JsG {
|
jaroslav@181
|
229 |
long watch;
|
jaroslav@181
|
230 |
|
jaroslav@181
|
231 |
@Override
|
jaroslav@181
|
232 |
public void onLocation(Object position) {
|
jaroslav@181
|
233 |
if (handle != this) {
|
jaroslav@181
|
234 |
return;
|
jaroslav@181
|
235 |
}
|
jaroslav@181
|
236 |
if (oneTime) {
|
jaroslav@181
|
237 |
stop();
|
jaroslav@181
|
238 |
}
|
jaroslav@181
|
239 |
try {
|
jaroslav@181
|
240 |
Handle.this.onLocation(new Position(position));
|
jaroslav@181
|
241 |
} catch (Throwable ex) {
|
jaroslav@181
|
242 |
LOG.log(Level.SEVERE, null, ex);
|
jaroslav@181
|
243 |
}
|
jaroslav@181
|
244 |
}
|
jaroslav@181
|
245 |
|
jaroslav@181
|
246 |
@Override
|
jaroslav@181
|
247 |
public void onError(Object error) {
|
jaroslav@181
|
248 |
if (handle != this) {
|
jaroslav@181
|
249 |
return;
|
jaroslav@181
|
250 |
}
|
jaroslav@181
|
251 |
if (oneTime) {
|
jaroslav@181
|
252 |
stop();
|
jaroslav@181
|
253 |
}
|
jaroslav@181
|
254 |
try {
|
jaroslav@181
|
255 |
Handle.this.onError(new Exception());
|
jaroslav@181
|
256 |
} catch (Throwable ex) {
|
jaroslav@181
|
257 |
LOG.log(Level.SEVERE, null, ex);
|
jaroslav@181
|
258 |
}
|
jaroslav@181
|
259 |
}
|
jaroslav@181
|
260 |
|
jaroslav@181
|
261 |
final void start() {
|
jaroslav@181
|
262 |
watch = start(oneTime, enableHighAccuracy, timeout, maximumAge);
|
jaroslav@181
|
263 |
}
|
jaroslav@181
|
264 |
|
jaroslav@181
|
265 |
protected final void stop() {
|
jaroslav@181
|
266 |
super.stop(watch);
|
jaroslav@181
|
267 |
}
|
jaroslav@175
|
268 |
}
|
jaroslav@175
|
269 |
}
|
jaroslav@172
|
270 |
}
|