geo/src/main/java/net/java/html/geo/Position.java
author Jaroslav Tulach <jaroslav.tulach@netbeans.org>
Fri, 07 Feb 2014 07:44:34 +0100
changeset 551 7ca2253fa86d
parent 365 5c93ad8c7a15
child 628 2cc7780be51d
permissions -rw-r--r--
Updating copyright headers to mention current year
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     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]"
    26  *
    27  * Contributor(s):
    28  *
    29  * The Original Software is NetBeans. The Initial Developer of the Original
    30  * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    31  *
    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.
    42  */
    43 package net.java.html.geo;
    44 
    45 import java.util.logging.Level;
    46 import java.util.logging.Logger;
    47 import org.netbeans.html.geo.impl.JsG;
    48 
    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/2012/PR­geolocation­API­20120510/">
    53  * W3C's Geolocation API</a>.
    54  *
    55  * @author Jaroslav Tulach <jtulach@netbeans.org>
    56  */
    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;
    61 
    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"));
    66     }
    67     
    68     /** The actual location of the position.
    69      * @return non-null coordinates
    70      */
    71     public Coordinates getCoords() {
    72         return coords;
    73     }
    74     
    75     /** The time when the position has been recorded.
    76      * @return time in milliseconds since era (e.g. Jan 1, 1970).
    77      */
    78     public long getTimestamp() {
    79         return timestamp;
    80     }
    81 
    82     /** Actual location of a {@link Position}. 
    83      *  Mimics closely <a href="http://www.w3.org/TR/2012/PR­geolocation­API­20120510/">
    84      * W3C's Geolocation API</a>.
    85      */
    86     public static final class Coordinates {
    87         private final Object data;
    88 
    89         Coordinates(Object data) {
    90             this.data = data;
    91         }
    92         
    93         public double getLatitude() {
    94             return ((Number)JsG.get(data, "latitude")).doubleValue(); // NOI18N
    95         }
    96 
    97         public double getLongitude() {
    98             return ((Number)JsG.get(data, "longitude")).doubleValue(); // NOI18N
    99         }
   100 
   101         public double getAccuracy() {
   102             return ((Number)JsG.get(data, "accuracy")).doubleValue(); // NOI18N
   103         }
   104         
   105         public Double getAltitude() {
   106             return (Double)JsG.get(data, "altitude"); // NOI18N
   107         }
   108         
   109         public Double getAltitudeAccuracy() {
   110             return (Double)JsG.get(data, "altitudeAccuracy"); // NOI18N
   111         }
   112         
   113         public Double getHeading() {
   114             return (Double)JsG.get(data, "heading"); // NOI18N
   115         }
   116         
   117         public Double getSpeed() {
   118             return (Double)JsG.get(data, "speed"); // NOI18N
   119         }
   120     } // end of Coordinates
   121 
   122     /** Rather than subclassing this class directly consider using {@link OnLocation}
   123      * annotation. Such annotation will generate a subclass for you automatically
   124      * with two static methods <code>createQuery</code> and <code>createWatch</code>
   125      * which can be used to obtain instance of this class.
   126      */
   127     public static abstract class Handle {
   128         private final boolean oneTime;
   129         private boolean enableHighAccuracy;
   130         private long timeout;
   131         private long maximumAge;
   132         volatile JsH handle;
   133 
   134         /** Creates new instance of this handle.
   135          * 
   136          * @param oneTime <code>true</code> if the handle represents one time 
   137          *   <em>query</em>. <code>false</code> if it represents a <em>watch</em>
   138          */
   139         protected Handle(boolean oneTime) {
   140             super();
   141             this.oneTime = oneTime;
   142         }
   143 
   144         /** Callback from the implementation when a (new) position has been
   145          * received and identified
   146          * @param p the position
   147          * @throws Throwable if an exception is thrown, it will be logged by the system
   148          */
   149         protected abstract void onLocation(Position p) throws Throwable;
   150 
   151         /** Callback when an error occurs.
   152          * @param ex the exception describing what went wrong
   153          * @throws Throwable if an exception is thrown, it will be logged by the system
   154          */
   155         protected abstract void onError(Exception ex) throws Throwable;
   156         
   157         /** Check whether the location API is supported.
   158          * @return true, if one can call {@link #start}.
   159          */
   160         public final boolean isSupported() {
   161             return JsG.hasGeolocation();
   162         }
   163 
   164         /** Turns on high accuracy mode as specified by the 
   165          * <a href="http://www.w3.org/TR/2012/PR­geolocation­API­20120510/">
   166          * W3C's Geolocation API</a>. By default the mode is disabled.
   167          * @param enable <code>true</code> or <code>false</code>
   168          */
   169         public final void setHighAccuracy(boolean enable) {
   170             this.enableHighAccuracy = enable;
   171         }
   172 
   173         /** The amount of milliseconds to wait for a result.
   174          * By default infinity.
   175          * @param timeout time in milliseconds to wait for a result.
   176          */
   177         public final void setTimeout(long timeout) {
   178             this.timeout = timeout;
   179         }
   180 
   181         /** Sets maximum age of cached results which are acceptable to be
   182          * returned. By default maximum age is set to zero.
   183          * @param age time in milliseconds of acceptable cached results
   184          */
   185         public final void setMaximumAge(long age) {
   186             this.maximumAge = age;
   187         }
   188         
   189         /** Initializes the <em>query</em> or <em>watch</em> request(s) and
   190          * returns immediately. Has no effect if the query has already been
   191          * started. If a problem appears while starting the system,
   192          * it is immediately reported via the {@link #onError(java.lang.Exception)}
   193          * callback. For example, if the {@link #isSupported()} method
   194          * returns <code>false</code> an IllegalStateException is created
   195          * and sent to the {@link #onError(java.lang.Exception) callback} method.
   196          */
   197         public final void start() {
   198             if (handle != null) {
   199                 return;
   200             }
   201             handle = new JsH();
   202             try {
   203                 if (!isSupported()) {
   204                     throw new IllegalStateException("geolocation API not supported");
   205                 }
   206                 handle.start();
   207             } catch (Exception ex) {
   208                 try {
   209                     onError(ex);
   210                 } catch (Throwable thr) {
   211                     LOG.log(Level.INFO, "Problems delivering onError report", thr);
   212                 }
   213             }
   214         }
   215 
   216         /** Stops all pending requests. After this call no further callbacks
   217          * can be obtained. Does nothing if no query or watch was in progress.
   218          */
   219         public final void stop() {
   220             JsH h = handle;
   221             if (h == null) {
   222                 return;
   223             }
   224             handle = null;
   225             h.stop();
   226         }
   227 
   228         private final class JsH extends JsG {
   229             long watch;
   230             
   231             @Override
   232             public void onLocation(Object position) {
   233                 if (handle != this) {
   234                     return;
   235                 }
   236                 if (oneTime) {
   237                     stop();
   238                 }
   239                 try {
   240                     Handle.this.onLocation(new Position(position));
   241                 } catch (Throwable ex) {
   242                     LOG.log(Level.SEVERE, null, ex);
   243                 }
   244             }
   245 
   246             @Override
   247             public void onError(Object error) {
   248                 if (handle != this) {
   249                     return;
   250                 }
   251                 if (oneTime) {
   252                     stop();
   253                 }
   254                 try {
   255                     Handle.this.onError(new Exception());
   256                 } catch (Throwable ex) {
   257                     LOG.log(Level.SEVERE, null, ex);
   258                 }
   259             }
   260 
   261             final void start() {
   262                 watch = start(oneTime, enableHighAccuracy, timeout, maximumAge);
   263             }
   264 
   265             protected final void stop() {
   266                 super.stop(watch);
   267             }
   268         }
   269     }
   270 }