WakeLock.cpp (4937B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "WakeLock.h" 8 9 #include "mozilla/Hal.h" 10 #include "mozilla/HalWakeLock.h" 11 #include "mozilla/dom/ContentParent.h" 12 #include "mozilla/dom/Document.h" 13 #include "mozilla/dom/Event.h" // for Event 14 #include "nsError.h" 15 #include "nsIPropertyBag2.h" 16 #include "nsPIDOMWindow.h" 17 18 using namespace mozilla::hal; 19 20 namespace mozilla::dom { 21 22 NS_INTERFACE_MAP_BEGIN(WakeLock) 23 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener) 24 NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) 25 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 26 NS_INTERFACE_MAP_ENTRY(nsIWakeLock) 27 NS_INTERFACE_MAP_END 28 29 NS_IMPL_ADDREF(WakeLock) 30 NS_IMPL_RELEASE(WakeLock) 31 32 WakeLock::~WakeLock() { 33 DoUnlock(); 34 DetachEventListener(); 35 } 36 37 nsresult WakeLock::Init(const nsAString& aTopic, nsPIDOMWindowInner* aWindow) { 38 // Don't Init() a WakeLock twice. 39 MOZ_ASSERT(mTopic.IsEmpty()); 40 41 if (aTopic.IsEmpty()) { 42 return NS_ERROR_INVALID_ARG; 43 } 44 45 mTopic.Assign(aTopic); 46 47 mWindow = do_GetWeakReference(aWindow); 48 49 /** 50 * Null windows are allowed. A wake lock without associated window 51 * is always considered invisible. 52 */ 53 if (aWindow) { 54 nsCOMPtr<Document> doc = aWindow->GetExtantDoc(); 55 NS_ENSURE_STATE(doc); 56 mHidden = doc->Hidden(); 57 } 58 59 AttachEventListener(); 60 DoLock(); 61 62 return NS_OK; 63 } 64 65 void WakeLock::DoLock() { 66 if (!mLocked) { 67 // Change the flag immediately to prevent recursive reentering 68 mLocked = true; 69 70 hal::ModifyWakeLock( 71 mTopic, hal::WAKE_LOCK_ADD_ONE, 72 mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_NO_CHANGE); 73 } 74 } 75 76 void WakeLock::DoUnlock() { 77 if (mLocked) { 78 // Change the flag immediately to prevent recursive reentering 79 mLocked = false; 80 81 hal::ModifyWakeLock( 82 mTopic, hal::WAKE_LOCK_REMOVE_ONE, 83 mHidden ? hal::WAKE_LOCK_REMOVE_ONE : hal::WAKE_LOCK_NO_CHANGE); 84 } 85 } 86 87 void WakeLock::AttachEventListener() { 88 if (nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow)) { 89 nsCOMPtr<Document> doc = window->GetExtantDoc(); 90 if (doc) { 91 doc->AddSystemEventListener(u"visibilitychange"_ns, this, 92 /* useCapture = */ true, 93 /* wantsUntrusted = */ false); 94 95 nsCOMPtr<EventTarget> target = do_QueryInterface(window); 96 target->AddSystemEventListener(u"pagehide"_ns, this, 97 /* useCapture = */ true, 98 /* wantsUntrusted = */ false); 99 target->AddSystemEventListener(u"pageshow"_ns, this, 100 /* useCapture = */ true, 101 /* wantsUntrusted = */ false); 102 } 103 } 104 } 105 106 void WakeLock::DetachEventListener() { 107 if (nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow)) { 108 nsCOMPtr<Document> doc = window->GetExtantDoc(); 109 if (doc) { 110 doc->RemoveSystemEventListener(u"visibilitychange"_ns, this, 111 /* useCapture = */ true); 112 nsCOMPtr<EventTarget> target = do_QueryInterface(window); 113 target->RemoveSystemEventListener(u"pagehide"_ns, this, 114 /* useCapture = */ true); 115 target->RemoveSystemEventListener(u"pageshow"_ns, this, 116 /* useCapture = */ true); 117 } 118 } 119 } 120 121 void WakeLock::Unlock(ErrorResult& aRv) { 122 /* 123 * We throw NS_ERROR_DOM_INVALID_STATE_ERR on double unlock. 124 */ 125 if (!mLocked) { 126 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 127 return; 128 } 129 130 DoUnlock(); 131 DetachEventListener(); 132 } 133 134 void WakeLock::GetTopic(nsAString& aTopic) { aTopic.Assign(mTopic); } 135 136 NS_IMETHODIMP 137 WakeLock::HandleEvent(Event* aEvent) { 138 nsAutoString type; 139 aEvent->GetType(type); 140 141 if (type.EqualsLiteral("visibilitychange")) { 142 nsCOMPtr<Document> doc = do_QueryInterface(aEvent->GetTarget()); 143 NS_ENSURE_STATE(doc); 144 145 bool oldHidden = mHidden; 146 mHidden = doc->Hidden(); 147 148 if (mLocked && oldHidden != mHidden) { 149 hal::ModifyWakeLock( 150 mTopic, hal::WAKE_LOCK_NO_CHANGE, 151 mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE); 152 } 153 154 return NS_OK; 155 } 156 157 if (type.EqualsLiteral("pagehide")) { 158 DoUnlock(); 159 return NS_OK; 160 } 161 162 if (type.EqualsLiteral("pageshow")) { 163 DoLock(); 164 return NS_OK; 165 } 166 167 return NS_OK; 168 } 169 170 NS_IMETHODIMP 171 WakeLock::Unlock() { 172 ErrorResult error; 173 Unlock(error); 174 return error.StealNSResult(); 175 } 176 177 nsPIDOMWindowInner* WakeLock::GetParentObject() const { 178 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mWindow); 179 return window; 180 } 181 182 } // namespace mozilla::dom