Skip to content

Commit 1e4d05e

Browse files
committed
Bug 1697647 - Add screen orientation lock api r=ipc-reviewers,mccr8,agi,smaug,jonalmeida
Previously, the screenOrientation.lock API was for Fennec and not supported for Fenix and multi-process use. The overall idea is to now allow apps to use the API through a delegate and make asynchronous calls to LockDeviceOrientation. This required replacing the existing code that returned a default false bool to calls that perform the requested orientation change and instead return a promise that contained either an allow or deny value. Returning a promise instead of a bool involved changing the API calls from the C++ side to Java. The new general control flow of screenOrientation lock follows: an app calls C++ ScreenOrientation.lock() which eventually dispatches LockOrientationTask to resolve the pending orientation promise. Hal.cpp sends an IPC call to the content process and RecvLockScreenOrientation retrieves the current instance of geckoRuntime and calls the java side LockScreenOrientation. Apps must create a delegate and override onOrientationLock to set the requested orientation. In geckoview's testing, this is done with the android API setRequestedOrientation. Once a device orientation change has been triggered, native OnOrientationChange calls to NotifyScreenConfigurationChange, which notifies all observers and dispatches a change event to resolve the pending orientation promise. Testing: I used a demo on the GeckoView Example (https://usefulangle.com/demos/105/screen.html) to test locking to landscape orientation. This required a change to the GVE to show the app from recreating the whole thing on orientation change. In the example AndroidManifest xml file, `orientation` prevents restart when orientation changes. The Junit/Kotlin tests were to verify that the expected orientation delegate was called with the expected new orientation value, in an orientation change, if the new orientation was the same as the current, and if the pre-lock conditions such as being fullscreen were not met. A static preference `dom.screenorientation.allow-lock` was added to the dom group, since it affects the ui dom) and is currently turned off. C++ can access it through its mirrored variable dom_screenorientation_allow_lock (same name but with underscores). The junit tests turn the preference on and test the lock feature. Reference: Orientation constant values: C++ 1 ScreenOrientation_PortraitPrimary); - vertical with button at bottom 2 ScreenOrientation_PortraitSecondary); - vertical with button at top 4 ScreenOrientation_LandscapePrimary); - horizational w button right 8 ScreenOrientation_LandscapeSecondary); - horization button left 16 ScreenOrientation_Default); Java 1 GeckoScreenOrientation.ScreenOrientation.PORTRAIT_PRIMARY.value 2 GeckoScreenOrientation.ScreenOrientation.PORTRAIT_SECONDARY.value 4 GeckoScreenOrientation.ScreenOrientation.LANDSCAPE_PRIMARY.value 8 GeckoScreenOrientation.ScreenOrientation.LANDSCAPE_SECONDARY.value Java public API 0 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE 1 Activitynfo.SCREEN_ORIENTATION_PORTRAIT Android 1 ORIENTATION_PORTRAIT 2 ORIENTATION_LANDSCAPE Differential Revision: https://phabricator.services.mozilla.com/D129427
1 parent 13de1c3 commit 1e4d05e

File tree

24 files changed

+433
-132
lines changed

24 files changed

+433
-132
lines changed

dom/base/ScreenOrientation.cpp

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "mozilla/dom/ContentChild.h"
1919
#include "mozilla/dom/Event.h"
2020
#include "mozilla/dom/Promise.h"
21+
#include "mozilla/StaticPrefs_browser.h"
2122
#include "nsContentUtils.h"
2223

