Merge mozilla-central to mozilla-inbound on a CLOSED TREE

--HG--
extra : rebase_source : c9e6b9edae9ecf064d1318fa15d5d57ea42c102a
This commit is contained in:
dvarga 2018-08-16 01:22:36 +03:00
commit 87db76ae1a
56 changed files with 424 additions and 235 deletions

View File

@ -1015,7 +1015,9 @@ var gIdentityHandler = {
let nameLabelId = "identity-popup-permission-label-" + aPermission.id;
nameLabel.setAttribute("id", nameLabelId);
let isPolicyPermission = aPermission.scope == SitePermissions.SCOPE_POLICY;
let isPolicyPermission = [
SitePermissions.SCOPE_POLICY, SitePermissions.SCOPE_GLOBAL
].includes(aPermission.scope);
if (aPermission.id == "popup" && !isPolicyPermission) {
let menulist = document.createXULElement("menulist");
@ -1083,8 +1085,8 @@ var gIdentityHandler = {
container.setAttribute("aria-labelledby", nameLabelId + " " + stateLabelId);
/* We return the permission item here without a remove button if the permission is a
SCOPE_POLICY permission. Policy permissions cannot be removed/changed for the duration
of the browser session. */
SCOPE_POLICY or SCOPE_GLOBAL permission. Policy permissions cannot be
removed/changed for the duration of the browser session. */
if (isPolicyPermission) {
return container;
}

View File

@ -97,7 +97,7 @@ function initRow(aPartId) {
command.setAttribute("disabled", "true");
}
if (scope == SitePermissions.SCOPE_POLICY) {
if ([SitePermissions.SCOPE_POLICY, SitePermissions.SCOPE_GLOBAL].includes(scope)) {
checkbox.setAttribute("disabled", "true");
command.setAttribute("disabled", "true");
}

View File

@ -10,6 +10,10 @@ support-files=
support-files =
temporary_permissions_subframe.html
../webrtc/get_user_media.html
[browser_autoplay_blocked.js]
support-files =
browser_autoplay_blocked.html
../general/audio.ogg
[browser_temporary_permissions_expiry.js]
[browser_temporary_permissions_navigation.js]
[browser_temporary_permissions_tabs.js]

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<html dir="ltr" xml:lang="en-US" lang="en-US">
<head>
<meta charset="utf8">
</head>
<body>
<audio autoplay="autoplay" >
<source src="audio.ogg" />
</audio>
</body>
</html>

View File

@ -0,0 +1,57 @@
/*
* Test that a blocked request to autoplay media is shown to the user
*/
const AUTOPLAY_PAGE = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "browser_autoplay_blocked.html";
function openIdentityPopup() {
let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
return promise;
}
function closeIdentityPopup() {
let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden");
gIdentityHandler._identityPopup.hidePopup();
return promise;
}
function autoplayBlockedIcon() {
return document.querySelector("#blocked-permissions-container " +
".blocked-permission-icon.autoplay-media-icon");
}
add_task(async function testMainViewVisible() {
Services.prefs.setIntPref("media.autoplay.default", Ci.nsIAutoplay.ALLOWED);
await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function() {
let permissionsList = document.getElementById("identity-popup-permission-list");
let emptyLabel = permissionsList.nextSibling.nextSibling;
ok(BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon not shown");
await openIdentityPopup();
ok(!BrowserTestUtils.is_hidden(emptyLabel), "List of permissions is empty");
await closeIdentityPopup();
});
Services.prefs.setIntPref("media.autoplay.default", Ci.nsIAutoplay.BLOCKED);
await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function() {
let permissionsList = document.getElementById("identity-popup-permission-list");
let emptyLabel = permissionsList.nextSibling.nextSibling;
ok(!BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon is shown");
await openIdentityPopup();
ok(BrowserTestUtils.is_hidden(emptyLabel), "List of permissions is not empty");
let labelText = SitePermissions.getPermissionLabel("autoplay-media");
let labels = permissionsList.querySelectorAll(".identity-popup-permission-label");
is(labels.length, 1, "One permission visible in main view");
is(labels[0].textContent, labelText, "Correct value");
await closeIdentityPopup();
});
Services.prefs.clearUserPref("media.autoplay.default");
});

View File

@ -279,6 +279,19 @@ var PermissionPromptPrototype = {
this.browser);
if (state == SitePermissions.BLOCK) {
// If the request is blocked by a global setting then we record
// a flag that lasts for the duration of the current page load
// to notify the user that the permission has been blocked.
// Currently only applies to autoplay-media
if (state == SitePermissions.getDefault(this.permissionKey) &&
SitePermissions.showGloballyBlocked(this.permissionKey)) {
SitePermissions.set(this.principal.URI,
this.permissionKey,
state,
SitePermissions.SCOPE_GLOBAL,
this.browser);
}
this.cancel();
return;
}

View File

@ -129,6 +129,71 @@ const TemporaryBlockedPermissions = {
},
};
// This hold a flag per browser to indicate whether we should show the
// user a notification as a permission has been requested that has been
// blocked globally. We only want to notify the user in the case that
// they actually requested the permission within the current page load
// so will clear the flag on navigation.
const GloballyBlockedPermissions = {
_stateByBrowser: new WeakMap(),
set(browser, id) {
if (!this._stateByBrowser.has(browser)) {
this._stateByBrowser.set(browser, {});
}
let entry = this._stateByBrowser.get(browser);
let prePath = browser.currentURI.prePath;
if (!entry[prePath]) {
entry[prePath] = {};
}
entry[prePath][id] = true;
// Listen to any top level navigations, once we see one clear the flag
// and remove the listener.
browser.addProgressListener({
QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference]),
onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
if (aWebProgress.isTopLevel) {
GloballyBlockedPermissions.remove(browser, id);
browser.removeProgressListener(this);
}
},
});
},
// Removes a permission with the specified id for the specified browser.
remove(browser, id) {
let entry = this._stateByBrowser.get(browser);
let prePath = browser.currentURI.prePath;
if (entry && entry[prePath]) {
delete entry[prePath][id];
}
},
// Gets all permissions for the specified browser.
// Note that only permissions that apply to the current URI
// of the passed browser element will be returned.
getAll(browser) {
let permissions = [];
let entry = this._stateByBrowser.get(browser);
let prePath = browser.currentURI.prePath;
if (entry && entry[prePath]) {
let timeStamps = entry[prePath];
for (let id of Object.keys(timeStamps)) {
permissions.push({
id,
state: SitePermissions.BLOCK,
scope: SitePermissions.SCOPE_GLOBAL
});
}
}
return permissions;
},
};
/**
* A module to manage permanent and temporary permissions
* by URI and browser.
@ -153,6 +218,7 @@ var SitePermissions = {
SCOPE_SESSION: "{SitePermissions.SCOPE_SESSION}",
SCOPE_PERSISTENT: "{SitePermissions.SCOPE_PERSISTENT}",
SCOPE_POLICY: "{SitePermissions.SCOPE_POLICY}",
SCOPE_GLOBAL: "{SitePermissions.SCOPE_GLOBAL}",
_defaultPrefBranch: Services.prefs.getBranch("permissions.default."),
@ -231,6 +297,10 @@ var SitePermissions = {
permissions[permission.id] = permission;
}
for (let permission of GloballyBlockedPermissions.getAll(browser)) {
permissions[permission.id] = permission;
}
for (let permission of this.getAllByURI(browser.currentURI)) {
permissions[permission.id] = permission;
}
@ -330,6 +400,23 @@ var SitePermissions = {
return this._defaultPrefBranch.getIntPref(permissionID, this.UNKNOWN);
},
/**
* Return whether the browser should notify the user if a permission was
* globally blocked due to a preference.
*
* @param {string} permissionID
* The ID to get the state for.
*
* @return boolean Whether to show notification for globally blocked permissions.
*/
showGloballyBlocked(permissionID) {
if (permissionID in gPermissionObject &&
gPermissionObject[permissionID].showGloballyBlocked)
return gPermissionObject[permissionID].showGloballyBlocked;
return false;
},
/**
* Returns the state and scope of a particular permission for a given URI.
*
@ -404,6 +491,13 @@ var SitePermissions = {
* This needs to be provided if the scope is SCOPE_TEMPORARY!
*/
set(uri, permissionID, state, scope = this.SCOPE_PERSISTENT, browser = null) {
if (scope == this.SCOPE_GLOBAL && state == this.BLOCK) {
GloballyBlockedPermissions.set(browser, permissionID);
browser.dispatchEvent(new browser.ownerGlobal.CustomEvent("PermissionStateChange"));
return;
}
if (state == this.UNKNOWN || state == this.getDefault(permissionID)) {
// Because they are controlled by two prefs with many states that do not
// correspond to the classical ALLOW/DENY/PROMPT model, we want to always
@ -607,13 +701,14 @@ var gPermissionObject = {
"autoplay-media": {
exactHostMatch: true,
showGloballyBlocked: true,
getDefault() {
let state = Services.prefs.getIntPref("media.autoplay.default",
Ci.nsIAutoplay.PROMPT);
if (state == Ci.nsIAutoplay.ALLOW) {
if (state == Ci.nsIAutoplay.ALLOWED) {
return SitePermissions.ALLOW;
} if (state == Ci.nsIAutoplay.BLOCK) {
return SitePermissions.DENY;
} if (state == Ci.nsIAutoplay.BLOCKED) {
return SitePermissions.BLOCK;
}
return SitePermissions.UNKNOWN;
},

View File

@ -2010,7 +2010,7 @@ HTMLMediaElement::Load()
HasSourceChildren(this),
EventStateManager::IsHandlingUserInput(),
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay),
AutoplayPolicy::IsAllowedToPlay(*this) == nsIAutoplay::ALLOWED,
AutoplayPolicy::IsAllowedToPlay(*this),
OwnerDoc(),
DocumentOrigin(OwnerDoc()).get(),
OwnerDoc() ? OwnerDoc()->HasBeenUserGestureActivated() : 0,
@ -2529,7 +2529,7 @@ HTMLMediaElement::ResumeLoad(PreloadAction aAction)
bool
HTMLMediaElement::AllowedToPlay() const
{
return AutoplayPolicy::IsAllowedToPlay(*this) == nsIAutoplay::ALLOWED;
return AutoplayPolicy::IsAllowedToPlay(*this);
}
void
@ -2538,7 +2538,7 @@ HTMLMediaElement::UpdatePreloadAction()
PreloadAction nextAction = PRELOAD_UNDEFINED;
// If autoplay is set, or we're playing, we should always preload data,
// as we'll need it to play.
if ((AutoplayPolicy::IsAllowedToPlay(*this) == nsIAutoplay::ALLOWED &&
if ((AutoplayPolicy::IsAllowedToPlay(*this) &&
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay)) ||
!mPaused) {
nextAction = HTMLMediaElement::PRELOAD_ENOUGH;
@ -3071,7 +3071,7 @@ HTMLMediaElement::PauseIfShouldNotBePlaying()
if (GetPaused()) {
return;
}
if (AutoplayPolicy::IsAllowedToPlay(*this) != nsIAutoplay::ALLOWED) {
if (!AutoplayPolicy::IsAllowedToPlay(*this)) {
AUTOPLAY_LOG("pause because not allowed to play, element=%p", this);
ErrorResult rv;
Pause(rv);
@ -4103,27 +4103,14 @@ HTMLMediaElement::Play(ErrorResult& aRv)
UpdateHadAudibleAutoplayState();
const bool handlingUserInput = EventStateManager::IsHandlingUserInput();
switch (AutoplayPolicy::IsAllowedToPlay(*this)) {
case nsIAutoplay::ALLOWED: {
mPendingPlayPromises.AppendElement(promise);
PlayInternal(handlingUserInput);
UpdateCustomPolicyAfterPlayed();
break;
}
case nsIAutoplay::BLOCKED: {
AUTOPLAY_LOG("%p play blocked.", this);
promise->MaybeReject(NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR);
if (StaticPrefs::MediaBlockEventEnabled()) {
DispatchAsyncEvent(NS_LITERAL_STRING("blocked"));
}
break;
}
case nsIAutoplay::PROMPT: {
// Prompt the user for permission to play.
mPendingPlayPromises.AppendElement(promise);
EnsureAutoplayRequested(handlingUserInput);
break;
}
if (AutoplayPolicy::IsAllowedToPlay(*this)) {
mPendingPlayPromises.AppendElement(promise);
PlayInternal(handlingUserInput);
UpdateCustomPolicyAfterPlayed();
} else {
// Prompt the user for permission to play.
mPendingPlayPromises.AppendElement(promise);
EnsureAutoplayRequested(handlingUserInput);
}
return promise.forget();
}
@ -6151,8 +6138,7 @@ HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
DispatchAsyncEvent(NS_LITERAL_STRING("canplay"));
if (!mPaused) {
if (mDecoder && !mPausedForInactiveDocumentOrChannel) {
MOZ_ASSERT(AutoplayPolicy::IsAllowedToPlay(*this) ==
nsIAutoplay::ALLOWED);
MOZ_ASSERT(AutoplayPolicy::IsAllowedToPlay(*this));
mDecoder->Play();
}
NotifyAboutPlaying();
@ -6264,14 +6250,9 @@ HTMLMediaElement::CheckAutoplayDataReady()
}
UpdateHadAudibleAutoplayState();
switch (AutoplayPolicy::IsAllowedToPlay(*this)) {
case nsIAutoplay::BLOCKED:
return;
case nsIAutoplay::PROMPT:
EnsureAutoplayRequested(false);
return;
case nsIAutoplay::ALLOWED:
break;
if (!AutoplayPolicy::IsAllowedToPlay(*this)) {
EnsureAutoplayRequested(false);
return;
}
mPaused = false;

View File

@ -156,7 +156,7 @@ AutoplayPolicy::WouldBeAllowedToPlayIfAutoplayDisabled(const HTMLMediaElement& a
return IsMediaElementAllowedToPlay(aElement);
}
/* static */ uint32_t
/* static */ bool
AutoplayPolicy::IsAllowedToPlay(const HTMLMediaElement& aElement)
{
const uint32_t autoplayDefault = DefaultAutoplayBehaviour();
@ -166,15 +166,19 @@ AutoplayPolicy::IsAllowedToPlay(const HTMLMediaElement& aElement)
// If element is blessed, it would always be allowed to play().
return (autoplayDefault == nsIAutoplay::ALLOWED ||
aElement.IsBlessed() ||
EventStateManager::IsHandlingUserInput())
? nsIAutoplay::ALLOWED : nsIAutoplay::BLOCKED;
EventStateManager::IsHandlingUserInput());
}
const uint32_t result = IsMediaElementAllowedToPlay(aElement) ?
nsIAutoplay::ALLOWED : autoplayDefault;
if (IsMediaElementAllowedToPlay(aElement)) {
return true;
}
const bool result = IsMediaElementAllowedToPlay(aElement) ||
autoplayDefault == nsIAutoplay::ALLOWED;
AUTOPLAY_LOG("IsAllowedToPlay, mediaElement=%p, isAllowToPlay=%s",
&aElement, AllowAutoplayToStr(result));
return result;
}

View File

@ -36,7 +36,7 @@ class AutoplayPolicy
{
public:
// Returns whether a given media element is allowed to play.
static uint32_t IsAllowedToPlay(const HTMLMediaElement& aElement);
static bool IsAllowedToPlay(const HTMLMediaElement& aElement);
// Returns true if a given media element would be allowed to play
// if block autoplay was enabled. If this returns false, it means we would

View File

@ -14,7 +14,6 @@
#include "mozilla/dom/DOMPoint.h"
#include "mozilla/dom/DOMQuad.h"
#include "mozilla/dom/DOMRect.h"
#include "nsContentUtils.h"
#include "nsIFrame.h"
#include "nsCSSFrameConstructor.h"
#include "nsLayoutUtils.h"

View File

@ -21,7 +21,6 @@
#include "mozilla/UndisplayedNode.h"
#include "nsIDocument.h"
#include "nsContentUtils.h"
#include "nsError.h"
#include "nsAutoPtr.h"
#include "nsAbsoluteContainingBlock.h"

View File

@ -14,7 +14,6 @@
#include "nsIPresShell.h"
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"
#include "nsContentUtils.h"
#include "nsCheckboxRadioFrame.h"
#include "nsFontMetrics.h"
#include "mozilla/dom/Element.h"

View File

@ -14,7 +14,6 @@
#include "nsIPresShell.h"
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"
#include "nsContentUtils.h"
#include "nsCheckboxRadioFrame.h"
#include "nsFontMetrics.h"
#include "mozilla/dom/Element.h"

View File

@ -11,7 +11,6 @@
#include "gfxContext.h"
#include "nsContentCreatorFunctions.h"
#include "nsContentUtils.h"
#include "nsCSSPseudoElements.h"
#include "nsCSSRendering.h"
#include "nsCheckboxRadioFrame.h"

View File

@ -12,7 +12,6 @@
#include "nsIPersistentProperties2.h"
#include "nsISimpleEnumerator.h"
#include "nsContentUtils.h"
#include "nsCRT.h"
// operator dictionary entry

View File

@ -73,7 +73,6 @@
#include "mozilla/ViewportFrame.h"
#include "mozilla/gfx/gfxVars.h"
#include "ActiveLayerTracker.h"
#include "nsContentUtils.h"
#include "nsPrintfCString.h"
#include "UnitTransforms.h"
#include "LayersLogging.h"

View File

@ -19,7 +19,6 @@
#include "nsString.h"
#include "mozilla/ComputedStyle.h"
#include "nsComputedDOMStyle.h"
#include "nsContentUtils.h"
#include "nsCSSPseudoElements.h"
#include "mozilla/dom/Element.h"
#include "mozilla/FloatingPoint.h"

View File

@ -21,7 +21,6 @@
#include "nsPresContext.h"
#include "nsStyleChangeList.h"
#include "nsContentUtils.h"
#include "nsLayoutUtils.h"
#include "nsIFrame.h"
#include "nsIDocument.h"

View File

@ -13,7 +13,6 @@
#include "mozilla/dom/MutationEventBinding.h"
#include "mozilla/InternalMutationEvent.h"
#include "mozAutoDocUpdate.h"
#include "nsContentUtils.h"
#include "nsIDocument.h"
#include "nsIURI.h"
#include "nsNodeUtils.h"

View File

@ -18,7 +18,6 @@
#include "mozAutoDocUpdate.h"
#include "nsIURI.h"
#include "mozilla/dom/BindingUtils.h"
#include "nsContentUtils.h"
#include "nsQueryObject.h"
#include "mozilla/layers/ScrollLinkedEffectDetector.h"

View File

@ -12,7 +12,6 @@
#include "nsFontFaceLoader.h"
#include "nsError.h"
#include "nsContentUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs.h"
#include "mozilla/Telemetry.h"

View File

@ -11,7 +11,6 @@
#include "mozilla/dom/CSSTransitionBinding.h"
#include "nsIContent.h"
#include "nsContentUtils.h"
#include "mozilla/ComputedStyle.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/TimeStamp.h"

View File

@ -6,7 +6,6 @@
// Keep in (case-insensitive) order:
#include "nsContainerFrame.h"
#include "nsContentUtils.h"
#include "nsFrame.h"
#include "nsGkAtoms.h"
#include "nsLiteralString.h"

View File

@ -11,7 +11,6 @@
// Keep others in (case-insensitive) order:
#include "gfxUtils.h"
#include "mozilla/Preferences.h"
#include "nsContentUtils.h"
#include "nsIFrame.h"
#include "nsPresContext.h"
#include "nsStyleStruct.h"

View File

@ -22,7 +22,6 @@
#include "SVGImageContext.h"
#include "mozilla/dom/MutationEventBinding.h"
#include "mozilla/dom/SVGImageElement.h"
#include "nsContentUtils.h"
#include "nsIReflowCallback.h"
#include "mozilla/Unused.h"

View File

@ -22,7 +22,6 @@
#include "SVGGeometryFrame.h"
#include "SVGImageContext.h"
#include "mozilla/dom/SVGImageElement.h"
#include "nsContentUtils.h"
#include "nsIReflowCallback.h"
#include "mozilla/Unused.h"

View File

@ -15,7 +15,6 @@
#include "gfxPattern.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/2D.h"
#include "nsContentUtils.h"
#include "nsGkAtoms.h"
#include "nsSVGDisplayableFrame.h"
#include "mozilla/ComputedStyle.h"

View File

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsSVGUseFrame.h"
#include "nsContentUtils.h"
#include "mozilla/dom/SVGUseElement.h"
#include "SVGObserverUtils.h"

View File

@ -18,7 +18,6 @@
#include "nsIServiceManager.h"
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"
#include "nsContentUtils.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/FromParser.h"

View File

@ -24,7 +24,6 @@
#include "nsISound.h"
#include "nsWidgetsCID.h"
#endif
#include "nsContentUtils.h"
#include "nsUTF8Utils.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Event.h"

View File

@ -10,7 +10,6 @@
#include "nsTreeContentView.h"
#include "nsITreeSelection.h"
#include "ChildIterator.h"
#include "nsContentUtils.h"
#include "nsError.h"
#include "nsTreeBodyFrame.h"
#include "mozilla/dom/TreeBoxObjectBinding.h"

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
import org.mozilla.gecko.GeckoScreenOrientation.ScreenOrientation;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.health.HealthRecorder;
@ -40,7 +41,6 @@ import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.ViewUtil;
import org.mozilla.gecko.widget.ActionModePresenter;
import org.mozilla.gecko.widget.AnchoredPopup;
import org.mozilla.geckoview.GeckoRuntime;
import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoSessionSettings;
import org.mozilla.geckoview.GeckoView;
@ -113,6 +113,7 @@ public abstract class GeckoApp extends GeckoActivity
BundleEventListener,
GeckoMenu.Callback,
GeckoMenu.MenuPresenter,
GeckoScreenOrientation.OrientationChangeListener,
GeckoSession.ContentDelegate,
ScreenOrientationDelegate,
Tabs.OnTabsChangedListener,
@ -982,6 +983,7 @@ public abstract class GeckoApp extends GeckoActivity
} catch (ClassNotFoundException e) { }
GeckoAppShell.setScreenOrientationDelegate(this);
GeckoScreenOrientation.getInstance().addListener(this);
// Tell Stumbler to register a local broadcast listener to listen for preference intents.
// We do this via intents since we can't easily access Stumbler directly,
@ -1065,8 +1067,6 @@ public abstract class GeckoApp extends GeckoActivity
super.onCreate(savedInstanceState);
GeckoScreenOrientation.getInstance().update(getResources().getConfiguration().orientation);
setContentView(getLayout());
// Set up Gecko layout.
@ -1930,11 +1930,6 @@ public abstract class GeckoApp extends GeckoActivity
GeckoAppShell.setScreenOrientationDelegate(this);
int newOrientation = getResources().getConfiguration().orientation;
if (GeckoScreenOrientation.getInstance().update(newOrientation)) {
refreshChrome();
}
// We use two times: a pseudo-unique wall-clock time to identify the
// current session across power cycles, and the elapsed realtime to
// track the duration of the session.
@ -2134,6 +2129,8 @@ public abstract class GeckoApp extends GeckoActivity
Tabs.unregisterOnTabsChangedListener(this);
Tabs.getInstance().detachFromContext();
GeckoScreenOrientation.getInstance().removeListener(this);
if (mShutdownOnDestroy) {
GeckoApplication.shutdown(!mRestartOnShutdown ? null : new Intent(
Intent.ACTION_MAIN, /* uri */ null, getApplicationContext(), getClass()));
@ -2178,19 +2175,6 @@ public abstract class GeckoApp extends GeckoActivity
onLocaleChanged(Locales.getLanguageTag(changed));
}
// onConfigurationChanged is not called for 180 degree orientation changes,
// we will miss such rotations and the screen orientation will not be
// updated.
if (GeckoScreenOrientation.getInstance().update(newConfig.orientation)) {
if (mFormAssistPopup != null)
mFormAssistPopup.hide();
refreshChrome();
}
if (mPromptService != null) {
mPromptService.changePromptOrientation(newConfig.orientation);
}
super.onConfigurationChanged(newConfig);
}
@ -2528,4 +2512,12 @@ public abstract class GeckoApp extends GeckoActivity
setRequestedOrientation(requestedActivityInfoOrientation);
return true;
}
@Override
public void onScreenOrientationChanged(ScreenOrientation newOrientation) {
if (mFormAssistPopup != null) {
mFormAssistPopup.hide();
}
refreshChrome();
}
}

View File

@ -9,7 +9,6 @@ import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@ -39,8 +38,6 @@ import org.mozilla.gecko.DoorHangerPopup;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.FormAssistPopup;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.preferences.GeckoPreferences;
import org.mozilla.gecko.R;
import org.mozilla.gecko.SnackbarBuilder;
import org.mozilla.gecko.Telemetry;
@ -59,9 +56,7 @@ import org.mozilla.gecko.util.PackageUtil;
import org.mozilla.gecko.webapps.WebApps;
import org.mozilla.gecko.widget.ActionModePresenter;
import org.mozilla.gecko.widget.GeckoPopupMenu;
import org.mozilla.geckoview.GeckoResponse;
import org.mozilla.geckoview.GeckoResult;
import org.mozilla.geckoview.GeckoRuntime;
import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoSessionSettings;
import org.mozilla.geckoview.GeckoView;
@ -191,15 +186,6 @@ public class CustomTabsActivity extends AppCompatActivity
Permissions.onRequestPermissionsResult(this, permissions, grantResults);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mPromptService != null) {
mPromptService.changePromptOrientation(newConfig.orientation);
}
}
private void sendTelemetry() {
final SafeIntent startIntent = new SafeIntent(getIntent());

View File

@ -6,23 +6,25 @@
package org.mozilla.gecko.prompts;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoScreenOrientation;
import org.mozilla.gecko.GeckoScreenOrientation.ScreenOrientation;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import android.content.Context;
public class PromptService implements BundleEventListener {
public class PromptService implements BundleEventListener,
GeckoScreenOrientation.OrientationChangeListener {
private static final String LOGTAG = "GeckoPromptService";
private final Context context;
private final EventDispatcher dispatcher;
private Prompt currentPrompt;
private int currentOrientation;
public PromptService(final Context context, final EventDispatcher dispatcher) {
this.context = context;
this.currentOrientation = context.getResources().getConfiguration().orientation;
GeckoScreenOrientation.getInstance().addListener(this);
this.dispatcher = dispatcher;
this.dispatcher.registerUiThreadListener(this,
"Prompt:Show",
@ -33,6 +35,7 @@ public class PromptService implements BundleEventListener {
dispatcher.unregisterUiThreadListener(this,
"Prompt:Show",
"Prompt:ShowTop");
GeckoScreenOrientation.getInstance().removeListener(this);
}
// BundleEventListener implementation
@ -49,10 +52,11 @@ public class PromptService implements BundleEventListener {
currentPrompt.show(message);
}
public void changePromptOrientation(int newOrientation) {
if (currentPrompt != null && currentOrientation != newOrientation) {
// OrientationChangeListener implementation
@Override
public void onScreenOrientationChanged(ScreenOrientation newOrientation) {
if (currentPrompt != null) {
currentPrompt.resetLayout();
}
currentOrientation = newOrientation;
}
}

View File

@ -9,7 +9,6 @@ import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
@ -29,8 +28,6 @@ import org.mozilla.gecko.DoorHangerPopup;
import org.mozilla.gecko.FormAssistPopup;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.GeckoScreenOrientation;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.preferences.GeckoPreferences;
import org.mozilla.gecko.R;
import org.mozilla.gecko.customtabs.CustomTabsActivity;
import org.mozilla.gecko.permissions.Permissions;
@ -39,9 +36,7 @@ import org.mozilla.gecko.text.TextSelection;
import org.mozilla.gecko.util.ActivityUtils;
import org.mozilla.gecko.util.ColorUtil;
import org.mozilla.gecko.widget.ActionModePresenter;
import org.mozilla.geckoview.GeckoResponse;
import org.mozilla.geckoview.GeckoResult;
import org.mozilla.geckoview.GeckoRuntime;
import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoSessionSettings;
import org.mozilla.geckoview.GeckoView;
@ -178,15 +173,6 @@ public class WebAppActivity extends AppCompatActivity
mGeckoSession.loadUri(mManifest.getStartUri().toString());
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mPromptService != null) {
mPromptService.changePromptOrientation(newConfig.orientation);
}
}
private void fallbackToFennec(String message) {
if (message != null) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();

View File

@ -28,9 +28,6 @@ import java.util.TreeMap;
import org.mozilla.gecko.annotation.JNITarget;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.permissions.Permissions;
import org.mozilla.gecko.process.GeckoProcessManager;
import org.mozilla.gecko.SysInfo;
import org.mozilla.gecko.util.BitmapUtils;
import org.mozilla.gecko.util.HardwareCodecCapabilityUtils;
import org.mozilla.gecko.util.HardwareUtils;
@ -39,28 +36,19 @@ import org.mozilla.gecko.util.ProxySelector;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.geckoview.BuildConfig;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
@ -78,33 +66,22 @@ import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.LocaleList;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.Vibrator;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.SimpleArrayMap;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.HapticFeedbackConstants;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.webkit.MimeTypeMap;
import android.widget.AbsoluteLayout;
public class GeckoAppShell
{
@ -261,8 +238,6 @@ public class GeckoAppShell
@WrapForJNI(dispatchTo = "gecko")
public static native void notifyUriVisited(String uri);
private static Rect sScreenSize;
@WrapForJNI(stubName = "NotifyObservers", dispatchTo = "gecko")
private static native void nativeNotifyObservers(String topic, String data);
@ -1848,19 +1823,12 @@ public class GeckoAppShell
return 0;
}
public static synchronized void resetScreenSize() {
sScreenSize = null;
}
@WrapForJNI(calledFrom = "gecko")
private static synchronized Rect getScreenSize() {
if (sScreenSize == null) {
final WindowManager wm = (WindowManager)
getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
final Display disp = wm.getDefaultDisplay();
sScreenSize = new Rect(0, 0, disp.getWidth(), disp.getHeight());
}
return sScreenSize;
private static Rect getScreenSize() {
final WindowManager wm = (WindowManager)
getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
final Display disp = wm.getDefaultDisplay();
return new Rect(0, 0, disp.getWidth(), disp.getHeight());
}
@WrapForJNI(calledFrom = "any")

View File

@ -13,7 +13,9 @@ import android.view.Surface;
import android.view.WindowManager;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.util.ThreadUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -64,6 +66,12 @@ public class GeckoScreenOrientation {
// Whether the update should notify Gecko about screen orientation changes.
private boolean mShouldNotify = true;
public interface OrientationChangeListener {
void onScreenOrientationChanged(ScreenOrientation newOrientation);
}
private final List<OrientationChangeListener> mListeners;
public static GeckoScreenOrientation getInstance() {
if (sInstance == null) {
sInstance = new GeckoScreenOrientation();
@ -72,9 +80,26 @@ public class GeckoScreenOrientation {
}
private GeckoScreenOrientation() {
mListeners = new ArrayList<>();
update();
}
/**
* Add a listener that will be notified when the screen orientation has changed.
*/
public void addListener(OrientationChangeListener aListener) {
ThreadUtils.assertOnUiThread();
mListeners.add(aListener);
}
/**
* Remove a OrientationChangeListener again.
*/
public void removeListener(OrientationChangeListener aListener) {
ThreadUtils.assertOnUiThread();
mListeners.remove(aListener);
}
/*
* Enable Gecko screen orientation events on update.
*/
@ -129,12 +154,13 @@ public class GeckoScreenOrientation {
*
* @return Whether the screen orientation has changed.
*/
public boolean update(ScreenOrientation aScreenOrientation) {
public synchronized boolean update(ScreenOrientation aScreenOrientation) {
if (mScreenOrientation == aScreenOrientation) {
return false;
}
mScreenOrientation = aScreenOrientation;
Log.d(LOGTAG, "updating to new orientation " + mScreenOrientation);
notifyListeners(mScreenOrientation);
if (mShouldNotify) {
// Gecko expects a definite screen orientation, so we default to the
// primary orientations.
@ -151,10 +177,27 @@ public class GeckoScreenOrientation {
aScreenOrientation.value, getAngle());
}
}
GeckoAppShell.resetScreenSize();
ScreenManagerHelper.refreshScreenInfo();
return true;
}
private void notifyListeners(final ScreenOrientation newOrientation) {
final Runnable notifier = new Runnable() {
@Override
public void run() {
for (OrientationChangeListener listener : mListeners) {
listener.onScreenOrientationChanged(newOrientation);
}
}
};
if (ThreadUtils.isOnUiThread()) {
notifier.run();
} else {
ThreadUtils.postToUiThread(notifier);
}
}
/*
* @return The Android orientation (Configuration.orientation).
*/
@ -193,11 +236,13 @@ public class GeckoScreenOrientation {
Log.d(LOGTAG, "locking to " + aScreenOrientation);
final ScreenOrientationDelegate delegate = GeckoAppShell.getScreenOrientationDelegate();
final int activityInfoOrientation = screenOrientationToActivityInfoOrientation(aScreenOrientation);
if (delegate.setRequestedOrientationForCurrentActivity(activityInfoOrientation)) {
update(aScreenOrientation);
return true;
} else {
return false;
synchronized (this) {
if (delegate.setRequestedOrientationForCurrentActivity(activityInfoOrientation)) {
update(aScreenOrientation);
return true;
} else {
return false;
}
}
}
@ -210,11 +255,13 @@ public class GeckoScreenOrientation {
Log.d(LOGTAG, "unlocking");
final ScreenOrientationDelegate delegate = GeckoAppShell.getScreenOrientationDelegate();
final int activityInfoOrientation = screenOrientationToActivityInfoOrientation(ScreenOrientation.DEFAULT);
if (delegate.setRequestedOrientationForCurrentActivity(activityInfoOrientation)) {
update();
return true;
} else {
return false;
synchronized (this) {
if (delegate.setRequestedOrientationForCurrentActivity(activityInfoOrientation)) {
update();
return true;
} else {
return false;
}
}
}

View File

@ -17,6 +17,20 @@ class ScreenManagerHelper {
final static int DISPLAY_EXTERNAL = 1; // wired displays, such as HDMI, DisplayPort, etc.
final static int DISPLAY_VIRTUAL = 2; // wireless displays, such as Chromecast, WiFi-Display, etc.
/**
* Trigger a refresh of the cached screen information held by Gecko.
*/
public static void refreshScreenInfo() {
// Screen data is initialised automatically on startup, so no need to queue the call if
// Gecko isn't running yet.
if (GeckoThread.isRunning()) {
nativeRefreshScreenInfo();
}
}
@WrapForJNI(stubName = "RefreshScreenInfo", dispatchTo = "gecko")
private native static void nativeRefreshScreenInfo();
/**
* Add a new nsScreen when a new display in Android is available.
*

View File

@ -6,7 +6,6 @@
package org.mozilla.geckoview;
import android.content.SharedPreferences;
import android.os.Parcel;
import android.os.Parcelable;
import android.content.Context;
@ -16,7 +15,7 @@ import android.util.Log;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.GeckoScreenOrientation;
import org.mozilla.gecko.GeckoThread;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.util.BundleEventListener;
@ -258,6 +257,22 @@ public final class GeckoRuntime implements Parcelable {
return GeckoThread.getActiveProfile().getDir();
}
/**
* Notify Gecko that the screen orientation has changed.
*/
public void orientationChanged() {
GeckoScreenOrientation.getInstance().update();
}
/**
* Notify Gecko that the screen orientation has changed.
* @param newOrientation The new screen orientation, as retrieved e.g. from the current
* {@link android.content.res.Configuration}.
*/
public void orientationChanged(int newOrientation) {
GeckoScreenOrientation.getInstance().update(newOrientation);
}
@Override // Parcelable
public int describeContents() {
return 0;

View File

@ -16,6 +16,7 @@ import org.mozilla.gecko.util.ActivityUtils;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
@ -29,7 +30,6 @@ import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
@ -342,6 +342,7 @@ public class GeckoView extends FrameLayout {
if (!mSession.isOpen()) {
mSession.open(mRuntime);
}
mRuntime.orientationChanged();
super.onAttachedToWindow();
}
@ -360,6 +361,18 @@ public class GeckoView extends FrameLayout {
}
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mRuntime != null) {
// onConfigurationChanged is not called for 180 degree orientation changes,
// we will miss such rotations and the screen orientation will not be
// updated.
mRuntime.orientationChanged(newConfig.orientation);
}
}
@Override
public boolean gatherTransparentRegion(final Region region) {
// For detecting changes in SurfaceView layout, we take a shortcut here and
@ -393,7 +406,7 @@ public class GeckoView extends FrameLayout {
setSession(ss.session, ss.session.getRuntime());
} else if (ss.session != null) {
mSession.transferFrom(ss.session);
mRuntime = ss.session.getRuntime();
mRuntime = mSession.getRuntime();
}
}

View File

@ -13,7 +13,10 @@ import threading
import time
import traceback
from Queue import Queue, Empty
try:
from queue import Queue, Empty
except ImportError:
from Queue import Queue, Empty
from datetime import datetime
@ -124,14 +127,14 @@ class ProcessHandlerMixin(object):
thread = threading.current_thread().name
print("DBG::MOZPROC PID:{} ({}) | {}".format(self.pid, thread, msg))
def __del__(self, _maxint=sys.maxint):
def __del__(self, _maxint=sys.maxsize):
if isWin:
handle = getattr(self, '_handle', None)
if handle:
if hasattr(self, '_internal_poll'):
self._internal_poll(_deadstate=_maxint)
else:
self.poll(_deadstate=sys.maxint)
self.poll(_deadstate=sys.maxsize)
if handle or self._job or self._io_port:
self._cleanup()
else:
@ -1069,7 +1072,7 @@ class StreamOutput(object):
def __call__(self, line):
try:
self.stream.write(line + '\n')
self.stream.write(line.decode() + '\n')
except UnicodeDecodeError:
# TODO: Workaround for bug #991866 to make sure we can display when
# when normal UTF-8 display is failing

View File

@ -6,7 +6,7 @@ from __future__ import absolute_import
from setuptools import setup
PACKAGE_VERSION = '0.26'
PACKAGE_VERSION = '1.0.0'
setup(name='mozprocess',
version=PACKAGE_VERSION,
@ -17,7 +17,8 @@ setup(name='mozprocess',
'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.5'
'Topic :: Software Development :: Libraries :: Python Modules',
],
keywords='mozilla',

View File

@ -1,6 +1,5 @@
[DEFAULT]
subsuite = mozbase, os == "linux"
skip-if = python == 3
[test_kill.py]
[test_misc.py]
[test_poll.py]

View File

@ -4,7 +4,10 @@ from __future__ import absolute_import, print_function
import argparse
import collections
import ConfigParser
try:
import configparser as ConfigParser
except ImportError:
import ConfigParser
import multiprocessing
import time

View File

@ -2,13 +2,13 @@
from __future__ import absolute_import
import io
import os
import mozunit
import proctest
from mozprocess import processhandler
import six
here = os.path.dirname(os.path.abspath(__file__))
@ -49,26 +49,24 @@ class ProcTestOutput(proctest.ProcTest):
"""
expected = '\n'.join([str(n) for n in range(0, 10)])
stream = io.BytesIO()
buf = io.BufferedRandom(stream)
stream = six.StringIO()
p = processhandler.ProcessHandler([self.python,
os.path.join("scripts", "proccountfive.py")],
cwd=here,
stream=buf)
stream=stream)
p.run()
p.wait()
for i in range(5, 10):
stream.write(str(i) + '\n')
buf.flush()
self.assertEquals(stream.getvalue().strip(), expected)
# make sure mozprocess doesn't close the stream
# since mozprocess didn't create it
self.assertFalse(buf.closed)
buf.close()
self.assertFalse(stream.closed)
stream.close()
self.determine_status(p, False, ())

View File

@ -33,11 +33,11 @@ class TestProcessReader(unittest.TestCase):
timeout_callback=on_timeout)
def test_stdout_callback(self):
proc = run_python('print 1; print 2')
proc = run_python('print(1); print(2)')
self.reader.start(proc)
self.reader.thread.join()
self.assertEqual(self.out.output, ['1', '2'])
self.assertEqual(self.out.output, [b'1', b'2'])
self.assertEqual(self.err.output, [])
def test_stderr_callback(self):
@ -46,15 +46,15 @@ class TestProcessReader(unittest.TestCase):
self.reader.thread.join()
self.assertEqual(self.out.output, [])
self.assertEqual(self.err.output, ['hello world'])
self.assertEqual(self.err.output, [b'hello world'])
def test_stdout_and_stderr_callbacks(self):
proc = run_python('import sys; sys.stderr.write("hello world\\n"); print 1; print 2')
proc = run_python('import sys; sys.stderr.write("hello world\\n"); print(1); print(2)')
self.reader.start(proc)
self.reader.thread.join()
self.assertEqual(self.out.output, ['1', '2'])
self.assertEqual(self.err.output, ['hello world'])
self.assertEqual(self.out.output, [b'1', b'2'])
self.assertEqual(self.err.output, [b'hello world'])
def test_finished_callback(self):
self.assertFalse(self.finished)
@ -85,21 +85,21 @@ class TestProcessReader(unittest.TestCase):
proc = run_python('import sys; sys.stdout.write("1")')
self.reader.start(proc)
self.reader.thread.join()
self.assertEqual(self.out.output, ['1'])
self.assertEqual(self.out.output, [b'1'])
def test_read_with_strange_eol(self):
proc = run_python('import sys; sys.stdout.write("1\\r\\r\\r\\n")')
self.reader.start(proc)
self.reader.thread.join()
self.assertEqual(self.out.output, ['1'])
self.assertEqual(self.out.output, [b'1'])
def test_mixed_stdout_stderr(self):
proc = run_python('import sys; sys.stderr.write("hello world\\n"); print 1; print 2',
proc = run_python('import sys; sys.stderr.write("hello world\\n"); print(1); print(2)',
stderr=subprocess.STDOUT)
self.reader.start(proc)
self.reader.thread.join()
self.assertEqual(sorted(self.out.output), sorted(['1', '2', 'hello world']))
self.assertEqual(sorted(self.out.output), sorted([b'1', b'2', b'hello world']))
self.assertEqual(self.err.output, [])

View File

@ -16,7 +16,7 @@ deps = [
'mozfile==1.*',
'mozinfo>=0.7,<2',
'mozlog==3.*',
'mozprocess>=0.23,<1',
'mozprocess>=0.23,<2',
'mozprofile>=1.1.0,<2',
'six>=1.10.0,<2',
]

View File

@ -120,6 +120,12 @@ class Output(object):
if test.test_config.get('alert_threshold') is not None:
subtest['alertThreshold'] = \
test.test_config['alert_threshold']
if test.test_config.get('subtest_alerts') is not None:
subtest['shouldAlert'] = \
test.test_config['subtest_alerts']
if test.test_config.get('alert_threshold') is not None:
subtest['alertThreshold'] = \
test.test_config['alert_threshold']
if test.test_config.get('unit'):
subtest['unit'] = test.test_config['unit']

View File

@ -37,6 +37,8 @@ class Test(object):
filters = filter.ignore_first.prepare(1) + filter.median.prepare()
lower_is_better = True
alert_threshold = 2.0
perfherder_framework = 'talos'
subtest_alerts = False
@classmethod
def name(cls):
@ -245,6 +247,7 @@ class PageloaderTest(Test):
tpcycles = 1 # number of time to run each page
cycles = None
timeout = None
keys = ['tpmanifest', 'tpcycles', 'tppagecycles', 'tprender', 'tpchrome',
'tpmozafterpaint', 'fnbpaint', 'tphero', 'tploadnocache', 'firstpaint',
'userready', 'testeventmap', 'base_vs_ref', 'mainthread', 'resolution',
@ -253,7 +256,8 @@ class PageloaderTest(Test):
'tpscrolltest', 'xperf_counters', 'timeout', 'responsiveness',
'profile_path', 'xperf_providers', 'xperf_user_providers', 'xperf_stackwalk',
'format_pagename', 'filters', 'preferences', 'extensions', 'setup', 'cleanup',
'lower_is_better', 'alert_threshold', 'unit', 'webextensions', 'profile']
'lower_is_better', 'alert_threshold', 'unit', 'webextensions', 'profile',
'subtest_alerts', 'perfherder_framework']
class QuantumPageloadTest(PageloaderTest):
@ -430,6 +434,8 @@ class damp(PageloaderTest):
preferences = {'devtools.memory.enabled': True,
'addon.test.damp.webserver': '${webserver}'}
unit = 'ms'
subtest_alerts = True
perfherder_framework = 'devtools'
@register_test()

View File

@ -146,6 +146,11 @@ class TTest(object):
# remove the browser error file
mozfile.remove(browser_config['error_filename'])
# individual tests can have different frameworks
# TODO: ensure that we don't run >1 test with custom frameworks
if test_config.get('perfherder_framework', None) is not None:
test_results.framework = test_config['perfherder_framework']
# reinstall any file whose stability we need to ensure across
# the cycles
if test_config.get('reinstall', ''):

View File

@ -13,7 +13,7 @@ deps = ['httplib2 == 0.9.2',
'mozhttpd == 0.7',
'mozinfo >= 0.10',
'mozinstall == 1.16',
'mozprocess == 0.26',
'mozprocess == 1.0.0',
'mozprofile == 1.1.0',
'mozrunner == 7.0.1',
'mozversion == 1.5',

View File

@ -410,88 +410,66 @@ var SafeBrowsing = {
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
getService(Ci.nsIUrlListManager);
listManager.disableAllUpdates();
for (let i = 0; i < this.phishingLists.length; ++i) {
if (this.phishingEnabled) {
listManager.enableUpdate(this.phishingLists[i]);
} else {
listManager.disableUpdate(this.phishingLists[i]);
}
}
for (let i = 0; i < this.malwareLists.length; ++i) {
if (this.malwareEnabled) {
listManager.enableUpdate(this.malwareLists[i]);
} else {
listManager.disableUpdate(this.malwareLists[i]);
}
}
for (let i = 0; i < this.downloadBlockLists.length; ++i) {
if (this.malwareEnabled && this.downloadsEnabled) {
listManager.enableUpdate(this.downloadBlockLists[i]);
} else {
listManager.disableUpdate(this.downloadBlockLists[i]);
}
}
for (let i = 0; i < this.downloadAllowLists.length; ++i) {
if (this.malwareEnabled && this.downloadsEnabled) {
listManager.enableUpdate(this.downloadAllowLists[i]);
} else {
listManager.disableUpdate(this.downloadAllowLists[i]);
}
}
for (let i = 0; i < this.passwordAllowLists.length; ++i) {
if (this.passwordsEnabled) {
listManager.enableUpdate(this.passwordAllowLists[i]);
} else {
listManager.disableUpdate(this.passwordAllowLists[i]);
}
}
for (let i = 0; i < this.trackingAnnotationLists.length; ++i) {
if (this.trackingAnnotations) {
listManager.enableUpdate(this.trackingAnnotationLists[i]);
} else {
listManager.disableUpdate(this.trackingAnnotationLists[i]);
}
}
for (let i = 0; i < this.trackingAnnotationWhitelists.length; ++i) {
if (this.trackingAnnotations) {
listManager.enableUpdate(this.trackingAnnotationWhitelists[i]);
} else {
listManager.disableUpdate(this.trackingAnnotationWhitelists[i]);
}
}
for (let i = 0; i < this.trackingProtectionLists.length; ++i) {
if (this.trackingEnabled) {
listManager.enableUpdate(this.trackingProtectionLists[i]);
} else {
listManager.disableUpdate(this.trackingProtectionLists[i]);
}
}
for (let i = 0; i < this.trackingProtectionWhitelists.length; ++i) {
if (this.trackingEnabled) {
listManager.enableUpdate(this.trackingProtectionWhitelists[i]);
} else {
listManager.disableUpdate(this.trackingProtectionWhitelists[i]);
}
}
for (let i = 0; i < this.blockedLists.length; ++i) {
if (this.blockedEnabled) {
listManager.enableUpdate(this.blockedLists[i]);
} else {
listManager.disableUpdate(this.blockedLists[i]);
}
}
for (let i = 0; i < this.flashLists.length; ++i) {
if (this.flashBlockEnabled) {
listManager.enableUpdate(this.flashLists[i]);
} else {
listManager.disableUpdate(this.flashLists[i]);
}
}
for (let i = 0; i < this.flashInfobarLists.length; ++i) {
if (this.flashInfobarListEnabled) {
listManager.enableUpdate(this.flashInfobarLists[i]);
} else {
listManager.disableUpdate(this.flashInfobarLists[i]);
}
}
listManager.maybeToggleUpdateChecking();

View File

@ -51,7 +51,12 @@ interface nsIUrlListManager : nsISupports
void enableUpdate(in ACString tableName);
/**
* Turn off update checking for a table.
* Turn off update checking for all tables.
*/
void disableAllUpdates();
/**
* Turn off update checking for a single table. Only used in tests.
*/
void disableUpdate(in ACString tableName);

View File

@ -168,8 +168,7 @@ PROT_ListManager.prototype.getUpdateUrl = function(tableName) {
};
/**
* Enable updates for some tables
* @param tables - an array of table names that need updating
* Enable updates for a single table.
*/
PROT_ListManager.prototype.enableUpdate = function(tableName) {
var table = this.tablesData[tableName];
@ -194,8 +193,17 @@ PROT_ListManager.prototype.updatesNeeded_ = function(updateUrl) {
};
/**
* Disables updates for some tables
* @param tables - an array of table names that no longer need updating
* Disable updates for all tables.
*/
PROT_ListManager.prototype.disableAllUpdates = function() {
for (const tableName of Object.keys(this.tablesData)) {
this.disableUpdate(tableName);
}
};
/**
* Disables updates for a single table. Avoid this internal function
* and use disableAllUpdates() instead.
*/
PROT_ListManager.prototype.disableUpdate = function(tableName) {
var table = this.tablesData[tableName];

View File

@ -26,6 +26,10 @@ class ScreenHelperAndroid::ScreenHelperSupport final
public:
typedef ScreenManagerHelper::Natives<ScreenHelperSupport> Base;
static void RefreshScreenInfo() {
gHelper->Refresh();
}
static int32_t AddDisplay(int32_t aDisplayType, int32_t aWidth, int32_t aHeight, float aDensity) {
static Atomic<uint32_t> nextId;