1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Geolocation.
15 : *
16 : * The Initial Developer of the Original Code is Mozilla Foundation
17 : * Portions created by the Initial Developer are Copyright (C) 2008
18 : * the Initial Developer. All Rights Reserved.
19 : *
20 : * This is a derivative of work done by Google under a BSD style License.
21 : * See: http://gears.googlecode.com/svn/trunk/gears/geolocation/
22 : *
23 : * Contributor(s):
24 : * Doug Turner <dougt@meer.net> (Original Author)
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "nsCOMPtr.h"
41 : #include "nsComponentManagerUtils.h"
42 : #include "nsServiceManagerUtils.h"
43 : #include "nsThreadUtils.h"
44 : #include "nsXPCOM.h"
45 : #include "nsXPCOMCID.h"
46 : #include "nsIObserver.h"
47 : #include "nsIObserverService.h"
48 : #include "nsWifiMonitor.h"
49 : #include "nsWifiAccessPoint.h"
50 :
51 : #include "nsServiceManagerUtils.h"
52 : #include "nsComponentManagerUtils.h"
53 : #include "mozilla/Services.h"
54 :
55 : using namespace mozilla;
56 :
57 : #if defined(PR_LOGGING)
58 : PRLogModuleInfo *gWifiMonitorLog;
59 : #endif
60 :
61 38 : NS_IMPL_THREADSAFE_ISUPPORTS3(nsWifiMonitor,
62 : nsIRunnable,
63 : nsIObserver,
64 : nsIWifiMonitor)
65 :
66 1 : nsWifiMonitor::nsWifiMonitor()
67 : : mKeepGoing(true)
68 1 : , mReentrantMonitor("nsWifiMonitor.mReentrantMonitor")
69 : {
70 : #if defined(PR_LOGGING)
71 1 : gWifiMonitorLog = PR_NewLogModule("WifiMonitor");
72 : #endif
73 :
74 2 : nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
75 1 : if (obsSvc)
76 1 : obsSvc->AddObserver(this, "xpcom-shutdown", false);
77 :
78 1 : LOG(("@@@@@ wifimonitor created\n"));
79 1 : }
80 :
81 1 : nsWifiMonitor::~nsWifiMonitor()
82 : {
83 1 : }
84 :
85 : NS_IMETHODIMP
86 1 : nsWifiMonitor::Observe(nsISupports *subject, const char *topic,
87 : const PRUnichar *data)
88 : {
89 1 : if (!strcmp(topic, "xpcom-shutdown")) {
90 1 : LOG(("Shutting down\n"));
91 1 : mKeepGoing = false;
92 :
93 2 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
94 1 : mon.Notify();
95 : }
96 1 : return NS_OK;
97 : }
98 :
99 :
100 1 : NS_IMETHODIMP nsWifiMonitor::StartWatching(nsIWifiListener *aListener)
101 : {
102 1 : if (!aListener)
103 0 : return NS_ERROR_NULL_POINTER;
104 :
105 1 : nsresult rv = NS_OK;
106 1 : if (!mThread) {
107 1 : rv = NS_NewThread(getter_AddRefs(mThread), this);
108 1 : if (NS_FAILED(rv))
109 0 : return rv;
110 : }
111 :
112 2 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
113 :
114 1 : mKeepGoing = true;
115 :
116 1 : mListeners.AppendElement(nsWifiListener(aListener));
117 :
118 : // tell ourselves that we have a new watcher.
119 1 : mon.Notify();
120 1 : return NS_OK;
121 : }
122 :
123 1 : NS_IMETHODIMP nsWifiMonitor::StopWatching(nsIWifiListener *aListener)
124 : {
125 1 : if (!aListener)
126 0 : return NS_ERROR_NULL_POINTER;
127 :
128 1 : LOG(("removing listener\n"));
129 :
130 2 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
131 :
132 1 : for (PRUint32 i = 0; i < mListeners.Length(); i++) {
133 :
134 1 : if (mListeners[i].mListener == aListener) {
135 1 : mListeners.RemoveElementAt(i);
136 1 : break;
137 : }
138 : }
139 :
140 1 : if (mListeners.Length() == 0) {
141 1 : mKeepGoing = false;
142 1 : mon.Notify();
143 1 : mThread = nsnull;
144 : }
145 :
146 1 : return NS_OK;
147 : }
148 :
149 : class nsPassErrorToWifiListeners : public nsIRunnable
150 0 : {
151 : public:
152 : NS_DECL_ISUPPORTS
153 : NS_DECL_NSIRUNNABLE
154 :
155 0 : nsPassErrorToWifiListeners(nsAutoPtr<nsCOMArray<nsIWifiListener> > aListeners,
156 : nsresult aResult)
157 : : mListeners(aListeners),
158 0 : mResult(aResult)
159 0 : {}
160 :
161 : private:
162 : nsAutoPtr<nsCOMArray<nsIWifiListener> > mListeners;
163 : nsresult mResult;
164 : };
165 :
166 0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsPassErrorToWifiListeners,
167 : nsIRunnable)
168 :
169 0 : NS_IMETHODIMP nsPassErrorToWifiListeners::Run()
170 : {
171 0 : LOG(("About to send error to the wifi listeners\n"));
172 0 : for (PRInt32 i = 0; i < mListeners->Count(); i++) {
173 0 : (*mListeners)[i]->OnError(mResult);
174 : }
175 0 : return NS_OK;
176 : }
177 :
178 1 : NS_IMETHODIMP nsWifiMonitor::Run()
179 : {
180 1 : LOG(("@@@@@ wifi monitor run called\n"));
181 :
182 1 : nsresult rv = DoScan();
183 :
184 1 : if (mKeepGoing && NS_FAILED(rv)) {
185 : nsAutoPtr<nsCOMArray<nsIWifiListener> > currentListeners(
186 0 : new nsCOMArray<nsIWifiListener>(mListeners.Length()));
187 0 : if (!currentListeners)
188 0 : return NS_ERROR_OUT_OF_MEMORY;
189 :
190 0 : for (PRUint32 i = 0; i < mListeners.Length(); i++)
191 0 : currentListeners->AppendObject(mListeners[i].mListener);
192 :
193 0 : nsCOMPtr<nsIThread> thread = do_GetMainThread();
194 0 : if (!thread)
195 0 : return NS_ERROR_UNEXPECTED;
196 :
197 0 : nsCOMPtr<nsIRunnable> runnable(new nsPassErrorToWifiListeners(currentListeners, rv));
198 0 : if (!runnable)
199 0 : return NS_ERROR_OUT_OF_MEMORY;
200 :
201 0 : thread->Dispatch(runnable, NS_DISPATCH_SYNC);
202 : }
203 :
204 1 : return NS_OK;
205 : }
206 :
207 : class nsCallWifiListeners : public nsIRunnable
208 1 : {
209 : public:
210 : NS_DECL_ISUPPORTS
211 : NS_DECL_NSIRUNNABLE
212 :
213 1 : nsCallWifiListeners(nsAutoPtr<nsCOMArray<nsIWifiListener> > aListeners,
214 : nsAutoPtr<nsTArray<nsIWifiAccessPoint*> > aAccessPoints)
215 : : mListeners(aListeners),
216 1 : mAccessPoints(aAccessPoints)
217 1 : {}
218 :
219 : private:
220 : nsAutoPtr<nsCOMArray<nsIWifiListener> > mListeners;
221 : nsAutoPtr<nsTArray<nsIWifiAccessPoint*> > mAccessPoints;
222 : };
223 :
224 11 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsCallWifiListeners,
225 : nsIRunnable)
226 :
227 1 : NS_IMETHODIMP nsCallWifiListeners::Run()
228 : {
229 1 : LOG(("About to send data to the wifi listeners\n"));
230 2 : for (PRInt32 i = 0; i < mListeners->Count(); i++) {
231 1 : (*mListeners)[i]->OnChange(mAccessPoints->Elements(), mAccessPoints->Length());
232 : }
233 1 : return NS_OK;
234 : }
235 :
236 : nsresult
237 1 : nsWifiMonitor::CallWifiListeners(const nsCOMArray<nsWifiAccessPoint> &aAccessPoints,
238 : bool aAccessPointsChanged)
239 : {
240 : nsAutoPtr<nsCOMArray<nsIWifiListener> > currentListeners(
241 3 : new nsCOMArray<nsIWifiListener>(mListeners.Length()));
242 1 : if (!currentListeners)
243 0 : return NS_ERROR_OUT_OF_MEMORY;
244 :
245 : {
246 2 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
247 :
248 2 : for (PRUint32 i = 0; i < mListeners.Length(); i++) {
249 1 : if (!mListeners[i].mHasSentData || aAccessPointsChanged) {
250 1 : mListeners[i].mHasSentData = true;
251 1 : currentListeners->AppendObject(mListeners[i].mListener);
252 : }
253 : }
254 : }
255 :
256 1 : if (currentListeners->Count() > 0)
257 : {
258 1 : PRUint32 resultCount = aAccessPoints.Count();
259 : nsAutoPtr<nsTArray<nsIWifiAccessPoint*> > accessPoints(
260 2 : new nsTArray<nsIWifiAccessPoint *>(resultCount));
261 1 : if (!accessPoints)
262 0 : return NS_ERROR_OUT_OF_MEMORY;
263 :
264 1 : for (PRUint32 i = 0; i < resultCount; i++)
265 0 : accessPoints->AppendElement(aAccessPoints[i]);
266 :
267 2 : nsCOMPtr<nsIThread> thread = do_GetMainThread();
268 1 : if (!thread)
269 0 : return NS_ERROR_UNEXPECTED;
270 :
271 : nsCOMPtr<nsIRunnable> runnable(
272 3 : new nsCallWifiListeners(currentListeners, accessPoints));
273 1 : if (!runnable)
274 0 : return NS_ERROR_OUT_OF_MEMORY;
275 :
276 2 : thread->Dispatch(runnable, NS_DISPATCH_SYNC);
277 : }
278 :
279 1 : return NS_OK;
280 : }
|