Home | History | Annotate | Download | only in geolocation
      1 /*
      2  * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All Rights Reserved.
      3  * Copyright 2010, The Android Open Source Project
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #ifndef Geolocation_h
     28 #define Geolocation_h
     29 
     30 #include "bindings/v8/ScriptWrappable.h"
     31 #include "core/dom/ActiveDOMObject.h"
     32 #include "modules/geolocation/Geoposition.h"
     33 #include "modules/geolocation/PositionCallback.h"
     34 #include "modules/geolocation/PositionError.h"
     35 #include "modules/geolocation/PositionErrorCallback.h"
     36 #include "modules/geolocation/PositionOptions.h"
     37 #include "platform/Timer.h"
     38 
     39 namespace WebCore {
     40 
     41 class Document;
     42 class Frame;
     43 class GeolocationController;
     44 class GeolocationError;
     45 class GeolocationPosition;
     46 class Page;
     47 class ExecutionContext;
     48 
     49 class Geolocation : public ScriptWrappable, public RefCounted<Geolocation>, public ActiveDOMObject
     50 {
     51 public:
     52     static PassRefPtr<Geolocation> create(ExecutionContext*);
     53     ~Geolocation();
     54 
     55     virtual void stop() OVERRIDE;
     56     Document* document() const;
     57     Frame* frame() const;
     58 
     59     // Creates a oneshot and attempts to obtain a position that meets the
     60     // constraints of the options.
     61     void getCurrentPosition(PassOwnPtr<PositionCallback>, PassOwnPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
     62 
     63     // Creates a watcher that will be notified whenever a new position is
     64     // available that meets the constraints of the options.
     65     int watchPosition(PassOwnPtr<PositionCallback>, PassOwnPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
     66 
     67     // Removes all references to the watcher, it will not be updated again.
     68     void clearWatch(int watchID);
     69 
     70     void setIsAllowed(bool);
     71 
     72     bool isAllowed() const { return m_allowGeolocation == Yes; }
     73 
     74     // Notifies this that a new position is available. Must never be called
     75     // before permission is granted by the user.
     76     void positionChanged();
     77 
     78     // Notifies this that an error has occurred, it must be handled immediately.
     79     void setError(GeolocationError*);
     80 
     81 private:
     82     // Returns the last known position, if any. May return null.
     83     Geoposition* lastPosition();
     84 
     85     bool isDenied() const { return m_allowGeolocation == No; }
     86 
     87     explicit Geolocation(ExecutionContext*);
     88 
     89     Page* page() const;
     90 
     91     // Holds the success and error callbacks and the options that were provided
     92     // when a oneshot or watcher were created. Also, if specified in the
     93     // options, manages a timer to limit the time to wait for the system to
     94     // obtain a position.
     95     class GeoNotifier : public RefCounted<GeoNotifier> {
     96     public:
     97         static PassRefPtr<GeoNotifier> create(Geolocation* geolocation, PassOwnPtr<PositionCallback> positionCallback, PassOwnPtr<PositionErrorCallback> positionErrorCallback, PassRefPtr<PositionOptions> options) { return adoptRef(new GeoNotifier(geolocation, positionCallback, positionErrorCallback, options)); }
     98 
     99         PositionOptions* options() const { return m_options.get(); };
    100 
    101         // Sets the given error as the fatal error if there isn't one yet.
    102         // Starts the timer with an interval of 0.
    103         void setFatalError(PassRefPtr<PositionError>);
    104 
    105         bool useCachedPosition() const { return m_useCachedPosition; }
    106 
    107         // Tells the notifier to use a cached position and starts its timer with
    108         // an interval of 0.
    109         void setUseCachedPosition();
    110 
    111         void runSuccessCallback(Geoposition*);
    112         void runErrorCallback(PositionError*);
    113 
    114         // Starts the timer if a timeout was specified on the options.
    115         void startTimerIfNeeded();
    116 
    117         void stopTimer();
    118 
    119         // Runs the error callback if there is a fatal error. Otherwise, if a
    120         // cached position must be used, registers itself for receiving one.
    121         // Otherwise, the notifier has expired, and its error callback is run.
    122         void timerFired(Timer<GeoNotifier>*);
    123 
    124         bool hasZeroTimeout() const;
    125 
    126     private:
    127         GeoNotifier(Geolocation*, PassOwnPtr<PositionCallback>, PassOwnPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
    128 
    129         RefPtr<Geolocation> m_geolocation;
    130         OwnPtr<PositionCallback> m_successCallback;
    131         OwnPtr<PositionErrorCallback> m_errorCallback;
    132         RefPtr<PositionOptions> m_options;
    133         Timer<GeoNotifier> m_timer;
    134         RefPtr<PositionError> m_fatalError;
    135         bool m_useCachedPosition;
    136     };
    137 
    138     typedef Vector<RefPtr<GeoNotifier> > GeoNotifierVector;
    139     typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet;
    140 
    141     class Watchers {
    142     public:
    143         bool add(int id, PassRefPtr<GeoNotifier>);
    144         GeoNotifier* find(int id);
    145         void remove(int id);
    146         void remove(GeoNotifier*);
    147         bool contains(GeoNotifier*) const;
    148         void clear();
    149         bool isEmpty() const;
    150         void getNotifiersVector(GeoNotifierVector&) const;
    151     private:
    152         typedef HashMap<int, RefPtr<GeoNotifier> > IdToNotifierMap;
    153         typedef HashMap<RefPtr<GeoNotifier>, int> NotifierToIdMap;
    154         IdToNotifierMap m_idToNotifierMap;
    155         NotifierToIdMap m_notifierToIdMap;
    156     };
    157 
    158     bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); }
    159 
    160     void sendError(GeoNotifierVector&, PositionError*);
    161     void sendPosition(GeoNotifierVector&, Geoposition*);
    162 
    163     // Removes notifiers that use a cached position from |notifiers| and
    164     // if |cached| is not null they are added to it.
    165     static void extractNotifiersWithCachedPosition(GeoNotifierVector& notifiers, GeoNotifierVector* cached);
    166 
    167     // Copies notifiers from |src| vector to |dest| set.
    168     static void copyToSet(const GeoNotifierVector& src, GeoNotifierSet& dest);
    169 
    170     static void stopTimer(GeoNotifierVector&);
    171     void stopTimersForOneShots();
    172     void stopTimersForWatchers();
    173     void stopTimers();
    174 
    175     // Sets a fatal error on the given notifiers.
    176     void cancelRequests(GeoNotifierVector&);
    177 
    178     // Sets a fatal error on all notifiers.
    179     void cancelAllRequests();
    180 
    181     // Runs the success callbacks on all notifiers. A position must be available
    182     // and the user must have given permission.
    183     void makeSuccessCallbacks();
    184 
    185     // Sends the given error to all notifiers, unless the error is not fatal and
    186     // the notifier is due to receive a cached position. Clears the oneshots,
    187     // and also  clears the watchers if the error is fatal.
    188     void handleError(PositionError*);
    189 
    190     // Requests permission to share positions with the page.
    191     void requestPermission();
    192 
    193     // Attempts to register this with the controller for receiving updates.
    194     // Returns false if there is no controller to register with.
    195     bool startUpdating(GeoNotifier*);
    196 
    197     void stopUpdating();
    198 
    199     // Processes the notifiers that were waiting for a permission decision. If
    200     // granted and this can be registered with the controller then the
    201     // notifier's timers are started. Otherwise, a fatal error is set on them.
    202     void handlePendingPermissionNotifiers();
    203 
    204     // Attempts to obtain a position for the given notifier, either by using
    205     // the cached position or by requesting one from the controller. Sets a
    206     // fatal error if permission is denied or no position can be obtained.
    207     void startRequest(GeoNotifier*);
    208 
    209     // Discards the notifier because a fatal error occurred for it.
    210     void fatalErrorOccurred(GeoNotifier*);
    211 
    212     // Discards the notifier if it is a oneshot because it timed it.
    213     void requestTimedOut(GeoNotifier*);
    214 
    215     // Adds the notifier to the set awaiting a cached position. Runs the success
    216     // callbacks for them if permission has been granted. Requests permission if
    217     // it is unknown.
    218     void requestUsesCachedPosition(GeoNotifier*);
    219 
    220     bool haveSuitableCachedPosition(PositionOptions*);
    221 
    222     // Runs the success callbacks for the set of notifiers awaiting a cached
    223     // position, the set is then cleared. The oneshots are removed everywhere.
    224     void makeCachedPositionCallbacks();
    225 
    226     GeoNotifierSet m_oneShots;
    227     Watchers m_watchers;
    228     GeoNotifierSet m_pendingForPermissionNotifiers;
    229     RefPtr<Geoposition> m_lastPosition;
    230 
    231     enum {
    232         Unknown,
    233         InProgress,
    234         Yes,
    235         No
    236     } m_allowGeolocation;
    237 
    238     GeoNotifierSet m_requestsAwaitingCachedPosition;
    239 };
    240 
    241 } // namespace WebCore
    242 
    243 #endif // Geolocation_h
    244