Merge m-c to b2g-inbound a=merge

This commit is contained in:
Wes Kocher 2014-09-26 19:17:41 -07:00
commit 0b16969b38
41 changed files with 316 additions and 154 deletions

View File

@ -46,7 +46,7 @@ const gXPInstallObserver = {
}
// Note that the above try/catch will pass through dead object proxies and
// other degenerate objects. Make sure the browser is bonafide.
if (!browser || gBrowser.browsers.indexOf(browser) == -1)
if (!browser || !gBrowser.browsers.contains(browser))
return;
const anchorID = "addons-notification-icon";

View File

@ -5,10 +5,6 @@
var FullScreen = {
_XULNS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
get _fullScrToggler() {
delete this._fullScrToggler;
return this._fullScrToggler = document.getElementById("fullscr-toggler");
},
init: function() {
// called when we go into full screen, even if initiated by a web page script
@ -46,6 +42,12 @@ var FullScreen = {
document.getElementById("exitFullScreenItem").hidden = !enterFS;
#endif
if (!this._fullScrToggler) {
this._fullScrToggler = document.getElementById("fullscr-toggler");
this._fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
}
// On OS X Lion we don't want to hide toolbars when entering fullscreen, unless
// we're entering DOM fullscreen, in which case we should hide the toolbars.
// If we're leaving fullscreen, then we'll go through the exit code below to
@ -65,14 +67,6 @@ var FullScreen = {
this.showXULChrome("toolbar", !enterFS);
if (enterFS) {
// Add a tiny toolbar to receive mouseover and dragenter events, and provide affordance.
// This will help simulate the "collapse" metaphor while also requiring less code and
// events than raw listening of mouse coords. We don't add the toolbar in DOM full-screen
// mode, only browser full-screen mode.
if (!document.mozFullScreen) {
this._fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
}
if (gPrefService.getBoolPref("browser.fullscreen.autohide"))
gBrowser.mPanelContainer.addEventListener("mousemove",
this._collapseCallback, false);
@ -187,11 +181,6 @@ var FullScreen = {
// the toolbar hide immediately.
this._cancelAnimation();
this.mouseoverToggle(false);
// Remove listeners on the full-screen toggler, so that mouseover
// the top of the screen will not cause the toolbar to re-appear.
this._fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
},
cleanup: function () {
@ -203,8 +192,6 @@ var FullScreen = {
document.removeEventListener("popuphidden", this._setPopupOpen, false);
gPrefService.removeObserver("browser.fullscreen", this);
this._fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
this.cancelWarning();
gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
@ -540,7 +527,7 @@ var FullScreen = {
gNavToolbox.style.marginTop =
aShow ? "" : -gNavToolbox.getBoundingClientRect().height + "px";
this._fullScrToggler.collapsed = aShow;
this._fullScrToggler.hidden = aShow || document.mozFullScreen;
this._isChromeCollapsed = !aShow;
if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 2)
this._shouldAnimate = true;

View File

@ -1371,7 +1371,7 @@ let BookmarkingUI = {
// calls back. For such an edge case, retain all unique entries from both
// arrays.
this._itemIds = this._itemIds.filter(
function (id) aItemIds.indexOf(id) == -1
function (id) !aItemIds.contains(id)
).concat(aItemIds);
this._updateStar();
@ -1592,7 +1592,7 @@ let BookmarkingUI = {
aURI) {
if (aURI && aURI.equals(this._uri)) {
// If a new bookmark has been added to the tracked uri, register it.
if (this._itemIds.indexOf(aItemId) == -1) {
if (!this._itemIds.contains(aItemId)) {
this._itemIds.push(aItemId);
// Only need to update the UI if it wasn't marked as starred before:
if (this._itemIds.length == 1) {

View File

@ -2218,7 +2218,7 @@ function URLBarSetURI(aURI) {
// Replace initial page URIs with an empty string
// only if there's no opener (bug 370555).
// Bug 863515 - Make content.opener checks work in electrolysis.
if (gInitialPages.indexOf(uri.spec) != -1)
if (gInitialPages.contains(uri.spec))
value = !gMultiProcessBrowser && content.opener ? uri.spec : "";
else
value = losslessDecodeURI(uri);

View File

@ -1069,7 +1069,7 @@
</toolbarpalette>
</toolbox>
<hbox id="fullscr-toggler" collapsed="true"/>
<hbox id="fullscr-toggler" hidden="true"/>
<deck id="content-deck" flex="1">
<hbox flex="1" id="browser">

View File

@ -131,7 +131,7 @@ let gUpdater = {
// Delete sites that were removed from the grid.
gGrid.sites.forEach(function (aSite) {
// The site must be valid and not in the current grid.
if (!aSite || aSites.indexOf(aSite) != -1)
if (!aSite || aSites.contains(aSite))
return;
batch.push(new Promise(resolve => {

View File

@ -18,7 +18,7 @@ var permissionObserver = {
if (aTopic == "perm-changed") {
var permission = aSubject.QueryInterface(Components.interfaces.nsIPermission);
if (permission.host == gPermURI.host) {
if (gPermissions.indexOf(permission.type) > -1)
if (gPermissions.contains(permission.type))
initRow(permission.type);
else if (permission.type.startsWith("plugin"))
setPluginsRadioState();

View File

@ -152,9 +152,9 @@ var gSyncSetup = {
// Only open the dialog if username + password are actually correct.
Weave.Service.login();
if ([Weave.LOGIN_FAILED_INVALID_PASSPHRASE,
Weave.LOGIN_FAILED_NO_PASSPHRASE,
Weave.LOGIN_SUCCEEDED].indexOf(Weave.Status.login) == -1) {
if (![Weave.LOGIN_FAILED_INVALID_PASSPHRASE,
Weave.LOGIN_FAILED_NO_PASSPHRASE,
Weave.LOGIN_SUCCEEDED].contains(Weave.Status.login)) {
return;
}

View File

@ -1668,7 +1668,7 @@
if (!docShellsSwapped && !uriIsAboutBlank) {
// pretend the user typed this so it'll be available till
// the document successfully loads
if (aURI && gInitialPages.indexOf(aURI) == -1)
if (aURI && !gInitialPages.contains(aURI))
b.userTypedValue = aURI;
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
@ -2167,14 +2167,14 @@
var tab = aTab;
do {
tab = tab.nextSibling;
} while (tab && remainingTabs.indexOf(tab) == -1);
} while (tab && !remainingTabs.contains(tab));
if (!tab) {
tab = aTab;
do {
tab = tab.previousSibling;
} while (tab && remainingTabs.indexOf(tab) == -1);
} while (tab && !remainingTabs.contains(tab));
}
this.selectedTab = tab;
@ -2422,10 +2422,10 @@
<body>
<![CDATA[
Array.forEach(this.tabs, function(tab) {
if (aTabs.indexOf(tab) == -1)
this.hideTab(tab);
else
if (aTabs.contains(tab))
this.showTab(tab);
else
this.hideTab(tab);
}, this);
this.tabContainer._handleTabSelect(false);

View File

@ -13,7 +13,7 @@ function test() {
function record(aName) {
info("got " + aName);
if (actual.indexOf(aName) == -1)
if (!actual.contains(aName))
actual.push(aName);
if (actual.length == expected.length) {
is(actual.toString(), expected.toString(),

View File

@ -212,8 +212,8 @@ let gClickHandler = {
// Check that all required methods have been called.
gCurrentTest.expectedInvokedMethods.forEach(function(aExpectedMethodName) {
isnot(gInvokedMethods.indexOf(aExpectedMethodName), -1,
gCurrentTest.desc + ":" + aExpectedMethodName + " was invoked");
ok(gInvokedMethods.contains(aExpectedMethodName),
gCurrentTest.desc + ":" + aExpectedMethodName + " was invoked");
});
if (gInvokedMethods.length != gCurrentTest.expectedInvokedMethods.length) {

View File

@ -33,7 +33,7 @@ function promiseObserverCalled(aTopic, aAction) {
ok(true, "got " + aTopic + " notification");
Services.obs.removeObserver(observer, aTopic);
if (kObservedTopics.indexOf(aTopic) != -1) {
if (kObservedTopics.contains(aTopic)) {
if (!(aTopic in gObservedTopics))
gObservedTopics[aTopic] = -1;
else
@ -827,7 +827,7 @@ let gTests = [
if (node.localName == "menuitem")
labels.push(node.getAttribute("label"));
}
is(labels.indexOf(alwaysLabel), -1, "The 'Always Allow' item isn't shown");
ok(!labels.contains(alwaysLabel), "The 'Always Allow' item isn't shown");
// Cleanup.
yield closeStream(true);

View File

@ -38,7 +38,7 @@ function promiseObserverCalled(aTopic, aAction) {
info("Message: " + aData);
Services.obs.removeObserver(observer, aTopic);
if (kObservedTopics.indexOf(aTopic) != -1) {
if (kObservedTopics.contains(aTopic)) {
if (!(aTopic in gObservedTopics))
gObservedTopics[aTopic] = -1;
else

View File

@ -681,7 +681,7 @@ function is_hidden(element) {
if (style.visibility != "visible")
return true;
if (style.display == "-moz-popup")
return ["hiding","closed"].indexOf(element.state) != -1;
return ["hiding","closed"].contains(element.state);
// Hiding a parent element will hide all its children
if (element.parentNode != element.ownerDocument)

View File

@ -891,7 +891,7 @@ function waitForEvents(event)
}
}
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
const isOSXMtnLion = navigator.userAgent.contains("Mac OS X 10.8");
if (isOSXMtnLion) {
todo(false, "Mountain Lion doesn't like this test (bug 792304)");

View File

@ -213,7 +213,7 @@
let protocol = value.match(/^[a-z\d.+\-]+:(?=[^\d])/);
if (protocol &&
["http:", "https:", "ftp:"].indexOf(protocol[0]) == -1)
!["http:", "https:", "ftp:"].contains(protocol[0]))
return;
let matchedURL = value.match(/^((?:[a-z]+:\/\/)?(?:[^\/]+@)?)(.+?)(?::\d+)?(?:\/|$)/);
if (!matchedURL)

View File

@ -98,6 +98,7 @@ this.UITour = {
["help", {query: "#PanelUI-help"}],
["home", {query: "#home-button"}],
["loop", {query: "#loop-call-button"}],
["forget", {query: "#panic-button"}],
["privateWindow", {query: "#privatebrowsing-button"}],
["quit", {query: "#PanelUI-quit"}],
["search", {

View File

@ -344,6 +344,7 @@ toolbarpaletteitem[place="toolbar"] {
}
#customization-lwtheme-menu-footer {
background: linear-gradient(hsla(210,4%,10%,.05) 60%, hsla(210,4%,10%,0)) border-box;
border-top: 1px solid hsla(210,4%,10%,.05);
margin-bottom: -10px;
}
@ -352,22 +353,18 @@ toolbarpaletteitem[place="toolbar"] {
-moz-appearance: none;
-moz-box-flex: 1;
color: hsl(0,0%,50%);
border: 1px solid transparent;
border-style: none;
padding: 10px;
margin-left: 0;
margin-right: 0;
}
.customization-lwtheme-menu-footeritem:hover {
background-color: hsla(210,4%,10%,.15);
background: linear-gradient(hsla(210,4%,10%,.08) 40%, hsla(210,4%,10%,0)) padding-box;
}
#customization-lwtheme-menu-footer:not(:hover) > .customization-lwtheme-menu-footeritem:first-child {
.customization-lwtheme-menu-footeritem:first-child {
-moz-border-end: 1px solid hsla(210,4%,10%,.15);
}
#customization-lwtheme-menu-footer:hover > .customization-lwtheme-menu-footeritem:first-child {
-moz-border-end-color: transparent;
}
%include customizeTip.inc.css

View File

@ -578,7 +578,7 @@ RasterImage::GetType()
}
already_AddRefed<imgFrame>
RasterImage::GetFrameNoDecode(uint32_t aFrameNum)
RasterImage::LookupFrameNoDecode(uint32_t aFrameNum)
{
if (!mAnim) {
NS_ASSERTION(aFrameNum == 0, "Don't ask for a frame > 0 if we're not animated!");
@ -588,7 +588,9 @@ RasterImage::GetFrameNoDecode(uint32_t aFrameNum)
}
DrawableFrameRef
RasterImage::GetFrame(uint32_t aFrameNum)
RasterImage::LookupFrame(uint32_t aFrameNum,
uint32_t aFlags,
bool aShouldSyncNotify /* = true */)
{
if (mMultipart &&
aFrameNum == GetCurrentFrameIndex() &&
@ -600,10 +602,10 @@ RasterImage::GetFrame(uint32_t aFrameNum)
}
// Try our best to start decoding if it's necessary.
nsresult rv = WantDecodedFrames();
nsresult rv = WantDecodedFrames(aFlags, aShouldSyncNotify);
CONTAINER_ENSURE_TRUE(NS_SUCCEEDED(rv), DrawableFrameRef());
nsRefPtr<imgFrame> frame = GetFrameNoDecode(aFrameNum);
nsRefPtr<imgFrame> frame = LookupFrameNoDecode(aFrameNum);
if (!frame) {
return DrawableFrameRef();
}
@ -614,9 +616,17 @@ RasterImage::GetFrame(uint32_t aFrameNum)
MOZ_ASSERT(!mAnim, "Animated frames should be locked");
if (CanForciblyDiscardAndRedecode()) {
ForceDiscard();
WantDecodedFrames();
WantDecodedFrames(aFlags, aShouldSyncNotify);
// See if we managed to entirely redecode the frame.
frame = LookupFrameNoDecode(aFrameNum);
ref = frame->DrawableRef();
}
if (!ref) {
// We didn't successfully redecode, so just fail.
return DrawableFrameRef();
}
return DrawableFrameRef();
}
// We will return a paletted frame if it's not marked as compositing failed
@ -659,7 +669,7 @@ RasterImage::FrameIsOpaque(uint32_t aWhichFrame)
// See if we can get an image frame.
nsRefPtr<imgFrame> frame =
GetFrameNoDecode(GetRequestedFrameIndex(aWhichFrame));
LookupFrameNoDecode(GetRequestedFrameIndex(aWhichFrame));
// If we don't get a frame, the safe answer is "not opaque".
if (!frame)
@ -683,7 +693,7 @@ RasterImage::FrameRect(uint32_t aWhichFrame)
// Get the requested frame.
nsRefPtr<imgFrame> frame =
GetFrameNoDecode(GetRequestedFrameIndex(aWhichFrame));
LookupFrameNoDecode(GetRequestedFrameIndex(aWhichFrame));
// If we have the frame, use that rectangle.
if (frame) {
@ -748,7 +758,8 @@ RasterImage::GetFirstFrameDelay()
TemporaryRef<SourceSurface>
RasterImage::CopyFrame(uint32_t aWhichFrame,
uint32_t aFlags)
uint32_t aFlags,
bool aShouldSyncNotify /* = true */)
{
if (aWhichFrame > FRAME_MAX_VALUE)
return nullptr;
@ -760,27 +771,16 @@ RasterImage::CopyFrame(uint32_t aWhichFrame,
if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
return nullptr;
nsresult rv;
if (!ApplyDecodeFlags(aFlags, aWhichFrame))
return nullptr;
// If requested, synchronously flush any data we have lying around to the decoder
if (aFlags & FLAG_SYNC_DECODE) {
rv = SyncDecode();
CONTAINER_ENSURE_TRUE(NS_SUCCEEDED(rv), nullptr);
}
// Get the frame. If it's not there, it's probably the caller's fault for
// not waiting for the data to be loaded from the network or not passing
// FLAG_SYNC_DECODE
DrawableFrameRef frameRef = GetFrame(GetRequestedFrameIndex(aWhichFrame));
DrawableFrameRef frameRef = LookupFrame(GetRequestedFrameIndex(aWhichFrame),
aFlags, aShouldSyncNotify);
if (!frameRef) {
// The OS threw this frame away.
if (aFlags & FLAG_SYNC_DECODE) {
ForceDiscard();
return CopyFrame(aWhichFrame, aFlags);
}
// The OS threw this frame away and we couldn't redecode it right now.
return nullptr;
}
@ -831,6 +831,14 @@ RasterImage::CopyFrame(uint32_t aWhichFrame,
NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
RasterImage::GetFrame(uint32_t aWhichFrame,
uint32_t aFlags)
{
return GetFrameInternal(aWhichFrame, aFlags);
}
TemporaryRef<SourceSurface>
RasterImage::GetFrameInternal(uint32_t aWhichFrame,
uint32_t aFlags,
bool aShouldSyncNotify /* = true */)
{
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
@ -847,26 +855,16 @@ RasterImage::GetFrame(uint32_t aWhichFrame,
if (!ApplyDecodeFlags(aFlags, aWhichFrame))
return nullptr;
// If the caller requested a synchronous decode, do it
if (aFlags & FLAG_SYNC_DECODE) {
nsresult rv = SyncDecode();
CONTAINER_ENSURE_TRUE(NS_SUCCEEDED(rv), nullptr);
}
// Get the frame. If it's not there, it's probably the caller's fault for
// not waiting for the data to be loaded from the network or not passing
// FLAG_SYNC_DECODE
DrawableFrameRef frameRef = GetFrame(GetRequestedFrameIndex(aWhichFrame));
DrawableFrameRef frameRef = LookupFrame(GetRequestedFrameIndex(aWhichFrame),
aFlags, aShouldSyncNotify);
if (!frameRef) {
// The OS threw this frame away. We'll request a redecode.
if (aFlags & FLAG_SYNC_DECODE) {
ForceDiscard();
return GetFrame(aWhichFrame, aFlags);
}
// The OS threw this frame away and we couldn't redecode it.
return nullptr;
}
// If this frame covers the entire image, we can just reuse its existing
// surface.
RefPtr<SourceSurface> frameSurf;
@ -880,7 +878,7 @@ RasterImage::GetFrame(uint32_t aWhichFrame,
// The image doesn't have a usable surface because it's been optimized away or
// because it's a partial update frame from an animation. Create one.
if (!frameSurf) {
frameSurf = CopyFrame(aWhichFrame, aFlags);
frameSurf = CopyFrame(aWhichFrame, aFlags, aShouldSyncNotify);
}
return frameSurf;
@ -889,21 +887,11 @@ RasterImage::GetFrame(uint32_t aWhichFrame,
already_AddRefed<layers::Image>
RasterImage::GetCurrentImage()
{
if (!mDecoded) {
// We can't call StartDecoding because that can synchronously notify
// which can cause DOM modification
RequestDecodeCore(ASYNCHRONOUS);
return nullptr;
}
RefPtr<SourceSurface> surface = GetFrame(FRAME_CURRENT, FLAG_NONE);
RefPtr<SourceSurface> surface =
GetFrameInternal(FRAME_CURRENT, FLAG_NONE, /* aShouldSyncNotify = */ false);
if (!surface) {
// The OS threw out some or all of our buffer. Start decoding again.
// GetFrame will only return null in the case that the image was
// discarded. We already checked that the image is decoded, so other
// error paths are not possible.
ForceDiscard();
RequestDecodeCore(ASYNCHRONOUS);
// The OS threw out some or all of our buffer. We'll need to wait for the
// redecode (which was automatically triggered by GetFrame) to complete.
return nullptr;
}
@ -1405,7 +1393,7 @@ RasterImage::StartAnimation()
EnsureAnimExists();
nsRefPtr<imgFrame> currentFrame = GetFrameNoDecode(GetCurrentFrameIndex());
nsRefPtr<imgFrame> currentFrame = LookupFrameNoDecode(GetCurrentFrameIndex());
// A timeout of -1 means we should display this frame forever.
if (currentFrame &&
mFrameBlender.GetTimeoutForFrame(GetCurrentFrameIndex()) < 0) {
@ -2137,12 +2125,12 @@ RasterImage::WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy
}
// This function is called in situations where it's clear that we want the
// frames in decoded form (Draw, GetFrame, etc). If we're completely decoded,
// frames in decoded form (Draw, LookupFrame, etc). If we're completely decoded,
// this method resets the discard timer (if we're discardable), since wanting
// the frames now is a good indicator of wanting them again soon. If we're not
// decoded, this method kicks off asynchronous decoding to generate the frames.
nsresult
RasterImage::WantDecodedFrames()
RasterImage::WantDecodedFrames(uint32_t aFlags, bool aShouldSyncNotify)
{
nsresult rv;
@ -2154,8 +2142,17 @@ RasterImage::WantDecodedFrames()
CONTAINER_ENSURE_SUCCESS(rv);
}
// Request a decode (no-op if we're decoded)
return StartDecoding();
// Request a decode, which does nothing if we're already decoded.
if (aShouldSyncNotify) {
// We can sync notify, which means we can also sync decode.
if (aFlags & FLAG_SYNC_DECODE) {
return SyncDecode();
}
return StartDecoding();
}
// We can't sync notify, so do an async decode.
return RequestDecodeCore(ASYNCHRONOUS);
}
//******************************************************************************
@ -2675,7 +2672,8 @@ RasterImage::Draw(gfxContext* aContext,
NS_ENSURE_SUCCESS(rv, rv);
}
DrawableFrameRef ref = GetFrame(GetRequestedFrameIndex(aWhichFrame));
DrawableFrameRef ref = LookupFrame(GetRequestedFrameIndex(aWhichFrame),
aFlags);
if (!ref) {
return NS_OK; // Getting the frame (above) touches the image and kicks off decoding
}
@ -3596,7 +3594,7 @@ RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame,
}
if (!frameRef) {
// We could HQ scale to this size, but we haven't. Request a scale now.
frameRef = GetFrame(GetRequestedFrameIndex(aWhichFrame));
frameRef = LookupFrame(GetRequestedFrameIndex(aWhichFrame), aFlags);
if (frameRef) {
RequestScale(frameRef.get(), aFlags, destSize);
}

View File

@ -541,10 +541,14 @@ private:
uint32_t aFlags);
TemporaryRef<gfx::SourceSurface> CopyFrame(uint32_t aWhichFrame,
uint32_t aFlags);
uint32_t aFlags,
bool aShouldSyncNotify = true);
TemporaryRef<gfx::SourceSurface> GetFrameInternal(uint32_t aWhichFrame,
uint32_t aFlags,
bool aShouldSyncNotify = true);
already_AddRefed<imgFrame> GetFrameNoDecode(uint32_t aFrameNum);
DrawableFrameRef GetFrame(uint32_t aFrameNum);
already_AddRefed<imgFrame> LookupFrameNoDecode(uint32_t aFrameNum);
DrawableFrameRef LookupFrame(uint32_t aFrameNum, uint32_t aFlags, bool aShouldSyncNotify = true);
uint32_t GetCurrentFrameIndex() const;
uint32_t GetRequestedFrameIndex(uint32_t aWhichFrame) const;
@ -696,7 +700,7 @@ private: // data
eShutdownIntent aIntent,
bool aDone,
bool aWasSize);
nsresult WantDecodedFrames();
nsresult WantDecodedFrames(uint32_t aFlags, bool aShouldSyncNotify);
nsresult SyncDecode();
nsresult InitDecoder(bool aDoSizeDecode);
nsresult WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy aStrategy);

View File

@ -5,22 +5,20 @@
package org.mozilla.gecko;
import java.util.Set;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
import android.content.Context;
import android.os.Bundle;
import android.os.UserManager;
import android.util.Log;
import java.lang.StringBuilder;
import java.util.HashSet;
import java.util.Set;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
@RobocopTarget
public class RestrictedProfiles {
private static final String LOGTAG = "GeckoRestrictedProfiles";
@ -28,12 +26,13 @@ public class RestrictedProfiles {
public static enum Restriction {
DISALLOW_DOWNLOADS(1, "no_download_files"),
DISALLOW_INSTALL_EXTENSIONS(2, "no_install_extensions"),
DISALLOW_INSTALL_APPS(3, UserManager.DISALLOW_INSTALL_APPS),
DISALLOW_INSTALL_APPS(3, "no_install_apps"), // UserManager.DISALLOW_INSTALL_APPS
DISALLOW_BROWSE_FILES(4, "no_browse_files"),
DISALLOW_SHARE(5, "no_share"),
DISALLOW_BOOKMARK(6, "no_bookmark"),
DISALLOW_ADD_CONTACTS(7, "no_add_contacts"),
DISALLOW_SET_IMAGE(8, "no_set_image");
DISALLOW_SET_IMAGE(8, "no_set_image"),
DISALLOW_MODIFY_ACCOUNTS(9, "no_modify_accounts"); // UserManager.DISALLOW_MODIFY_ACCOUNTS
public final int id;
public final String name;
@ -54,6 +53,7 @@ public class RestrictedProfiles {
throw new IllegalArgumentException("Unknown action " + action);
}
@RobocopTarget
private static Bundle getRestrictions() {
final UserManager mgr = (UserManager) GeckoAppShell.getContext().getSystemService(Context.USER_SERVICE);
return mgr.getUserRestrictions();

View File

@ -15,6 +15,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.RestrictedProfiles;
import org.mozilla.gecko.home.HomeConfig.HomeConfigBackend;
import org.mozilla.gecko.home.HomeConfig.OnReloadListener;
import org.mozilla.gecko.home.HomeConfig.PanelConfig;
@ -81,18 +82,29 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
final PanelConfig historyEntry = createBuiltinPanelConfig(mContext, PanelType.HISTORY);
final PanelConfig recentTabsEntry = createBuiltinPanelConfig(mContext, PanelType.RECENT_TABS);
final PanelConfig remoteTabsEntry = createBuiltinPanelConfig(mContext, PanelType.REMOTE_TABS);
// We disable Synced Tabs for guest mode profiles.
final PanelConfig remoteTabsEntry;
if (RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
remoteTabsEntry = createBuiltinPanelConfig(mContext, PanelType.REMOTE_TABS);
} else {
remoteTabsEntry = null;
}
// On tablets, we go [...|History|Recent Tabs|Synced Tabs].
// On phones, we go [Synced Tabs|Recent Tabs|History|...].
if (HardwareUtils.isTablet()) {
panelConfigs.add(historyEntry);
panelConfigs.add(recentTabsEntry);
panelConfigs.add(remoteTabsEntry);
if (remoteTabsEntry != null) {
panelConfigs.add(remoteTabsEntry);
}
} else {
panelConfigs.add(0, historyEntry);
panelConfigs.add(0, recentTabsEntry);
panelConfigs.add(0, remoteTabsEntry);
if (remoteTabsEntry != null) {
panelConfigs.add(0, remoteTabsEntry);
}
}
return new State(panelConfigs, true);

View File

@ -625,7 +625,7 @@ public class TopSitesPanel extends HomeFragment {
// Only try to fetch thumbnails for non-empty URLs that
// don't have an associated suggested image URL.
if (TextUtils.isEmpty(url) || TextUtils.isEmpty(imageUrl)) {
if (TextUtils.isEmpty(url) || !TextUtils.isEmpty(imageUrl)) {
continue;
}

View File

@ -29,6 +29,7 @@ import org.mozilla.gecko.LocaleManager;
import org.mozilla.gecko.NewTabletUI;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.R;
import org.mozilla.gecko.RestrictedProfiles;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.TelemetryContract.Method;
@ -717,7 +718,8 @@ OnSharedPreferenceChangeListener
CharSequence selectedEntry = listPref.getEntry();
listPref.setSummary(selectedEntry);
continue;
} else if (PREFS_SYNC.equals(key) && GeckoProfile.get(this).inGuestMode()) {
} else if (PREFS_SYNC.equals(key) &&
!RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
// Don't show sync prefs while in guest mode.
preferences.removePreference(pref);
i--;

View File

@ -15,6 +15,7 @@ import org.mozilla.gecko.LightweightTheme;
import org.mozilla.gecko.LightweightThemeDrawable;
import org.mozilla.gecko.NewTabletUI;
import org.mozilla.gecko.R;
import org.mozilla.gecko.RestrictedProfiles;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.animation.PropertyAnimator;
@ -173,7 +174,7 @@ public class TabsPanel extends LinearLayout
mTabWidget.addTab(R.drawable.tabs_normal, R.string.tabs_normal);
mTabWidget.addTab(R.drawable.tabs_private, R.string.tabs_private);
if (!GeckoProfile.get(mContext).inGuestMode()) {
if (RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
// The initial icon is not the animated icon, because on Android
// 4.4.2, the animation starts immediately (and can start at other
// unpredictable times). See Bug 1015974.

View File

@ -26,8 +26,7 @@ add_task(function test_isUserRestricted() {
do_check_true(pc.isAllowed(Ci.nsIParentalControlsService.SHARE));
do_check_true(pc.isAllowed(Ci.nsIParentalControlsService.BOOKMARK));
do_check_true(pc.isAllowed(Ci.nsIParentalControlsService.INSTALL_EXTENSION));
run_next_test();
do_check_true(pc.isAllowed(Ci.nsIParentalControlsService.MODIFY_ACCOUNTS));
});
add_task(function test_getUserRestrictions() {

View File

@ -0,0 +1,47 @@
[DEFAULT]
subsuite = background
[src/common/TestAndroidLogWriters.java]
[src/common/TestBrowserContractHelpers.java]
[src/common/TestDateUtils.java]
[src/common/TestUtils.java]
[src/common/TestWaitHelper.java]
[src/db/TestAndroidBrowserBookmarksRepository.java]
[src/db/TestAndroidBrowserHistoryDataExtender.java]
[src/db/TestAndroidBrowserHistoryRepository.java]
[src/db/TestBookmarks.java]
[src/db/TestCachedSQLiteOpenHelper.java]
[src/db/TestClientsDatabase.java]
[src/db/TestClientsDatabaseAccessor.java]
[src/db/TestFennecTabsRepositorySession.java]
[src/db/TestFennecTabsStorage.java]
[src/db/TestFormHistoryRepositorySession.java]
[src/db/TestPasswordsRepository.java]
[src/fxa/TestBrowserIDKeyPairGeneration.java]
[src/fxa/authenticator/TestAccountPickler.java]
[src/healthreport/TestEnvironmentBuilder.java]
[src/healthreport/TestEnvironmentV1HashAppender.java]
[src/healthreport/TestHealthReportBroadcastService.java]
[src/healthreport/TestHealthReportDatabaseStorage.java]
[src/healthreport/TestHealthReportGenerator.java]
[src/healthreport/TestHealthReportProvider.java]
[src/healthreport/TestHealthReportSQLiteOpenHelper.java]
[src/healthreport/TestProfileInformationCache.java]
[src/healthreport/prune/TestHealthReportPruneService.java]
[src/healthreport/prune/TestPrunePolicyDatabaseStorage.java]
[src/healthreport/upload/TestAndroidSubmissionClient.java]
[src/healthreport/upload/TestHealthReportUploadService.java]
[src/nativecode/test/TestNativeCrypto.java]
[src/sync/TestAccountPickler.java]
[src/sync/TestClientsStage.java]
[src/sync/TestConfigurationMigrator.java]
[src/sync/TestResetting.java]
[src/sync/TestSendTabData.java]
[src/sync/TestStoreTracking.java]
[src/sync/TestSyncAccounts.java]
[src/sync/TestSyncAuthenticatorService.java]
[src/sync/TestSyncConfiguration.java]
[src/sync/TestTabsRecord.java]
[src/sync/TestUpgradeRequired.java]
[src/sync/TestWebURLFinder.java]
[src/telemetry/TestTelemetryRecorder.java]

View File

@ -21,3 +21,5 @@ main.referenced_projects += ['Fennec']
main.add_classpathentry('src', SRCDIR + '/src',
dstdir='src/org/mozilla/gecko/background')
ANDROID_INSTRUMENTATION_MANIFESTS += ['instrumentation.ini']

View File

@ -0,0 +1,10 @@
[DEFAULT]
subsuite = browser
[src/TestDistribution.java]
[src/TestGeckoSharedPrefs.java]
[src/TestImageDownloader.java]
[src/TestJarReader.java]
[src/TestRawResource.java]
[src/TestSuggestedSites.java]
[src/TestTopSitesCursorWrapper.java]

View File

@ -37,3 +37,5 @@ main.referenced_projects += ['Fennec']
main.add_classpathentry('src', SRCDIR + '/src',
dstdir='src/org/mozilla/gecko')
ANDROID_INSTRUMENTATION_MANIFESTS += ['instrumentation.ini']

View File

@ -821,6 +821,10 @@ VARIABLES = {
These are commonly named crashtests.list.
""", None),
'ANDROID_INSTRUMENTATION_MANIFESTS': (StrictOrderingOnAppendList, list,
"""List of manifest files defining Android instrumentation tests.
""", None),
'METRO_CHROME_MANIFESTS': (StrictOrderingOnAppendList, list,
"""List of manifest files defining metro browser chrome tests.
""", None),

View File

@ -750,28 +750,32 @@ class TreeMetadataEmitter(LoggingMixin):
# Keys are variable prefixes and values are tuples describing how these
# manifests should be handled:
#
# (flavor, install_prefix, active)
# (flavor, install_prefix, active, package_tests)
#
# flavor identifies the flavor of this test.
# install_prefix is the path prefix of where to install the files in
# the tests directory.
# active indicates whether to filter out inactive tests from the
# manifest.
# package_tests indicates whether to package test files into the test
# package; suites that compile the test files should not install
# them into the test package.
#
# We ideally don't filter out inactive tests. However, not every test
# harness can yet deal with test filtering. Once all harnesses can do
# this, this feature can be dropped.
test_manifests = dict(
A11Y=('a11y', 'testing/mochitest', 'a11y', True),
BROWSER_CHROME=('browser-chrome', 'testing/mochitest', 'browser', True),
JETPACK_PACKAGE=('jetpack-package', 'testing/mochitest', 'jetpack-package', True),
JETPACK_ADDON=('jetpack-addon', 'testing/mochitest', 'jetpack-addon', True),
METRO_CHROME=('metro-chrome', 'testing/mochitest', 'metro', True),
MOCHITEST=('mochitest', 'testing/mochitest', 'tests', True),
MOCHITEST_CHROME=('chrome', 'testing/mochitest', 'chrome', True),
MOCHITEST_WEBAPPRT_CHROME=('webapprt-chrome', 'testing/mochitest', 'webapprtChrome', True),
WEBRTC_SIGNALLING_TEST=('steeplechase', 'steeplechase', '.', True),
XPCSHELL_TESTS=('xpcshell', 'xpcshell', '.', False),
A11Y=('a11y', 'testing/mochitest', 'a11y', True, True),
BROWSER_CHROME=('browser-chrome', 'testing/mochitest', 'browser', True, True),
ANDROID_INSTRUMENTATION=('instrumentation', 'instrumentation', '.', False, False),
JETPACK_PACKAGE=('jetpack-package', 'testing/mochitest', 'jetpack-package', True, True),
JETPACK_ADDON=('jetpack-addon', 'testing/mochitest', 'jetpack-addon', True, False),
METRO_CHROME=('metro-chrome', 'testing/mochitest', 'metro', True, True),
MOCHITEST=('mochitest', 'testing/mochitest', 'tests', True, True),
MOCHITEST_CHROME=('chrome', 'testing/mochitest', 'chrome', True, True),
MOCHITEST_WEBAPPRT_CHROME=('webapprt-chrome', 'testing/mochitest', 'webapprtChrome', True, True),
WEBRTC_SIGNALLING_TEST=('steeplechase', 'steeplechase', '.', True, True),
XPCSHELL_TESTS=('xpcshell', 'xpcshell', '.', False, True),
)
for prefix, info in test_manifests.items():
@ -823,7 +827,7 @@ class TreeMetadataEmitter(LoggingMixin):
return sub
def _process_test_manifest(self, context, info, manifest_path):
flavor, install_root, install_subdir, filter_inactive = info
flavor, install_root, install_subdir, filter_inactive, package_tests = info
manifest_path = mozpath.normpath(manifest_path)
path = mozpath.normpath(mozpath.join(context.srcdir, manifest_path))
@ -930,9 +934,9 @@ class TreeMetadataEmitter(LoggingMixin):
for test in filtered:
obj.tests.append(test)
# Jetpack add-on tests are generated directly in the test
# directory
if flavor != 'jetpack-addon':
# Some test files are compiled and should not be copied into the
# test package. They function as identifiers rather than files.
if package_tests:
obj.installs[mozpath.normpath(test['path'])] = \
(mozpath.join(out_dir, test['relpath']), True)

View File

@ -0,0 +1,10 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
MOCHITEST_MANIFESTS += [
'mochitest.ini',
]
ANDROID_INSTRUMENTATION_MANIFESTS += [
'instrumentation.ini',
]

View File

@ -687,6 +687,37 @@ class TestRecursiveMakeBackend(BackendTester):
stem = '%s/android_eclipse/%s' % (env.topobjdir, project_name)
self.assertIn(command_template % (stem, stem), lines)
def test_install_manifests_package_tests(self):
"""Ensure test suites honor package_tests=False."""
env = self._consume('test-manifests-package-tests', RecursiveMakeBackend)
tests_dir = mozpath.join(env.topobjdir, '_tests')
all_tests_path = mozpath.join(env.topobjdir, 'all-tests.json')
self.assertTrue(os.path.exists(all_tests_path))
with open(all_tests_path, 'rt') as fh:
o = json.load(fh)
self.assertIn('mochitest.js', o)
self.assertIn('not_packaged.java', o)
man_dir = mozpath.join(env.topobjdir, '_build_manifests', 'install')
self.assertTrue(os.path.isdir(man_dir))
full = mozpath.join(man_dir, 'tests')
self.assertTrue(os.path.exists(full))
m = InstallManifest(path=full)
# Only mochitest.js should be in the install manifest.
self.assertTrue('testing/mochitest/tests/mochitest.js' in m)
# The path is odd here because we do not normalize at test manifest
# processing time. This is a fragile test because there's currently no
# way to iterate the manifest.
self.assertFalse('instrumentation/./not_packaged.java' in m)
if __name__ == '__main__':
main()

View File

@ -101,6 +101,32 @@ ALL_TESTS_JSON = b'''
"support-files": "\\ndata/**\\nxpcshell_updater.ini",
"tail": ""
}
],
"mobile/android/tests/background/junit3/src/common/TestAndroidLogWriters.java": [
{
"dir_relpath": "mobile/android/tests/background/junit3/src/common",
"file_relpath": "mobile/android/tests/background/junit3/src/common/TestAndroidLogWriters.java",
"flavor": "instrumentation",
"here": "/Users/nalexander/Mozilla/gecko-dev/mobile/android/tests/background/junit3",
"manifest": "/Users/nalexander/Mozilla/gecko-dev/mobile/android/tests/background/junit3/instrumentation.ini",
"name": "src/common/TestAndroidLogWriters.java",
"path": "/Users/nalexander/Mozilla/gecko-dev/mobile/android/tests/background/junit3/src/common/TestAndroidLogWriters.java",
"relpath": "src/common/TestAndroidLogWriters.java",
"subsuite": "background"
}
],
"mobile/android/tests/browser/junit3/src/TestDistribution.java": [
{
"dir_relpath": "mobile/android/tests/browser/junit3/src",
"file_relpath": "mobile/android/tests/browser/junit3/src/TestDistribution.java",
"flavor": "instrumentation",
"here": "/Users/nalexander/Mozilla/gecko-dev/mobile/android/tests/browser/junit3",
"manifest": "/Users/nalexander/Mozilla/gecko-dev/mobile/android/tests/browser/junit3/instrumentation.ini",
"name": "src/TestDistribution.java",
"path": "/Users/nalexander/Mozilla/gecko-dev/mobile/android/tests/browser/junit3/src/TestDistribution.java",
"relpath": "src/TestDistribution.java",
"subsuite": "browser"
}
]
}'''.strip()
@ -127,14 +153,14 @@ class Base(unittest.TestCase):
class TestTestMetadata(Base):
def test_load(self):
t = self._get_test_metadata()
self.assertEqual(len(t._tests_by_path), 4)
self.assertEqual(len(t._tests_by_path), 6)
self.assertEqual(len(list(t.tests_with_flavor('xpcshell'))), 3)
self.assertEqual(len(list(t.tests_with_flavor('mochitest-plain'))), 0)
def test_resolve_all(self):
t = self._get_test_metadata()
self.assertEqual(len(list(t.resolve_tests())), 5)
self.assertEqual(len(list(t.resolve_tests())), 7)
def test_resolve_filter_flavor(self):
t = self._get_test_metadata()
@ -213,6 +239,22 @@ class TestTestResolver(Base):
actual = list(r.resolve_tests(paths=['services'], cwd=r.topobjdir))
self.assertEqual(actual, expected)
def test_subsuites(self):
"""Test filtering by subsuite."""
r = self._get_resolver()
tests = list(r.resolve_tests(paths=['mobile']))
self.assertEqual(len(tests), 2)
tests = list(r.resolve_tests(paths=['mobile'], subsuite='browser'))
self.assertEqual(len(tests), 1)
self.assertEqual(tests[0]['name'], 'src/TestDistribution.java')
tests = list(r.resolve_tests(paths=['mobile'], subsuite='background'))
self.assertEqual(len(tests), 1)
self.assertEqual(tests[0]['name'], 'src/common/TestAndroidLogWriters.java')
if __name__ == '__main__':
main()

View File

@ -70,7 +70,7 @@ class TestMetadata(object):
for path in sorted(self._tests_by_flavor.get(flavor, [])):
yield self._tests_by_path[path]
def resolve_tests(self, paths=None, flavor=None, under_path=None):
def resolve_tests(self, paths=None, flavor=None, subsuite=None, under_path=None):
"""Resolve tests from an identifier.
This is a generator of dicts describing each test.
@ -88,6 +88,9 @@ class TestMetadata(object):
If ``flavor`` is a string, it will be used to filter returned tests
to only be the flavor specified. A flavor is something like
``xpcshell``.
If ``subsuite`` is a string, it will be used to filter returned tests
to only be in the subsuite specified.
"""
def fltr(tests):
for test in tests:
@ -96,6 +99,9 @@ class TestMetadata(object):
(flavor != 'devtools' and test.get('flavor') != flavor):
continue
if subsuite and test.get('subsuite') != subsuite:
continue
if under_path \
and not test['file_relpath'].startswith(under_path):
continue

View File

@ -11,7 +11,7 @@ interface nsIFile;
interface nsIInterfaceRequestor;
interface nsIArray;
[scriptable, uuid(b3585b2a-b4b3-4aa7-be92-b8ddaa6aec5f)]
[scriptable, uuid(4bde6754-406a-45d1-b18e-dc685adc1db4)]
interface nsIParentalControlsService : nsISupports
{
/**
@ -25,6 +25,7 @@ interface nsIParentalControlsService : nsISupports
const short BOOKMARK = 6; // Creating bookmarks
const short ADD_CONTACT = 7; // Add contacts to the system database
const short SET_IMAGE = 8; // Setting images as wall paper
const short MODIFY_ACCOUNTS = 9; // Modifying system accounts
/**
* @returns true if the current user account has parental controls