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/core/v8/ScriptWrappable.h"
31#include "core/dom/ActiveDOMObject.h"
32#include "modules/geolocation/GeoNotifier.h"
33#include "modules/geolocation/GeolocationWatchers.h"
34#include "modules/geolocation/Geoposition.h"
35#include "modules/geolocation/PositionCallback.h"
36#include "modules/geolocation/PositionError.h"
37#include "modules/geolocation/PositionErrorCallback.h"
38#include "modules/geolocation/PositionOptions.h"
39#include "platform/Timer.h"
40#include "platform/heap/Handle.h"
41
42namespace blink {
43
44class Dictionary;
45class Document;
46class LocalFrame;
47class GeolocationController;
48class GeolocationError;
49class GeolocationPosition;
50class ExecutionContext;
51
52class Geolocation FINAL
53    : public GarbageCollectedFinalized<Geolocation>
54    , public ScriptWrappable
55    , public ActiveDOMObject {
56    DEFINE_WRAPPERTYPEINFO();
57public:
58    static Geolocation* create(ExecutionContext*);
59    virtual ~Geolocation();
60    void trace(Visitor*);
61
62    virtual void stop() OVERRIDE;
63    Document* document() const;
64    LocalFrame* frame() const;
65
66    // Creates a oneshot and attempts to obtain a position that meets the
67    // constraints of the options.
68    void getCurrentPosition(PositionCallback*, PositionErrorCallback*, const Dictionary&);
69
70    // Creates a watcher that will be notified whenever a new position is
71    // available that meets the constraints of the options.
72    int watchPosition(PositionCallback*, PositionErrorCallback*, const Dictionary&);
73
74    // Removes all references to the watcher, it will not be updated again.
75    void clearWatch(int watchID);
76
77    void setIsAllowed(bool);
78
79    bool isAllowed() const { return m_geolocationPermission == PermissionAllowed; }
80
81    // Notifies this that a new position is available. Must never be called
82    // before permission is granted by the user.
83    void positionChanged();
84
85    // Notifies this that an error has occurred, it must be handled immediately.
86    void setError(GeolocationError*);
87
88    // Discards the notifier because a fatal error occurred for it.
89    void fatalErrorOccurred(GeoNotifier*);
90
91    // Adds the notifier to the set awaiting a cached position. Runs the success
92    // callbacks for them if permission has been granted. Requests permission if
93    // it is unknown.
94    void requestUsesCachedPosition(GeoNotifier*);
95
96    // Discards the notifier if it is a oneshot because it timed it.
97    void requestTimedOut(GeoNotifier*);
98
99private:
100    // Returns the last known position, if any. May return null.
101    Geoposition* lastPosition();
102
103    bool isDenied() const { return m_geolocationPermission == PermissionDenied; }
104
105    explicit Geolocation(ExecutionContext*);
106
107    typedef HeapVector<Member<GeoNotifier> > GeoNotifierVector;
108    typedef HeapHashSet<Member<GeoNotifier> > GeoNotifierSet;
109
110    bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); }
111
112    void sendError(GeoNotifierVector&, PositionError*);
113    void sendPosition(GeoNotifierVector&, Geoposition*);
114
115    // Removes notifiers that use a cached position from |notifiers| and
116    // if |cached| is not null they are added to it.
117    static void extractNotifiersWithCachedPosition(GeoNotifierVector& notifiers, GeoNotifierVector* cached);
118
119    // Copies notifiers from |src| vector to |dest| set.
120    static void copyToSet(const GeoNotifierVector& src, GeoNotifierSet& dest);
121
122    static void stopTimer(GeoNotifierVector&);
123    void stopTimersForOneShots();
124    void stopTimersForWatchers();
125    void stopTimers();
126
127    // Sets a fatal error on the given notifiers.
128    void cancelRequests(GeoNotifierVector&);
129
130    // Sets a fatal error on all notifiers.
131    void cancelAllRequests();
132
133    // Runs the success callbacks on all notifiers. A position must be available
134    // and the user must have given permission.
135    void makeSuccessCallbacks();
136
137    // Sends the given error to all notifiers, unless the error is not fatal and
138    // the notifier is due to receive a cached position. Clears the oneshots,
139    // and also  clears the watchers if the error is fatal.
140    void handleError(PositionError*);
141
142    // Requests permission to share positions with the page.
143    void requestPermission();
144
145    // Attempts to register this with the controller for receiving updates.
146    // Returns false if there is no controller to register with.
147    bool startUpdating(GeoNotifier*);
148
149    void stopUpdating();
150
151    // Processes the notifiers that were waiting for a permission decision. If
152    // granted and this can be registered with the controller then the
153    // notifier's timers are started. Otherwise, a fatal error is set on them.
154    void handlePendingPermissionNotifiers();
155
156    // Attempts to obtain a position for the given notifier, either by using
157    // the cached position or by requesting one from the controller. Sets a
158    // fatal error if permission is denied or no position can be obtained.
159    void startRequest(GeoNotifier*);
160
161    bool haveSuitableCachedPosition(PositionOptions*);
162
163    // Runs the success callbacks for the set of notifiers awaiting a cached
164    // position, the set is then cleared. The oneshots are removed everywhere.
165    void makeCachedPositionCallbacks();
166
167    GeoNotifierSet m_oneShots;
168    GeolocationWatchers m_watchers;
169    GeoNotifierSet m_pendingForPermissionNotifiers;
170    Member<Geoposition> m_lastPosition;
171
172    // States of Geolocation permission as granted by the embedder. Unknown
173    // means that the embedder still has to be asked for the current permission
174    // level; Requested means that the user has yet to make a decision.
175    enum Permission {
176        PermissionUnknown,
177        PermissionRequested,
178        PermissionAllowed,
179        PermissionDenied
180    };
181
182    Permission m_geolocationPermission;
183
184    GeoNotifierSet m_requestsAwaitingCachedPosition;
185};
186
187} // namespace blink
188
189#endif // Geolocation_h
190