1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
14 * The Original Code is Geolocation.
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.
21 * Doug Turner <dougt@meer.net> (Original Author)
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 #include "nsGeolocationOOP.h"
39 #include "nsXULAppAPI.h"
41 #include "mozilla/dom/PBrowserChild.h"
42 #include "mozilla/dom/PBrowserParent.h"
43 #include "mozilla/dom/ContentChild.h"
44 #include "nsNetUtil.h"
46 #include "nsFrameManager.h"
47 #include "nsFrameLoader.h"
48 #include "nsIFrameLoader.h"
50 #include "nsIDocShellTreeOwner.h"
51 #include "nsIDocShellTreeItem.h"
52 #include "nsIWebProgressListener2.h"
54 #include "nsDOMEventTargetHelper.h"
58 #include "nsGeolocation.h"
59 #include "nsAutoPtr.h"
61 #include "nsIDOMWindow.h"
62 #include "nsDOMClassInfo.h"
63 #include "nsComponentManagerUtils.h"
64 #include "nsICategoryManager.h"
65 #include "nsISupportsPrimitives.h"
66 #include "nsServiceManagerUtils.h"
67 #include "nsContentUtils.h"
69 #include "nsIPermissionManager.h"
70 #include "nsIObserverService.h"
71 #include "nsIPrefService.h"
72 #include "nsIPrefBranch2.h"
73 #include "nsIJSContextStack.h"
74 #include "nsThreadUtils.h"
75 #include "mozilla/Services.h"
76 #include "mozilla/unused.h"
80 #ifdef WINCE_WINDOWS_MOBILE
81 #include "WinMobileLocationProvider.h"
84 #ifdef MOZ_MAEMO_LIBLOCATION
85 #include "MaemoLocationProvider.h"
89 #include "AndroidLocationProvider.h"
92 #include "nsIDOMDocument.h"
93 #include "nsIDocument.h"
95 // Some limit to the number of get or watch geolocation requests
96 // that a window can make.
97 #define MAX_GEO_REQUESTS_PER_WINDOW 1500
99 using mozilla::unused
; // <snicker>
100 using namespace mozilla::dom
;
102 class RequestPromptEvent
: public nsRunnable
105 RequestPromptEvent(nsGeolocationRequest
* request
)
111 nsCOMPtr
<nsIContentPermissionPrompt
> prompt
= do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID
);
113 prompt
->Prompt(mRequest
);
119 nsRefPtr
<nsGeolocationRequest
> mRequest
;
122 class RequestAllowEvent
: public nsRunnable
125 RequestAllowEvent(int allow
, nsGeolocationRequest
* request
)
141 nsRefPtr
<nsGeolocationRequest
> mRequest
;
144 class RequestSendLocationEvent
: public nsRunnable
147 // a bit funky. if locator is passed, that means this
148 // event should remove the request from it. If we ever
149 // have to do more, then we can change this around.
150 RequestSendLocationEvent(nsIDOMGeoPosition
* aPosition
,
151 nsGeolocationRequest
* aRequest
,
152 nsGeolocation
* aLocator
= nsnull
)
153 : mPosition(aPosition
),
160 mRequest
->SendLocation(mPosition
);
162 mLocator
->RemoveRequest(mRequest
);
167 nsCOMPtr
<nsIDOMGeoPosition
> mPosition
;
168 nsRefPtr
<nsGeolocationRequest
> mRequest
;
170 nsRefPtr
<nsGeolocation
> mLocator
;
173 ////////////////////////////////////////////////////
174 // nsDOMGeoPositionError
175 ////////////////////////////////////////////////////
177 class nsDOMGeoPositionError
: public nsIDOMGeoPositionError
181 NS_DECL_NSIDOMGEOPOSITIONERROR
183 nsDOMGeoPositionError(PRInt16 aCode
);
184 void NotifyCallback(nsIDOMGeoPositionErrorCallback
* callback
);
187 ~nsDOMGeoPositionError();
191 DOMCI_DATA(GeoPositionError
, nsDOMGeoPositionError
)
193 NS_INTERFACE_MAP_BEGIN(nsDOMGeoPositionError
)
194 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDOMGeoPositionError
)
195 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionError
)
196 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(GeoPositionError
)
199 NS_IMPL_THREADSAFE_ADDREF(nsDOMGeoPositionError
)
200 NS_IMPL_THREADSAFE_RELEASE(nsDOMGeoPositionError
)
202 nsDOMGeoPositionError::nsDOMGeoPositionError(PRInt16 aCode
)
207 nsDOMGeoPositionError::~nsDOMGeoPositionError(){}
211 nsDOMGeoPositionError::GetCode(PRInt16
*aCode
)
213 NS_ENSURE_ARG_POINTER(aCode
);
219 nsDOMGeoPositionError::NotifyCallback(nsIDOMGeoPositionErrorCallback
* aCallback
)
224 // Ensure that the proper context is on the stack (bug 452762)
225 nsCOMPtr
<nsIJSContextStack
> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
226 if (!stack
|| NS_FAILED(stack
->Push(nsnull
)))
229 aCallback
->HandleEvent(this);
235 ////////////////////////////////////////////////////
236 // nsGeolocationRequest
237 ////////////////////////////////////////////////////
239 nsGeolocationRequest::nsGeolocationRequest(nsGeolocation
* aLocator
,
240 nsIDOMGeoPositionCallback
* aCallback
,
241 nsIDOMGeoPositionErrorCallback
* aErrorCallback
,
242 nsIDOMGeoPositionOptions
* aOptions
)
243 : mAllowed(PR_FALSE
),
245 mCallback(aCallback
),
246 mErrorCallback(aErrorCallback
),
252 nsGeolocationRequest::~nsGeolocationRequest()
257 nsGeolocationRequest::Init()
259 // This method is called before the user has given permission for this request.
261 // check to see if we have a geolocation provider, if not, notify an error and bail.
262 nsRefPtr
<nsGeolocationService
> geoService
= nsGeolocationService::GetInstance();
263 if (!geoService
->HasGeolocationProvider()) {
264 NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE
);
265 return NS_ERROR_FAILURE
;
271 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGeolocationRequest
)
272 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIContentPermissionRequest
)
273 NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest
)
274 NS_INTERFACE_MAP_ENTRY(nsITimerCallback
)
277 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocationRequest
)
278 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocationRequest
)
280 NS_IMPL_CYCLE_COLLECTION_4(nsGeolocationRequest
, mCallback
, mErrorCallback
, mOptions
, mLocator
)
284 nsGeolocationRequest::NotifyError(PRInt16 errorCode
)
286 nsRefPtr
<nsDOMGeoPositionError
> positionError
= new nsDOMGeoPositionError(errorCode
);
290 positionError
->NotifyCallback(mErrorCallback
);
295 nsGeolocationRequest::Notify(nsITimer
* aTimer
)
297 // If we haven't gotten an answer from the geolocation
298 // provider yet, cancel the request. Same logic as
299 // ::Cancel, just a different error
301 NotifyError(nsIDOMGeoPositionError::TIMEOUT
);
302 // remove ourselves from the locator's callback lists.
303 mLocator
->RemoveRequest(this);
305 mTimeoutTimer
= nsnull
;
310 nsGeolocationRequest::GetUri(nsIURI
* *aRequestingURI
)
312 NS_ENSURE_ARG_POINTER(aRequestingURI
);
314 nsCOMPtr
<nsIURI
> uri
= mLocator
->GetURI();
315 uri
.forget(aRequestingURI
);
321 nsGeolocationRequest::GetType(nsACString
& aType
)
323 aType
= "geolocation";
328 nsGeolocationRequest::GetWindow(nsIDOMWindow
* *aRequestingWindow
)
330 NS_ENSURE_ARG_POINTER(aRequestingWindow
);
332 nsCOMPtr
<nsIDOMWindow
> window
= do_QueryReferent(mLocator
->GetOwner());
333 window
.forget(aRequestingWindow
);
339 nsGeolocationRequest::GetElement(nsIDOMElement
* *aRequestingElement
)
341 NS_ENSURE_ARG_POINTER(aRequestingElement
);
342 *aRequestingElement
= nsnull
;
347 nsGeolocationRequest::Cancel()
349 NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED
);
351 // remove ourselves from the locators callback lists.
352 mLocator
->RemoveRequest(this);
357 nsGeolocationRequest::Allow()
359 nsRefPtr
<nsGeolocationService
> geoService
= nsGeolocationService::GetInstance();
361 // Kick off the geo device, if it isn't already running
362 nsresult rv
= geoService
->StartDevice();
365 // Location provider error
366 NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE
);
370 nsCOMPtr
<nsIDOMGeoPosition
> lastPosition
= geoService
->GetCachedPosition();
371 DOMTimeStamp cachedPositionTime
;
373 lastPosition
->GetTimestamp(&cachedPositionTime
);
375 // check to see if we can use a cached value
378 // a) the user has specified a maximumAge which allows us to return a cached value,
380 // b) the cached position time is some reasonable value to return to the user (<30s)
382 PRUint32 maximumAge
= 30 * PR_MSEC_PER_SEC
;
385 nsresult rv
= mOptions
->GetMaximumAge(&tempAge
);
386 if (NS_SUCCEEDED(rv
)) {
388 maximumAge
= tempAge
;
392 if (lastPosition
&& maximumAge
> 0 &&
393 ( PRTime(PR_Now() / PR_USEC_PER_MSEC
) - maximumAge
<=
394 PRTime(cachedPositionTime
) )) {
395 // okay, we can return a cached position
398 nsCOMPtr
<nsIRunnable
> ev
= new RequestSendLocationEvent(lastPosition
, this, mLocator
);
399 NS_DispatchToMainThread(ev
);
409 nsGeolocationRequest::SetTimeoutTimer()
412 mTimeoutTimer
->Cancel();
413 mTimeoutTimer
= nsnull
;
416 if (mOptions
&& NS_SUCCEEDED(mOptions
->GetTimeout(&timeout
)) && timeout
> 0) {
421 mTimeoutTimer
= do_CreateInstance("@mozilla.org/timer;1");
422 mTimeoutTimer
->InitWithCallback(this, timeout
, nsITimer::TYPE_ONE_SHOT
);
427 nsGeolocationRequest::MarkCleared()
433 nsGeolocationRequest::SendLocation(nsIDOMGeoPosition
* aPosition
)
435 if (mCleared
|| !mAllowed
)
439 mTimeoutTimer
->Cancel();
440 mTimeoutTimer
= nsnull
;
443 // we should not pass null back to the DOM.
445 NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE
);
449 // Ensure that the proper context is on the stack (bug 452762)
450 nsCOMPtr
<nsIJSContextStack
> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
451 if (!stack
|| NS_FAILED(stack
->Push(nsnull
)))
452 return; // silently fail
454 mCallback
->HandleEvent(aPosition
);
464 nsGeolocationRequest::Shutdown()
468 mErrorCallback
= nsnull
;
472 bool nsGeolocationRequest::Recv__delete__(const bool& allow
)
481 ////////////////////////////////////////////////////
482 // nsGeolocationService
483 ////////////////////////////////////////////////////
484 NS_INTERFACE_MAP_BEGIN(nsGeolocationService
)
485 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIGeolocationUpdate
)
486 NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate
)
487 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
490 NS_IMPL_THREADSAFE_ADDREF(nsGeolocationService
)
491 NS_IMPL_THREADSAFE_RELEASE(nsGeolocationService
)
494 static PRBool sGeoEnabled
= PR_TRUE
;
495 static PRBool sGeoIgnoreLocationFilter
= PR_FALSE
;
498 GeoEnabledChangedCallback(const char *aPrefName
, void *aClosure
)
500 sGeoEnabled
= nsContentUtils::GetBoolPref("geo.enabled", PR_TRUE
);
505 GeoIgnoreLocationFilterChangedCallback(const char *aPrefName
, void *aClosure
)
507 sGeoIgnoreLocationFilter
= nsContentUtils::GetBoolPref("geo.ignore.location_filter",
513 nsresult
nsGeolocationService::Init()
515 mTimeout
= nsContentUtils::GetIntPref("geo.timeout", 6000);
517 nsContentUtils::RegisterPrefCallback("geo.ignore.location_filter",
518 GeoIgnoreLocationFilterChangedCallback
,
521 GeoIgnoreLocationFilterChangedCallback("geo.ignore.location_filter", nsnull
);
524 nsContentUtils::RegisterPrefCallback("geo.enabled",
525 GeoEnabledChangedCallback
,
528 GeoEnabledChangedCallback("geo.enabled", nsnull
);
531 return NS_ERROR_FAILURE
;
533 nsCOMPtr
<nsIGeolocationProvider
> provider
= do_GetService(NS_GEOLOCATION_PROVIDER_CONTRACTID
);
535 mProviders
.AppendObject(provider
);
537 // look up any providers that were registered via the category manager
538 nsCOMPtr
<nsICategoryManager
> catMan(do_GetService("@mozilla.org/categorymanager;1"));
540 return NS_ERROR_FAILURE
;
542 // geolocation service can be enabled -> now register observer
543 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
545 return NS_ERROR_FAILURE
;
547 obs
->AddObserver(this, "quit-application", false);
549 nsCOMPtr
<nsISimpleEnumerator
> geoproviders
;
550 catMan
->EnumerateCategory("geolocation-provider", getter_AddRefs(geoproviders
));
554 while (NS_SUCCEEDED(geoproviders
->HasMoreElements(&hasMore
)) && hasMore
) {
555 nsCOMPtr
<nsISupports
> elem
;
556 geoproviders
->GetNext(getter_AddRefs(elem
));
558 nsCOMPtr
<nsISupportsCString
> elemString
= do_QueryInterface(elem
);
561 elemString
->GetData(name
);
564 catMan
->GetCategoryEntry("geolocation-provider", name
.get(), getter_Copies(spec
));
566 provider
= do_GetService(spec
);
568 mProviders
.AppendObject(provider
);
572 // we should move these providers outside of this file! dft
574 #ifdef WINCE_WINDOWS_MOBILE
575 provider
= new WinMobileLocationProvider();
577 mProviders
.AppendObject(provider
);
580 #ifdef MOZ_MAEMO_LIBLOCATION
581 provider
= new MaemoLocationProvider();
583 mProviders
.AppendObject(provider
);
587 provider
= new AndroidLocationProvider();
589 mProviders
.AppendObject(provider
);
594 nsGeolocationService::~nsGeolocationService()
599 nsGeolocationService::Observe(nsISupports
* aSubject
,
601 const PRUnichar
* aData
)
603 if (!strcmp("quit-application", aTopic
))
605 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
607 obs
->RemoveObserver(this, "quit-application");
610 for (PRUint32 i
= 0; i
< mGeolocators
.Length(); i
++)
611 mGeolocators
[i
]->Shutdown();
618 if (!strcmp("timer-callback", aTopic
))
620 // decide if we can close down the service.
621 for (PRUint32 i
= 0; i
< mGeolocators
.Length(); i
++)
622 if (mGeolocators
[i
]->HasActiveCallbacks())
624 SetDisconnectTimer();
634 return NS_ERROR_FAILURE
;
638 nsGeolocationService::Update(nsIDOMGeoPosition
*aSomewhere
)
640 // here we have to determine this aSomewhere is a "better"
641 // position than any previously recv'ed.
643 if (!IsBetterPosition(aSomewhere
))
646 SetCachedPosition(aSomewhere
);
648 for (PRUint32 i
= 0; i
< mGeolocators
.Length(); i
++)
649 mGeolocators
[i
]->Update(aSomewhere
);
654 nsGeolocationService::IsBetterPosition(nsIDOMGeoPosition
*aSomewhere
)
659 nsRefPtr
<nsGeolocationService
> geoService
= nsGeolocationService::GetInstance();
663 nsCOMPtr
<nsIDOMGeoPosition
> lastPosition
= geoService
->GetCachedPosition();
668 DOMTimeStamp oldTime
;
669 rv
= lastPosition
->GetTimestamp(&oldTime
);
670 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
672 nsCOMPtr
<nsIDOMGeoPositionCoords
> coords
;
673 lastPosition
->GetCoords(getter_AddRefs(coords
));
678 rv
= coords
->GetAccuracy(&oldAccuracy
);
679 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
681 double oldLat
, oldLon
;
682 rv
= coords
->GetLongitude(&oldLon
);
683 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
685 rv
= coords
->GetLatitude(&oldLat
);
686 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
689 DOMTimeStamp newTime
;
690 rv
= aSomewhere
->GetTimestamp(&newTime
);
691 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
693 aSomewhere
->GetCoords(getter_AddRefs(coords
));
698 rv
= coords
->GetAccuracy(&newAccuracy
);
699 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
701 double newLat
, newLon
;
702 rv
= coords
->GetLongitude(&newLon
);
703 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
705 rv
= coords
->GetLatitude(&newLat
);
706 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
708 // check to see if there has been a large movement
709 // Use spherical law of cosines to calculate difference
710 // Not quite as correct as the Haversine but simpler and cheaper
711 double radsInDeg
= 3.14159265 / 180.0;
713 double rNewLat
= newLat
* radsInDeg
;
714 double rNewLon
= newLon
* radsInDeg
;
715 double rOldLat
= oldLat
* radsInDeg
;
716 double rOldLon
= oldLon
* radsInDeg
;
718 // WGS84 equatorial radius of earth = 6378137m
719 double delta
= acos( (sin(rNewLat
) * sin(rOldLat
)) + (cos(rNewLat
) * cos(rOldLat
) * cos(rOldLon
- rNewLon
)) ) * 6378137;
721 // The threshold is when the distance between the two positions exceeds the
722 // worse (larger value) of the two accuracies.
723 double max_accuracy
= NS_MAX(oldAccuracy
, newAccuracy
);
724 if (delta
> max_accuracy
)
727 // check to see if the aSomewhere position is more accurate
728 if (oldAccuracy
>= newAccuracy
)
735 nsGeolocationService::SetCachedPosition(nsIDOMGeoPosition
* aPosition
)
737 mLastPosition
= aPosition
;
741 nsGeolocationService::GetCachedPosition()
743 return mLastPosition
;
747 nsGeolocationService::HasGeolocationProvider()
749 return mProviders
.Count() > 0;
753 nsGeolocationService::StartDevice()
756 return NS_ERROR_NOT_AVAILABLE
;
758 if (!HasGeolocationProvider())
759 return NS_ERROR_NOT_AVAILABLE
;
761 // if we have one, start it up.
764 nsresult rv
= NS_ERROR_NOT_AVAILABLE
;
765 for (PRUint32 i
= mProviders
.Count() - 1; i
!= PRUint32(-1); --i
) {
766 // If any provder gets started without error, go ahead
767 // and proceed without error
768 nsresult temp
= mProviders
[i
]->Startup();
769 if (NS_SUCCEEDED(temp
)) {
772 mProviders
[i
]->Watch(this);
777 return NS_ERROR_NOT_AVAILABLE
;
779 // we do not want to keep the geolocation devices online
780 // indefinitely. Close them down after a reasonable period of
782 SetDisconnectTimer();
788 nsGeolocationService::SetDisconnectTimer()
790 if (!mDisconnectTimer
)
791 mDisconnectTimer
= do_CreateInstance("@mozilla.org/timer;1");
793 mDisconnectTimer
->Cancel();
795 mDisconnectTimer
->Init(this,
797 nsITimer::TYPE_ONE_SHOT
);
801 nsGeolocationService::StopDevice()
803 for (PRUint32 i
= mProviders
.Count() - 1; i
!= PRUint32(-1); --i
) {
804 mProviders
[i
]->Shutdown();
807 if(mDisconnectTimer
) {
808 mDisconnectTimer
->Cancel();
809 mDisconnectTimer
= nsnull
;
813 nsGeolocationService
* nsGeolocationService::gService
= nsnull
;
815 nsGeolocationService
*
816 nsGeolocationService::GetInstance()
818 if (!nsGeolocationService::gService
) {
819 nsGeolocationService::gService
= new nsGeolocationService();
820 NS_ASSERTION(nsGeolocationService::gService
, "null nsGeolocationService.");
822 if (nsGeolocationService::gService
) {
823 if (NS_FAILED(nsGeolocationService::gService
->Init())) {
824 delete nsGeolocationService::gService
;
825 nsGeolocationService::gService
= nsnull
;
829 return nsGeolocationService::gService
;
832 nsGeolocationService
*
833 nsGeolocationService::GetGeolocationService()
835 nsGeolocationService
* inst
= nsGeolocationService::GetInstance();
841 nsGeolocationService::AddLocator(nsGeolocation
* aLocator
)
843 mGeolocators
.AppendElement(aLocator
);
847 nsGeolocationService::RemoveLocator(nsGeolocation
* aLocator
)
849 mGeolocators
.RemoveElement(aLocator
);
852 ////////////////////////////////////////////////////
854 ////////////////////////////////////////////////////
856 DOMCI_DATA(GeoGeolocation
, nsGeolocation
)
858 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGeolocation
)
859 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDOMGeoGeolocation
)
860 NS_INTERFACE_MAP_ENTRY(nsIDOMGeoGeolocation
)
861 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(GeoGeolocation
)
864 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocation
)
865 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocation
)
866 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGeolocation
)
868 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGeolocation
)
869 tmp
->mPendingCallbacks
.Clear();
870 tmp
->mWatchingCallbacks
.Clear();
871 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
873 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGeolocation
)
875 for (i
= 0; i
< tmp
->mPendingCallbacks
.Length(); ++i
)
876 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mPendingCallbacks
[i
], nsIContentPermissionRequest
)
878 for (i
= 0; i
< tmp
->mWatchingCallbacks
.Length(); ++i
)
879 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mWatchingCallbacks
[i
], nsIContentPermissionRequest
)
880 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
882 nsGeolocation::nsGeolocation()
886 nsGeolocation::~nsGeolocation()
893 nsGeolocation::Init(nsIDOMWindow
* aContentDom
)
895 // Remember the window
897 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(aContentDom
);
899 return NS_ERROR_FAILURE
;
901 mOwner
= do_GetWeakReference(window
->GetCurrentInnerWindow());
903 return NS_ERROR_FAILURE
;
905 // Grab the uri of the document
906 nsCOMPtr
<nsIDOMDocument
> domdoc
;
907 aContentDom
->GetDocument(getter_AddRefs(domdoc
));
908 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(domdoc
);
910 return NS_ERROR_FAILURE
;
912 doc
->NodePrincipal()->GetURI(getter_AddRefs(mURI
));
915 return NS_ERROR_FAILURE
;
918 // If no aContentDom was passed into us, we are being used
919 // by chrome/c++ and have no mOwner, no mURI, and no need
921 mService
= nsGeolocationService::GetInstance();
923 mService
->AddLocator(this);
929 nsGeolocation::Shutdown()
931 // Shutdown and release all callbacks
932 for (PRUint32 i
= 0; i
< mPendingCallbacks
.Length(); i
++)
933 mPendingCallbacks
[i
]->Shutdown();
934 mPendingCallbacks
.Clear();
936 for (PRUint32 i
= 0; i
< mWatchingCallbacks
.Length(); i
++)
937 mWatchingCallbacks
[i
]->Shutdown();
938 mWatchingCallbacks
.Clear();
941 mService
->RemoveLocator(this);
948 nsGeolocation::HasActiveCallbacks()
950 return mWatchingCallbacks
.Length() != 0;
954 nsGeolocation::RemoveRequest(nsGeolocationRequest
* aRequest
)
956 mPendingCallbacks
.RemoveElement(aRequest
);
958 // if it is in the mWatchingCallbacks, we can't do much
959 // since we passed back the position in the array to who
960 // ever called WatchPosition() and we do not want to mess
961 // around with the ordering of the array. Instead, just
962 // mark the request as "cleared".
964 aRequest
->MarkCleared();
968 nsGeolocation::Update(nsIDOMGeoPosition
*aSomewhere
)
970 if (!WindowOwnerStillExists())
973 for (PRUint32 i
= 0; i
< mPendingCallbacks
.Length(); i
++) {
974 nsCOMPtr
<nsIRunnable
> ev
= new RequestSendLocationEvent(aSomewhere
,
975 mPendingCallbacks
[i
]);
976 NS_DispatchToMainThread(ev
);
978 mPendingCallbacks
.Clear();
980 // notify everyone that is watching
981 for (PRUint32 i
= 0; i
< mWatchingCallbacks
.Length(); i
++) {
982 nsCOMPtr
<nsIRunnable
> ev
= new RequestSendLocationEvent(aSomewhere
, mWatchingCallbacks
[i
]);
983 NS_DispatchToMainThread(ev
);
988 nsGeolocation::GetCurrentPosition(nsIDOMGeoPositionCallback
*callback
,
989 nsIDOMGeoPositionErrorCallback
*errorCallback
,
990 nsIDOMGeoPositionOptions
*options
)
992 NS_ENSURE_ARG_POINTER(callback
);
995 return NS_ERROR_NOT_AVAILABLE
;
997 if (mPendingCallbacks
.Length() > MAX_GEO_REQUESTS_PER_WINDOW
)
998 return NS_ERROR_NOT_AVAILABLE
;
1000 nsRefPtr
<nsGeolocationRequest
> request
= new nsGeolocationRequest(this, callback
, errorCallback
, options
);
1002 return NS_ERROR_OUT_OF_MEMORY
;
1004 if (NS_FAILED(request
->Init()))
1005 return NS_ERROR_FAILURE
; // this as OKAY. not sure why we wouldn't throw. xxx dft
1008 RegisterRequestWithPrompt(request
);
1009 mPendingCallbacks
.AppendElement(request
);
1013 if (!nsContentUtils::IsCallerChrome())
1014 return NS_ERROR_FAILURE
;
1016 mPendingCallbacks
.AppendElement(request
);
1018 nsCOMPtr
<nsIRunnable
> ev
= new RequestAllowEvent(true, request
);
1019 NS_DispatchToMainThread(ev
);
1025 nsGeolocation::WatchPosition(nsIDOMGeoPositionCallback
*callback
,
1026 nsIDOMGeoPositionErrorCallback
*errorCallback
,
1027 nsIDOMGeoPositionOptions
*options
,
1028 PRInt32
*_retval NS_OUTPARAM
)
1031 NS_ENSURE_ARG_POINTER(callback
);
1034 return NS_ERROR_NOT_AVAILABLE
;
1036 if (mPendingCallbacks
.Length() > MAX_GEO_REQUESTS_PER_WINDOW
)
1037 return NS_ERROR_NOT_AVAILABLE
;
1039 nsRefPtr
<nsGeolocationRequest
> request
= new nsGeolocationRequest(this, callback
, errorCallback
, options
);
1041 return NS_ERROR_OUT_OF_MEMORY
;
1043 if (NS_FAILED(request
->Init()))
1044 return NS_ERROR_FAILURE
; // this as OKAY. not sure why we wouldn't throw. xxx dft
1047 RegisterRequestWithPrompt(request
);
1049 // need to hand back an index/reference.
1050 mWatchingCallbacks
.AppendElement(request
);
1051 *_retval
= mWatchingCallbacks
.Length() - 1;
1056 if (!nsContentUtils::IsCallerChrome())
1057 return NS_ERROR_FAILURE
;
1061 // need to hand back an index/reference.
1062 mWatchingCallbacks
.AppendElement(request
);
1063 *_retval
= mWatchingCallbacks
.Length() - 1;
1069 nsGeolocation::ClearWatch(PRInt32 aWatchId
)
1071 PRUint32 count
= mWatchingCallbacks
.Length();
1072 if (aWatchId
< 0 || count
== 0 || PRUint32(aWatchId
) > count
)
1075 mWatchingCallbacks
[aWatchId
]->MarkCleared();
1080 nsGeolocation::WindowOwnerStillExists()
1082 // an owner was never set when nsGeolocation
1083 // was created, which means that this object
1084 // is being used without a window.
1085 if (mOwner
== nsnull
)
1088 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryReferent(mOwner
);
1092 PRBool closed
= PR_FALSE
;
1093 window
->GetClosed(&closed
);
1097 nsPIDOMWindow
* outer
= window
->GetOuterWindow();
1098 if (!outer
|| outer
->GetCurrentInnerWindow() != window
)
1106 nsGeolocation::RegisterRequestWithPrompt(nsGeolocationRequest
* request
)
1109 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
1110 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryReferent(mOwner
);
1114 // because owner implements nsITabChild, we can assume that it is
1115 // the one and only TabChild.
1116 TabChild
* child
= GetTabChildFrom(window
->GetDocShell());
1118 // Retain a reference so the object isn't deleted without IPDL's knowledge.
1119 // Corresponding release occurs in DeallocPContentPermissionRequest.
1122 nsCString type
= NS_LITERAL_CSTRING("geolocation");
1123 child
->SendPContentPermissionRequestConstructor(request
, type
, IPC::URI(mURI
));
1125 request
->Sendprompt();
1130 if (nsContentUtils::GetBoolPref("geo.prompt.testing", PR_FALSE
))
1132 nsCOMPtr
<nsIRunnable
> ev
= new RequestAllowEvent(nsContentUtils::GetBoolPref("geo.prompt.testing.allow", PR_FALSE
), request
);
1133 NS_DispatchToMainThread(ev
);
1137 nsCOMPtr
<nsIRunnable
> ev
= new RequestPromptEvent(request
);
1138 NS_DispatchToMainThread(ev
);
1141 #if !defined(WINCE_WINDOWS_MOBILE) && !defined(MOZ_MAEMO_LIBLOCATION) && !defined(ANDROID)
1142 DOMCI_DATA(GeoPositionCoords
, void)
1143 DOMCI_DATA(GeoPosition
, void)
1147 nsGeolocationRequestProxy::nsGeolocationRequestProxy()
1149 MOZ_COUNT_CTOR(nsGeolocationRequestProxy
);
1152 nsGeolocationRequestProxy::~nsGeolocationRequestProxy()
1154 MOZ_COUNT_DTOR(nsGeolocationRequestProxy
);
1158 nsGeolocationRequestProxy::Init(mozilla::dom::GeolocationRequestParent
* parent
)
1160 NS_ASSERTION(parent
, "null parent");
1163 nsCOMPtr
<nsIContentPermissionPrompt
> prompt
= do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID
);
1165 return NS_ERROR_FAILURE
;
1168 (void) prompt
->Prompt(this);
1172 NS_IMPL_ISUPPORTS1(nsGeolocationRequestProxy
, nsIContentPermissionRequest
);
1175 nsGeolocationRequestProxy::GetType(nsACString
& aType
)
1177 aType
= "geolocation";
1182 nsGeolocationRequestProxy::GetWindow(nsIDOMWindow
* *aRequestingWindow
)
1184 NS_ENSURE_ARG_POINTER(aRequestingWindow
);
1185 *aRequestingWindow
= nsnull
;
1190 nsGeolocationRequestProxy::GetUri(nsIURI
* *aRequestingURI
)
1192 NS_ENSURE_ARG_POINTER(aRequestingURI
);
1193 NS_ASSERTION(mParent
, "No parent for request");
1195 NS_ADDREF(*aRequestingURI
= mParent
->mURI
);
1200 nsGeolocationRequestProxy::GetElement(nsIDOMElement
* *aRequestingElement
)
1202 NS_ENSURE_ARG_POINTER(aRequestingElement
);
1203 NS_ASSERTION(mParent
&& mParent
->mElement
.get(), "No parent for request");
1204 NS_ADDREF(*aRequestingElement
= mParent
->mElement
);
1209 nsGeolocationRequestProxy::Cancel()
1211 NS_ASSERTION(mParent
, "No parent for request");
1212 unused
<< mozilla::dom::GeolocationRequestParent::Send__delete__(mParent
, false);
1218 nsGeolocationRequestProxy::Allow()
1220 NS_ASSERTION(mParent
, "No parent for request");
1221 unused
<< mozilla::dom::GeolocationRequestParent::Send__delete__(mParent
, true);
1229 GeolocationRequestParent::GeolocationRequestParent(nsIDOMElement
*element
, const IPC::URI
& uri
)
1231 MOZ_COUNT_CTOR(GeolocationRequestParent
);
1237 GeolocationRequestParent::~GeolocationRequestParent()
1239 MOZ_COUNT_DTOR(GeolocationRequestParent
);
1243 GeolocationRequestParent::Recvprompt()
1245 mProxy
= new nsGeolocationRequestProxy();
1246 NS_ASSERTION(mProxy
, "Alloc of request proxy failed");
1247 if (NS_FAILED(mProxy
->Init(this)))
1253 } // namespace mozilla