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
42namespace WebCore {
43
44class Frame;
45
46#if ENABLE(CLIENT_BASED_GEOLOCATION)
47class GeolocationPosition;
48class GeolocationError;
49#endif
50
51class Geolocation : public RefCounted<Geolocation>
52#if !ENABLE(CLIENT_BASED_GEOLOCATION) && ENABLE(GEOLOCATION)
53    , public GeolocationServiceClient
54#endif
55{
56public:
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);
73    Frame* frame() const { return m_frame; }
74
75#if ENABLE(CLIENT_BASED_GEOLOCATION)
76    void positionChanged();
77    void setError(GeolocationError*);
78#else
79    GeolocationService* getGeolocationService() const { return m_service.get(); }
80#endif
81
82private:
83    Geoposition* lastPosition();
84
85    bool isAllowed() const { return m_allowGeolocation == Yes; }
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:
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        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:
136        PositionCacheWrapper()
137            : m_cache(GeolocationPositionCache::instance())
138        {
139            m_cache->addUser();
140        }
141        ~PositionCacheWrapper()
142        {
143            m_cache->removeUser();
144        }
145        void setCachedPosition(Geoposition* cachedPosition) { m_cache->setCachedPosition(cachedPosition); }
146        Geoposition* cachedPosition() { return m_cache->cachedPosition(); }
147    private:
148        GeolocationPositionCache* m_cache;
149    };
150
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