2324
using namespace mozilla;
@@ -158,8 +159,11 @@ bool ScreenOrientation::LockOrientationTask::OrientationLockContains(
158159

159160
NS_IMETHODIMP
160161
ScreenOrientation::LockOrientationTask::Run() {
161-
// Step to lock the orientation as defined in the spec.
162+
if (!mPromise) {
163+
return NS_OK;
164+
}
162165

166+
// Step to lock the orientation as defined in the spec.
163167
if (mDocument->GetOrientationPendingPromise() != mPromise) {
164168
// The document's pending promise is not associated with this task
165169
// to lock orientation. There has since been another request to
@@ -182,19 +186,29 @@ ScreenOrientation::LockOrientationTask::Run() {
182186
return NS_OK;
183187
}
184188

185-
ErrorResult rv;
186-
bool result = mScreenOrientation->LockDeviceOrientation(mOrientationLock,
187-
mIsFullscreen, rv);
188-
if (NS_WARN_IF(rv.Failed())) {
189-
return rv.StealNSResult();
190-
}
189+
RefPtr<MozPromise<bool, bool, false>> lockOrientationPromise =
190+
mScreenOrientation->LockDeviceOrientation(mOrientationLock,
191+
mIsFullscreen);
191192

192-
if (NS_WARN_IF(!result)) {
193+
if (NS_WARN_IF(!lockOrientationPromise)) {
193194
mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
194195
mDocument->ClearOrientationPendingPromise();
195196
return NS_OK;
196197
}
197198

199+
lockOrientationPromise->Then(
200+
GetCurrentSerialEventTarget(), __func__,
201+
[self = RefPtr{this}](
202+
const mozilla::MozPromise<bool, bool, false>::ResolveOrRejectValue&
203+
aValue) {
204+
if (aValue.IsResolve()) {
205+
return NS_OK;
206+
}
207+
self->mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
208+
self->mDocument->ClearOrientationPendingPromise();
209+
return NS_OK;
210+
});
211+
198212
BrowsingContext* bc = mDocument->GetBrowsingContext();
199213
if (OrientationLockContains(bc->GetCurrentOrientationType()) ||
200214
(mOrientationLock == hal::eScreenOrientation_Default &&
@@ -304,6 +318,12 @@ already_AddRefed<Promise> ScreenOrientation::LockInternal(
304318
p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
305319
return p.forget();
306320
#else
321+
// Bypass locking screen orientation if preference is false
322+
if (!StaticPrefs::dom_screenorientation_allow_lock()) {
323+
p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
324+
return p.forget();
325+
}
326+
307327
LockPermission perm = GetLockOrientationPermission(true);
308328
if (perm == LOCK_DENIED) {
309329
p->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
@@ -342,11 +362,10 @@ already_AddRefed<Promise> ScreenOrientation::LockInternal(
342362
#endif
343363
}
344364

345-
bool ScreenOrientation::LockDeviceOrientation(
346-
hal::ScreenOrientation aOrientation, bool aIsFullscreen, ErrorResult& aRv) {
365+
RefPtr<MozPromise<bool, bool, false>> ScreenOrientation::LockDeviceOrientation(
366+
hal::ScreenOrientation aOrientation, bool aIsFullscreen) {
347367
if (!GetOwner()) {
348-
aRv.Throw(NS_ERROR_UNEXPECTED);
349-
return false;
368+
return MozPromise<bool, bool, false>::CreateAndReject(false, __func__);
350369
}
351370

352371
nsCOMPtr<EventTarget> target = GetOwner()->GetDoc();
@@ -355,11 +374,7 @@ bool ScreenOrientation::LockDeviceOrientation(
355374
// This needs to be done before LockScreenOrientation call to make sure
356375
// the locking can be unlocked.
357376
if (aIsFullscreen && !target) {
358-
return false;
359-
}
360-
361-
if (NS_WARN_IF(!hal::LockScreenOrientation(aOrientation))) {
362-
return false;
377+
return MozPromise<bool, bool, false>::CreateAndReject(false, __func__);
363378
}
364379

365380
// We are fullscreen and lock has been accepted.
@@ -368,15 +383,21 @@ bool ScreenOrientation::LockDeviceOrientation(
368383
mFullscreenListener = new FullscreenEventListener();
369384
}
370385

371-
aRv = target->AddSystemEventListener(u"fullscreenchange"_ns,
372-
mFullscreenListener,
373-
/* useCapture = */ true);
374-
if (NS_WARN_IF(aRv.Failed())) {
375-
return false;
386+
nsresult rv = target->AddSystemEventListener(u"fullscreenchange"_ns,
387+
mFullscreenListener,
388+
/* aUseCapture = */ true);
389+
if (NS_WARN_IF(NS_FAILED(rv))) {
390+
return MozPromise<bool, bool, false>::CreateAndReject(false, __func__);
376391
}
377392
}
378393

379-
return true;
394+
RefPtr<MozPromise<bool, bool, false>> halPromise =
395+
hal::LockScreenOrientation(aOrientation);
396+
if (halPromise == nullptr) {
397+
return MozPromise<bool, bool, false>::CreateAndReject(false, __func__);
398+
}
399+
400+
return halPromise;
380401
}
381402

382403
void ScreenOrientation::Unlock(ErrorResult& aRv) {
@@ -521,7 +542,7 @@ void ScreenOrientation::Notify(const hal::ScreenConfiguration& aConfiguration) {
521542
if (doc->Hidden() && !mVisibleListener) {
522543
mVisibleListener = new VisibleEventListener();
523544
rv = doc->AddSystemEventListener(u"visibilitychange"_ns, mVisibleListener,
524-
/* useCapture = */ true);
545+
/* aUseCapture = */ true);
525546
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddSystemEventListener failed");
526547
return;
527548
}
@@ -541,8 +562,14 @@ void ScreenOrientation::UpdateActiveOrientationLock(
541562
if (aOrientation == hal::eScreenOrientation_None) {
542563
hal::UnlockScreenOrientation();
543564
} else {
544-
DebugOnly<bool> ok = hal::LockScreenOrientation(aOrientation);
545-
NS_WARNING_ASSERTION(ok, "hal::LockScreenOrientation failed");
565+
hal::LockScreenOrientation(aOrientation)
566+
->Then(
567+
GetMainThreadSerialEventTarget(), __func__,
568+
[](const mozilla::MozPromise<bool, bool,
569+
false>::ResolveOrRejectValue& aValue) {
570+
NS_WARNING_ASSERTION(aValue.IsResolve(),
571+
"hal::LockScreenOrientation failed");
572+
});
546573
}
547574
}
548575

dom/base/ScreenOrientation.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "mozilla/dom/BindingDeclarations.h"
1212
#include "mozilla/dom/ScreenOrientationBinding.h"
1313
#include "mozilla/HalScreenConfiguration.h"
14+
#include "mozilla/MozPromise.h"
1415

1516
class nsScreen;
1617

@@ -74,8 +75,8 @@ class ScreenOrientation final
7475

7576
// This method calls into the HAL to lock the device and sets
7677
// up listeners for full screen change.
77-
bool LockDeviceOrientation(hal::ScreenOrientation aOrientation,
78-
bool aIsFullscreen, ErrorResult& aRv);
78+
RefPtr<MozPromise<bool, bool, false>> LockDeviceOrientation(
79+
hal::ScreenOrientation aOrientation, bool aIsFullscreen);
7980

8081
// This method calls in to the HAL to unlock the device and removes
8182
// full screen change listener.

dom/base/nsScreen.cpp

Lines changed: 3 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -195,27 +195,6 @@ void nsScreen::GetMozOrientation(nsString& aOrientation,
195195
}
196196
}
197197

198-
static void UpdateDocShellOrientationLock(nsPIDOMWindowInner* aWindow,
199-
hal::ScreenOrientation aOrientation) {
200-
if (!aWindow) {
201-
return;
202-
}
203-
204-
nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
205-
if (!docShell) {
206-
return;
207-
}
208-
209-
RefPtr<BrowsingContext> bc = docShell->GetBrowsingContext();
210-
bc = bc ? bc->Top() : nullptr;
211-
if (!bc) {
212-
return;
213-
}
214-
215-
// Setting orientation lock on a discarded context has no effect.
216-
Unused << bc->SetOrientationLock(aOrientation);
217-
}
218-
219198
bool nsScreen::MozLockOrientation(const nsAString& aOrientation,
220199
ErrorResult& aRv) {
221200
nsString orientation(aOrientation);
@@ -227,62 +206,13 @@ bool nsScreen::MozLockOrientation(const nsAString& aOrientation,
227206
return MozLockOrientation(orientations, aRv);
228207
}
229208

209+
// This function is deprecated, use ScreenOrientation API instead.
230210
bool nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations,
231211
ErrorResult& aRv) {
232-
if (ShouldResistFingerprinting()) {
233-
return false;
234-
}
235-
hal::ScreenOrientation orientation = hal::eScreenOrientation_None;
236-
237-
for (uint32_t i = 0; i < aOrientations.Length(); ++i) {
238-
const nsString& item = aOrientations[i];
239-
240-
if (item.EqualsLiteral("portrait")) {
241-
orientation |= hal::eScreenOrientation_PortraitPrimary |
242-
hal::eScreenOrientation_PortraitSecondary;
243-
} else if (item.EqualsLiteral("portrait-primary")) {
244-
orientation |= hal::eScreenOrientation_PortraitPrimary;
245-
} else if (item.EqualsLiteral("portrait-secondary")) {
246-
orientation |= hal::eScreenOrientation_PortraitSecondary;
247-
} else if (item.EqualsLiteral("landscape")) {
248-
orientation |= hal::eScreenOrientation_LandscapePrimary |
249-
hal::eScreenOrientation_LandscapeSecondary;
250-
} else if (item.EqualsLiteral("landscape-primary")) {
251-
orientation |= hal::eScreenOrientation_LandscapePrimary;
252-
} else if (item.EqualsLiteral("landscape-secondary")) {
253-
orientation |= hal::eScreenOrientation_LandscapeSecondary;
254-
} else if (item.EqualsLiteral("default")) {
255-
orientation |= hal::eScreenOrientation_Default;
256-
} else {
257-
// If we don't recognize the token, we should just return 'false'
258-
// without throwing.
259-
return false;
260-
}
261-
}
262-
263-
switch (mScreenOrientation->GetLockOrientationPermission(false)) {
264-
case ScreenOrientation::LOCK_DENIED:
265-
return false;
266-
case ScreenOrientation::LOCK_ALLOWED:
267-
UpdateDocShellOrientationLock(GetOwner(), orientation);
268-
return mScreenOrientation->LockDeviceOrientation(orientation, false, aRv);
269-
case ScreenOrientation::FULLSCREEN_LOCK_ALLOWED:
270-
UpdateDocShellOrientationLock(GetOwner(), orientation);
271-
return mScreenOrientation->LockDeviceOrientation(orientation, true, aRv);
272-
}
273-
274-
// This is only for compilers that don't understand that the previous switch
275-
// will always return.
276-
MOZ_CRASH("unexpected lock orientation permission value");
212+
return false;
277213
}
278214

279-
void nsScreen::MozUnlockOrientation() {
280-
if (ShouldResistFingerprinting()) {
281-
return;
282-
}
283-
UpdateDocShellOrientationLock(GetOwner(), hal::eScreenOrientation_None);
284-
mScreenOrientation->UnlockDeviceOrientation();
285-
}
215+
void nsScreen::MozUnlockOrientation() {}
286216

287217
/* virtual */
288218
JSObject* nsScreen::WrapObject(JSContext* aCx,

hal/Hal.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,10 @@ void NotifyScreenConfigurationChange(
407407
ScreenConfigurationObservers()->BroadcastCachedInformation();
408408
}
409409

410-
bool LockScreenOrientation(const ScreenOrientation& aOrientation) {
410+
RefPtr<mozilla::MozPromise<bool, bool, false>> LockScreenOrientation(
411+
const ScreenOrientation& aOrientation) {
411412
AssertMainThread();
412-
RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), false);
413+
RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), nullptr);
413414
}
414415

415416
void UnlockScreenOrientation() {

hal/Hal.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "mozilla/HalWakeLockInformation.h"
1818
#include "mozilla/HalTypes.h"
1919
#include "mozilla/Types.h"
20+
#include "mozilla/MozPromise.h"
2021

2122
/*
2223
* Hal.h contains the public Hal API.
@@ -232,10 +233,10 @@ void NotifyScreenConfigurationChange(
232233

233234
/**
234235
* Lock the screen orientation to the specific orientation.
235-
* @return Whether the lock has been accepted.
236+
* @return A promise indicating that the screen orientation has been locked.
236237
*/
237-
[[nodiscard]] bool LockScreenOrientation(
238-
const hal::ScreenOrientation& aOrientation);
238+
[[nodiscard]] RefPtr<mozilla::MozPromise<bool, bool, false>>
239+
LockScreenOrientation(const hal::ScreenOrientation& aOrientation);
239240

240241
/**
241242
* Unlock the screen orientation.

hal/android/AndroidHal.cpp

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "AndroidBridge.h"
1010
#include "mozilla/dom/network/Constants.h"
1111
#include "mozilla/java/GeckoAppShellWrappers.h"
12+
#include "mozilla/java/GeckoRuntimeWrappers.h"
1213
#include "nsIScreenManager.h"
1314
#include "nsPIDOMWindow.h"
1415
#include "nsServiceManagerUtils.h"
@@ -123,8 +124,40 @@ void GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration) {
123124
orientation, angle, colorDepth, pixelDepth);
124125
}
125126

126-
bool LockScreenOrientation(const hal::ScreenOrientation& aOrientation) {
127-
return false;
127+
RefPtr<MozPromise<bool, bool, false>> LockScreenOrientation(
128+
const hal::ScreenOrientation& aOrientation) {
129+
// Force the default orientation to be portrait-primary.
130+
hal::ScreenOrientation orientation =
131+
aOrientation == eScreenOrientation_Default
132+
? eScreenOrientation_PortraitPrimary
133+
: aOrientation;
134+
135+
switch (orientation) {
136+
// The Android backend only supports these orientations.
137+
case eScreenOrientation_PortraitPrimary:
138+
case eScreenOrientation_PortraitSecondary:
139+
case eScreenOrientation_PortraitPrimary |
140+
eScreenOrientation_PortraitSecondary:
141+
case eScreenOrientation_LandscapePrimary:
142+
case eScreenOrientation_LandscapeSecondary:
143+
case eScreenOrientation_LandscapePrimary |
144+
eScreenOrientation_LandscapeSecondary:
145+
case eScreenOrientation_Default: {
146+
java::GeckoRuntime::LocalRef runtime = java::GeckoRuntime::GetInstance();
147+
if (runtime != NULL) {
148+
auto result = runtime->LockScreenOrientation(orientation);
149+
auto geckoResult = java::GeckoResult::LocalRef(std::move(result));
150+
return geckoResult
151+
? MozPromise<bool, bool, false>::FromGeckoResult(geckoResult)
152+
: MozPromise<bool, bool, false>::CreateAndReject(false,
153+
__func__);
154+
} else {
155+
return MozPromise<bool, bool, false>::CreateAndReject(false, __func__);
156+
}
157+
}
158+
default:
159+
return nullptr;
160+
}
128161
}
129162

130163
void UnlockScreenOrientation() {}

hal/fallback/FallbackScreenConfiguration.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ void GetCurrentScreenConfiguration(
1616
fallback::GetCurrentScreenConfiguration(aScreenConfiguration);
1717
}
1818

19-
bool LockScreenOrientation(const hal::ScreenOrientation& aOrientation) {
20-
return false;
19+
RefPtr<mozilla::MozPromise<bool, bool, false>> LockScreenOrientation(
20+
const hal::ScreenOrientation& aOrientation) {
21+
return mozilla::MozPromise<bool, bool, false>::CreateAndReject(false,
22+
__func__);
2123
}
2224

2325
void UnlockScreenOrientation() {}

hal/sandbox/PHal.ipdl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ parent:
9191

9292
async EnableScreenConfigurationNotifications();
9393
async DisableScreenConfigurationNotifications();
94-
sync LockScreenOrientation(ScreenOrientation aOrientation)
94+
async LockScreenOrientation(ScreenOrientation aOrientation)
9595
returns (bool allowed);
9696
async UnlockScreenOrientation();
9797

0 commit comments

Comments
 (0)