1 /*
2  * Copyright (C) 2008, 2009 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 "GeolocationPositionCache.h"
31 #include "Geoposition.h"
32 #include "PositionCallback.h"
33 #include "PositionError.h"
34 #include "PositionErrorCallback.h"
35 #include "PositionOptions.h"
36 #include "Timer.h"
37 
38 #if !ENABLE(CLIENT_BASED_GEOLOCATION)
39 #include "GeolocationService.h"
40 #endif
41 
42 namespace WebCore {
43 
44 class Frame;
45 
46 #if ENABLE(CLIENT_BASED_GEOLOCATION)
47 class GeolocationPosition;
48 class GeolocationError;
49 #endif
50 
51 class Geolocation : public RefCounted<Geolocation>
52 #if !ENABLE(CLIENT_BASED_GEOLOCATION) && ENABLE(GEOLOCATION)
53     , public GeolocationServiceClient
54 #endif
55 {
56 public:
create(Frame * frame)57     static PassRefPtr<Geolocation> create(Frame* frame) { return adoptRef(new Geolocation(frame)); }
58 
59     ~Geolocation();
60 
61     void reset();
62     void disconnectFrame();
63 
64     void getCurrentPosition(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
65     int watchPosition(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
66     void clearWatch(int watchId);
67 
68     // These methods are used by Android.
69     void suspend();
70     void resume();
71 
72     void setIsAllowed(bool);
frame()73     Frame* frame() const { return m_frame; }
74 
75 #if ENABLE(CLIENT_BASED_GEOLOCATION)
76     void positionChanged();
77     void setError(GeolocationError*);
78 #else
getGeolocationService()79     GeolocationService* getGeolocationService() const { return m_service.get(); }
80 #endif
81 
82 private:
83     Geoposition* lastPosition();
84 
isAllowed()85     bool isAllowed() const { return m_allowGeolocation == Yes; }
isDenied()86     bool isDenied() const { return m_allowGeolocation == No; }
87 
88     Geolocation(Frame*);
89 
90     Page* page() const;
91 
92     class GeoNotifier : public RefCounted<GeoNotifier> {
93     public:
create(Geolocation * geolocation,PassRefPtr<PositionCallback> positionCallback,PassRefPtr<PositionErrorCallback> positionErrorCallback,PassRefPtr<PositionOptions> options)94         static PassRefPtr<GeoNotifier> create(Geolocation* geolocation, PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PassRefPtr<PositionOptions> options) { return adoptRef(new GeoNotifier(geolocation, positionCallback, positionErrorCallback, options)); }
95 
96         void setFatalError(PassRefPtr<PositionError>);
97         bool hasZeroTimeout() const;
98         void setUseCachedPosition();
99         void runSuccessCallback(Geoposition*);
100         void startTimerIfNeeded();
101         void timerFired(Timer<GeoNotifier>*);
102 
103         RefPtr<Geolocation> m_geolocation;
104         RefPtr<PositionCallback> m_successCallback;
105         RefPtr<PositionErrorCallback> m_errorCallback;
106         RefPtr<PositionOptions> m_options;
107         Timer<GeoNotifier> m_timer;
108         RefPtr<PositionError> m_fatalError;
109         bool m_useCachedPosition;
110 
111     private:
112         GeoNotifier(Geolocation*, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
113     };
114 
115     typedef Vector<RefPtr<GeoNotifier> > GeoNotifierVector;
116     typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet;
117 
118     class Watchers {
119     public:
120         void set(int id, PassRefPtr<GeoNotifier>);
121         void remove(int id);
122         void remove(GeoNotifier*);
123         bool contains(GeoNotifier*) const;
124         void clear();
125         bool isEmpty() const;
126         void getNotifiersVector(GeoNotifierVector&) const;
127     private:
128         typedef HashMap<int, RefPtr<GeoNotifier> > IdToNotifierMap;
129         typedef HashMap<RefPtr<GeoNotifier>, int> NotifierToIdMap;
130         IdToNotifierMap m_idToNotifierMap;
131         NotifierToIdMap m_notifierToIdMap;
132     };
133 
134     class PositionCacheWrapper {
135     public:
PositionCacheWrapper()136         PositionCacheWrapper()
137             : m_cache(GeolocationPositionCache::instance())
138         {
139             m_cache->addUser();
140         }
~PositionCacheWrapper()141         ~PositionCacheWrapper()
142         {
143             m_cache->removeUser();
144         }
setCachedPosition(Geoposition * cachedPosition)145         void setCachedPosition(Geoposition* cachedPosition) { m_cache->setCachedPosition(cachedPosition); }
cachedPosition()146         Geoposition* cachedPosition() { return m_cache->cachedPosition(); }
147     private:
148         GeolocationPositionCache* m_cache;
149     };
150 
hasListeners()151     bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); }
152 
153     void sendError(GeoNotifierVector&, PositionError*);
154     void sendPosition(GeoNotifierVector&, Geoposition*);
155 
156     static void extractNotifiersWithCachedPosition(GeoNotifierVector& notifiers, GeoNotifierVector* cached);
157     static void copyToSet(const GeoNotifierVector&, GeoNotifierSet&);
158 
159     static void stopTimer(GeoNotifierVector&);
160     void stopTimersForOneShots();
161     void stopTimersForWatchers();
162     void stopTimers();
163 
164     void cancelRequests(GeoNotifierVector&);
165     void cancelAllRequests();
166 
167     void positionChangedInternal();
168     void makeSuccessCallbacks();
169     void handleError(PositionError*);
170 
171     void requestPermission();
172 
173     bool startUpdating(GeoNotifier*);
174     void stopUpdating();
175 
176 #if USE(PREEMPT_GEOLOCATION_PERMISSION)
177     void handlePendingPermissionNotifiers();
178 #endif
179 
180 #if !ENABLE(CLIENT_BASED_GEOLOCATION) && ENABLE(GEOLOCATION)
181     // GeolocationServiceClient
182     virtual void geolocationServicePositionChanged(GeolocationService*);
183     virtual void geolocationServiceErrorOccurred(GeolocationService*);
184 #endif
185 
186     PassRefPtr<GeoNotifier> startRequest(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
187 
188     void fatalErrorOccurred(GeoNotifier*);
189     void requestTimedOut(GeoNotifier*);
190     void requestUsesCachedPosition(GeoNotifier*);
191     bool haveSuitableCachedPosition(PositionOptions*);
192     void makeCachedPositionCallbacks();
193 
194     GeoNotifierSet m_oneShots;
195     Watchers m_watchers;
196     Frame* m_frame;
197 #if !ENABLE(CLIENT_BASED_GEOLOCATION)
198     OwnPtr<GeolocationService> m_service;
199 #endif
200 #if USE(PREEMPT_GEOLOCATION_PERMISSION)
201     GeoNotifierSet m_pendingForPermissionNotifiers;
202 #endif
203     RefPtr<Geoposition> m_lastPosition;
204 
205     enum {
206         Unknown,
207         InProgress,
208         Yes,
209         No
210     } m_allowGeolocation;
211 
212 #if ENABLE(GEOLOCATION)
213     PositionCacheWrapper m_positionCache;
214 #endif
215     GeoNotifierSet m_requestsAwaitingCachedPosition;
216 };
217 
218 } // namespace WebCore
219 
220 #endif // Geolocation_h
221 
222