Bug 1216148 - Handle how geolocation acts when the app's visibility changes. r=kchen.

Add the wake lock api to geolocation.
If your app holds a lock, you can continue use geolocation service when your app is invisible.
Otherwise, your invisible app can't get any updated location.
This commit is contained in:
ywu 2016-01-12 00:33:00 +01:00
parent f86b489302
commit d75819d824
2 changed files with 102 additions and 5 deletions

View File

@ -20,15 +20,20 @@
#include "nsContentUtils.h"
#include "nsContentPermissionHelper.h"
#include "nsIDocument.h"
#include "nsIDOMEvent.h"
#include "nsIObserverService.h"
#include "nsPIDOMWindow.h"
#include "nsThreadUtils.h"
#include "mozilla/HalWakeLock.h"
#include "mozilla/Hal.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
#include "mozilla/Preferences.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/SettingChangeNotificationBinding.h"
#include "mozilla/dom/WakeLock.h"
#include "nsJSUtils.h"
#include "prdtoa.h"
@ -66,6 +71,7 @@ class nsIPrincipal;
using mozilla::Unused; // <snicker>
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::hal;
class nsGeolocationRequest final
: public nsIContentPermissionRequest
@ -499,6 +505,10 @@ nsGeolocationRequest::Allow(JS::HandleValue aChoices)
}
}
if (mLocator->ContainsRequest(this)) {
return NS_OK;
}
if (mIsWatchPositionRequest || !canUseCache) {
// let the locator know we're pending
// we will now be owned by the locator
@ -1044,6 +1054,16 @@ nsGeolocationService::StartDevice(nsIPrincipal *aPrincipal)
return NS_OK;
}
void
nsGeolocationService::StopDisconnectTimer()
{
if (mDisconnectTimer) {
mDisconnectTimer->Cancel();
mDisconnectTimer = nullptr;
}
}
void
nsGeolocationService::SetDisconnectTimer()
{
@ -1096,10 +1116,7 @@ nsGeolocationService::UpdateAccuracy(bool aForceHigh)
void
nsGeolocationService::StopDevice()
{
if(mDisconnectTimer) {
mDisconnectTimer->Cancel();
mDisconnectTimer = nullptr;
}
StopDisconnectTimer();
if (XRE_IsContentProcess()) {
ContentChild* cpc = ContentChild::GetSingleton();
@ -1209,6 +1226,14 @@ Geolocation::Init(nsIDOMWindow* aContentDom)
}
mPrincipal = doc->NodePrincipal();
if (XRE_IsContentProcess()) {
doc->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
/* listener */ this,
/* use capture */ true,
/* wants untrusted */ false);
}
}
// If no aContentDom was passed into us, we are being used
@ -1221,6 +1246,58 @@ Geolocation::Init(nsIDOMWindow* aContentDom)
return NS_OK;
}
bool
Geolocation::ContainsRequest(nsGeolocationRequest* aRequest)
{
if (aRequest->IsWatch()) {
if (mWatchingCallbacks.Contains(aRequest)) {
return true;
}
} else {
if (mPendingCallbacks.Contains(aRequest)) {
return true;
}
}
return false;
}
NS_IMETHODIMP
Geolocation::HandleEvent(nsIDOMEvent* aEvent)
{
nsAutoString type;
aEvent->GetType(type);
if (!type.EqualsLiteral("visibilitychange")) {
return NS_OK;
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
MOZ_ASSERT(doc);
if (doc->Hidden()) {
WakeLockInformation info;
GetWakeLockInfo(NS_LITERAL_STRING("gps"), &info);
MOZ_ASSERT(XRE_IsContentProcess());
ContentChild* cpc = ContentChild::GetSingleton();
if (!info.lockingProcesses().Contains(cpc->GetID())) {
cpc->SendRemoveGeolocationListener();
mService->StopDisconnectTimer();
}
} else {
mService->SetDisconnectTimer();
for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) {
mWatchingCallbacks[i]->Allow(JS::UndefinedHandleValue);
}
for (uint32_t i = 0, length = mPendingCallbacks.Length(); i < length; ++i) {
mPendingCallbacks[i]->Allow(JS::UndefinedHandleValue);
}
}
return NS_OK;
}
void
Geolocation::Shutdown()
{
@ -1228,6 +1305,18 @@ Geolocation::Shutdown()
mPendingCallbacks.Clear();
mWatchingCallbacks.Clear();
if (XRE_IsContentProcess()) {
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mOwner);
if (window) {
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (doc) {
doc->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
this,
/* useCapture = */ true);
}
}
}
if (mService) {
mService->RemoveLocator(this);
mService->UpdateAccuracy();

View File

@ -22,6 +22,7 @@
#include "nsCycleCollectionParticipant.h"
#include "nsGeoPosition.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMGeoGeolocation.h"
#include "nsIDOMGeoPosition.h"
#include "nsIDOMGeoPositionError.h"
@ -91,6 +92,7 @@ public:
// create, or reinitalize the callback timer
void SetDisconnectTimer();
void StopDisconnectTimer();
// Update the accuracy and notify the provider if changed
void UpdateAccuracy(bool aForceHigh = false);
@ -128,7 +130,8 @@ namespace dom {
*/
class Geolocation final : public nsIDOMGeoGeolocation,
public nsIGeolocationUpdate,
public nsWrapperCache
public nsWrapperCache,
public nsIDOMEventListener
{
public:
@ -138,6 +141,8 @@ public:
NS_DECL_NSIGEOLOCATIONUPDATE
NS_DECL_NSIDOMGEOGEOLOCATION
NS_DECL_NSIDOMEVENTLISTENER
Geolocation();
nsresult Init(nsIDOMWindow* contentDom=nullptr);
@ -154,6 +159,9 @@ public:
// Register an allowed request
void NotifyAllowedRequest(nsGeolocationRequest* aRequest);
// Check if callbacks arrays already contain this request
bool ContainsRequest(nsGeolocationRequest* aRequest);
// Remove request from all callbacks arrays
void RemoveRequest(nsGeolocationRequest* request);