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 #include "platform/heap/Handle.h"
     39 
     40 namespace WebCore {
     41 
     42 class Document;
     43 class LocalFrame;
     44 class GeolocationController;
     45 class GeolocationError;
     46 class GeolocationPosition;
     47 class ExecutionContext;
     48 
     49 class Geolocation FINAL
     50     : public GarbageCollectedFinalized<Geolocation>
     51     , public ScriptWrappable
     52     , public ActiveDOMObject {
     53 public:
     54     static Geolocation* create(ExecutionContext*);
     55     virtual ~Geolocation();
     56     void trace(Visitor*);
     57 
     58     virtual void stop() OVERRIDE;
     59     Document* document() const;
     60     LocalFrame* frame() const;
     61 
     62     // Creates a oneshot and attempts to obtain a position that meets the
     63     // constraints of the options.
     64     void getCurrentPosition(PassOwnPtr<PositionCallback>, PassOwnPtr<PositionErrorCallback>, PositionOptions*);
     65 
     66     // Creates a watcher that will be notified whenever a new position is
     67     // available that meets the constraints of the options.
     68     int watchPosition(PassOwnPtr<PositionCallback>, PassOwnPtr<PositionErrorCallback>, PositionOptions*);
     69 
     70     // Removes all references to the watcher, it will not be updated again.
     71     void clearWatch(int watchID);
     72 
     73     void setIsAllowed(bool);
     74 
     75     bool isAllowed() const { return m_allowGeolocation == Yes; }
     76 
     77     // Notifies this that a new position is available. Must never be called
     78     // before permission is granted by the user.
     79     void positionChanged();
     80 
     81     // Notifies this that an error has occurred, it must be handled immediately.
     82     void setError(GeolocationError*);
     83 
     84 private:
     85     // Returns the last known position, if any. May return null.
     86     Geoposition* lastPosition();
     87 
     88     bool isDenied() const { return m_allowGeolocation == No; }
     89 
     90     explicit Geolocation(ExecutionContext*);
     91 
     92     // Holds the success and error callbacks and the options that were provided
     93     // when a oneshot or watcher were created. Also, if specified in the
     94     // options, manages a timer to limit the time to wait for the system to
     95     // obtain a position.
     96     class GeoNotifier : public GarbageCollectedFinalized<GeoNotifier> {
     97     public:
     98         static GeoNotifier* create(Geolocation* geolocation, PassOwnPtr<PositionCallback> positionCallback, PassOwnPtr<PositionErrorCallback> positionErrorCallback, PositionOptions* options)
     99         {
    100             return new GeoNotifier(geolocation, positionCallback, positionErrorCallback, options);
    101         }
    102         void trace(Visitor*);
    103 
    104         PositionOptions* options() const { return m_options.get(); };
    105 
    106         // Sets the given error as the fatal error if there isn't one yet.
    107         // Starts the timer with an interval of 0.
    108         void setFatalError(PositionError*);
    109 
    110         bool useCachedPosition() const { return m_useCachedPosition; }
    111 
    112         // Tells the notifier to use a cached position and starts its timer with
    113         // an interval of 0.
    114         void setUseCachedPosition();
    115 
    116         void runSuccessCallback(Geoposition*);
    117         void runErrorCallback(PositionError*);
    118 
    119         void startTimer();
    120         void stopTimer();
    121 
    122         // Runs the error callback if there is a fatal error. Otherwise, if a
    123         // cached position must be used, registers itself for receiving one.
    124         // Otherwise, the notifier has expired, and its error callback is run.
    125         void timerFired(Timer<GeoNotifier>*);
    126 
    127     private:
    128         GeoNotifier(Geolocation*, PassOwnPtr<PositionCallback>, PassOwnPtr<PositionErrorCallback>, PositionOptions*);
    129 
    130         Member<Geolocation> m_geolocation;
    131         OwnPtr<PositionCallback> m_successCallback;
    132         OwnPtr<PositionErrorCallback> m_errorCallback;
    133         Member<PositionOptions> m_options;
    134         Timer<GeoNotifier> m_timer;
    135         Member<PositionError> m_fatalError;
    136         bool m_useCachedPosition;
    137     };
    138 
    139     typedef HeapVector<Member<GeoNotifier> > GeoNotifierVector;
    140     typedef HeapHashSet<Member<GeoNotifier> > GeoNotifierSet;
    141 
    142     class Watchers {
    143         DISALLOW_ALLOCATION();
    144     public:
    145         void trace(Visitor*);
    146         bool add(int id, GeoNotifier*);
    147         GeoNotifier* find(int id);
    148         void remove(int id);
    149         void remove(GeoNotifier*);
    150         bool contains(GeoNotifier*) const;
    151         void clear();
    152         bool isEmpty() const;
    153         void getNotifiersVector(GeoNotifierVector&) const;
    154     private:
    155         typedef HeapHashMap<int, Member<GeoNotifier> > IdToNotifierMap;
    156         typedef HeapHashMap<Member<GeoNotifier>, int> NotifierToIdMap;
    157         IdToNotifierMap m_idToNotifierMap;
    158         NotifierToIdMap m_notifierToIdMap;
    159     };
    160 
    161     bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); }
    162 
    163     void sendError(GeoNotifierVector&, PositionError*);
    164     void sendPosition(GeoNotifierVector&, Geoposition*);
    165 
    166     // Removes notifiers that use a cached position from |notifiers| and
    167     // if |cached| is not null they are added to it.
    168     static void extractNotifiersWithCachedPosition(GeoNotifierVector& notifiers, GeoNotifierVector* cached);
    169 
    170     // Copies notifiers from |src| vector to |dest| set.
    171     static void copyToSet(const GeoNotifierVector& src, GeoNotifierSet& dest);
    172 
    173     static void stopTimer(GeoNotifierVector&);
    174     void stopTimersForOneShots();
    175     void stopTimersForWatchers();
    176     void stopTimers();
    177 
    178     // Sets a fatal error on the given notifiers.
    179     void cancelRequests(GeoNotifierVector&);
    180 
    181     // Sets a fatal error on all notifiers.
    182     void cancelAllRequests();
    183 
    184     // Runs the success callbacks on all notifiers. A position must be available
    185     // and the user must have given permission.
    186     void makeSuccessCallbacks();
    187 
    188     // Sends the given error to all notifiers, unless the error is not fatal and
    189     // the notifier is due to receive a cached position. Clears the oneshots,
    190     // and also  clears the watchers if the error is fatal.
    191     void handleError(PositionError*);
    192 
    193     // Requests permission to share positions with the page.
    194     void requestPermission();
    195 
    196     // Attempts to register this with the controller for receiving updates.
    197     // Returns false if there is no controller to register with.
    198     bool startUpdating(GeoNotifier*);
    199 
    200     void stopUpdating();
    201 
    202     // Processes the notifiers that were waiting for a permission decision. If
    203     // granted and this can be registered with the controller then the
    204     // notifier's timers are started. Otherwise, a fatal error is set on them.
    205     void handlePendingPermissionNotifiers();
    206 
    207     // Attempts to obtain a position for the given notifier, either by using
    208     // the cached position or by requesting one from the controller. Sets a
    209     // fatal error if permission is denied or no position can be obtained.
    210     void startRequest(GeoNotifier*);
    211 
    212     // Discards the notifier because a fatal error occurred for it.
    213     void fatalErrorOccurred(GeoNotifier*);
    214 
    215     // Discards the notifier if it is a oneshot because it timed it.
    216     void requestTimedOut(GeoNotifier*);
    217 
    218     // Adds the notifier to the set awaiting a cached position. Runs the success
    219     // callbacks for them if permission has been granted. Requests permission if
    220     // it is unknown.
    221     void requestUsesCachedPosition(GeoNotifier*);
    222 
    223     bool haveSuitableCachedPosition(PositionOptions*);
    224 
    225     // Runs the success callbacks for the set of notifiers awaiting a cached
    226     // position, the set is then cleared. The oneshots are removed everywhere.
    227     void makeCachedPositionCallbacks();
    228 
    229     GeoNotifierSet m_oneShots;
    230     Watchers m_watchers;
    231     GeoNotifierSet m_pendingForPermissionNotifiers;
    232     Member<Geoposition> m_lastPosition;
    233 
    234     enum {
    235         Unknown,
    236         InProgress,
    237         Yes,
    238         No
    239     } m_allowGeolocation;
    240 
    241     GeoNotifierSet m_requestsAwaitingCachedPosition;
    242 };
    243 
    244 } // namespace WebCore
    245 
    246 #endif // Geolocation_h
    247