Merge m-c to inbound.

--HG--
rename : dom/contacts/tests/test_contacts_upgrade.html => dom/contacts/tests/test_contacts_upgrade.xul
rename : dom/indexedDB/test/test_globalObjects.xul => dom/indexedDB/test/test_globalObjects_chrome.xul
rename : dom/indexedDB/test/test_globalObjects.html => dom/indexedDB/test/test_globalObjects_content.html
rename : dom/indexedDB/test/unit/test_globalObjects.js => dom/indexedDB/test/unit/test_globalObjects_xpc.js
This commit is contained in:
Ryan VanderMeulen 2013-11-19 13:54:20 -05:00
commit 554a83ef67
75 changed files with 2333 additions and 1726 deletions

View File

@ -191,21 +191,22 @@ let PaymentProvider = {
},
#ifdef MOZ_B2G_RIL
// Until bug 814629 is done, we only have support for a single SIM, so we
// can only provide information for a single ICC. However, we return an array
// so the payment provider facing API won't need to change once we support
// multiple SIMs.
// Bug 938993. Support Multi-SIM for Payments.
get iccInfo() {
delete this.iccInfo;
return this.iccInfo = iccProvider.getIccInfo(0);
},
get iccIds() {
return [iccProvider.iccInfo.iccid];
return [this.iccInfo.iccid];
},
get mcc() {
return [iccProvider.iccInfo.mcc];
return [this.iccInfo.mcc];
},
get mnc() {
return [iccProvider.iccInfo.mnc];
return [this.iccInfo.mnc];
},
_silentNumbers: null,

View File

@ -1,4 +1,4 @@
{
"revision": "8ef103bc368f8309e42cffb648fa73ab756b2599",
"revision": "4e8959a60a4ee1373e71fe31229ba5bd7575c02c",
"repo_path": "/integration/gaia-central"
}

View File

@ -963,6 +963,9 @@ var gPluginHandler = {
return;
}
Services.telemetry.getHistogramById("PLUGINS_INFOBAR_SHOWN").
add(true);
let message;
// Icons set directly cannot be manipulated using moz-image-region, so
// we use CSS classes instead.
@ -1001,21 +1004,26 @@ var gPluginHandler = {
}
}
// These strings are temporary no-string-change for branch uplift
let buttons = [
{
label: gNavigatorBundle.getString("pluginBlockNow.label"),
accessKey: gNavigatorBundle.getString("pluginBlockNow.accesskey"),
label: gNavigatorBundle.getString("pluginContinueBlocking.label"),
accessKey: gNavigatorBundle.getString("pluginContinueBlocking.accesskey"),
callback: function() {
Services.telemetry.getHistogramById("PLUGINS_INFOBAR_BLOCK").
add(true);
Services.perms.addFromPrincipal(aBrowser.contentDocument.nodePrincipal,
"plugin-hidden-notification",
Services.perms.DENY_ACTION);
}
},
{
label: gNavigatorBundle.getString("offlineApps.allow"),
accessKey: gNavigatorBundle.getString("offlineApps.allowAccessKey"),
label: gNavigatorBundle.getString("pluginActivateTrigger.label"),
accessKey: gNavigatorBundle.getString("pluginActivateTrigger.accesskey"),
callback: function() {
Services.telemetry.getHistogramById("PLUGINS_INFOBAR_ALLOW").
add(true);
let curNotification =
PopupNotifications.getNotification("click-to-play-plugins",
aBrowser);

View File

@ -2071,6 +2071,12 @@ this.CustomizableUI = {
onWidgetDrag: function(aWidgetId, aArea) {
CustomizableUIInternal.notifyListeners("onWidgetDrag", aWidgetId, aArea);
},
notifyStartCustomizing: function(aWindow) {
CustomizableUIInternal.notifyListeners("onCustomizeStart", aWindow);
},
notifyEndCustomizing: function(aWindow) {
CustomizableUIInternal.notifyListeners("onCustomizeEnd", aWindow);
},
isAreaOverflowable: function(aAreaId) {
let area = gAreas.get(aAreaId);
return area ? area.get("type") == this.TYPE_TOOLBAR && area.get("overflowable")

View File

@ -111,6 +111,7 @@ CustomizeMode.prototype = {
this.document.documentElement._lightweightTheme.disable();
this.dispatchToolboxEvent("beforecustomization");
CustomizableUI.notifyStartCustomizing(this.window);
let window = this.window;
let document = this.document;
@ -285,6 +286,7 @@ CustomizeMode.prototype = {
this._changed = false;
this._transitioning = false;
this.dispatchToolboxEvent("aftercustomization");
CustomizableUI.notifyEndCustomizing(this.window);
}.bind(this)).then(null, ERROR);
},

View File

@ -178,6 +178,7 @@ body {
pointer-events: none;
}
body.dim > #header > #element-position,
body.dim > #main > p,
body.dim > #main > .tooltip {
visibility: hidden;

View File

@ -46,6 +46,9 @@ LayoutView.prototype = {
// 'property' is what we are measuring;
// 'value' is the computed dimension, computed in update().
this.map = {
position: {selector: "#element-position",
property: "position",
value: undefined},
marginTop: {selector: ".margin.top > span",
property: "margin-top",
value: undefined},
@ -201,7 +204,19 @@ LayoutView.prototype = {
for (let i in this.map) {
let property = this.map[i].property;
this.map[i].value = parseInt(layout[property]);
if (!(property in layout)) {
// Depending on the actor version, some properties
// might be missing.
continue;
}
let parsedValue = parseInt(layout[property]);
if (Number.isNaN(parsedValue)) {
// Not a number. We use the raw string.
// Useful for "position" for example.
this.map[i].value = layout[property];
} else {
this.map[i].value = parsedValue;
}
}
let margins = layout.autoMargins;

View File

@ -74,7 +74,7 @@
<body class="theme-body devtools-monospace">
<p id="header">
<span id="element-size"></span>
<span id="element-size"></span><span id="element-position"></span>
</p>
<div id="main">

View File

@ -229,7 +229,7 @@ CssHtmlTree.processTemplate = function CssHtmlTree_processTemplate(aTemplate,
};
XPCOMUtils.defineLazyGetter(CssHtmlTree, "_strings", function() Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
.createBundle("chrome://global/locale/devtools/styleinspector.properties"));
XPCOMUtils.defineLazyGetter(this, "clipboardHelper", function() {
return Cc["@mozilla.org/widget/clipboardhelper;1"].

View File

@ -2446,7 +2446,7 @@ XPCOMUtils.defineLazyGetter(this, "clipboardHelper", function() {
XPCOMUtils.defineLazyGetter(this, "_strings", function() {
return Services.strings.createBundle(
"chrome://browser/locale/devtools/styleinspector.properties");
"chrome://global/locale/devtools/styleinspector.properties");
});
XPCOMUtils.defineLazyGetter(this, "domUtils", function() {

View File

@ -14,7 +14,7 @@ loader.lazyGetter(this, "gDevTools", () => Cu.import("resource:///modules/devtoo
loader.lazyGetter(this, "RuleView", () => require("devtools/styleinspector/rule-view"));
loader.lazyGetter(this, "ComputedView", () => require("devtools/styleinspector/computed-view"));
loader.lazyGetter(this, "_strings", () => Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
.createBundle("chrome://global/locale/devtools/styleinspector.properties"));
// This module doesn't currently export any symbols directly, it only
// registers inspector tools.

View File

@ -47,7 +47,7 @@ function checkCssLogic()
cssLogic.processMatchedSelectors();
let _strings = Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties");
.createBundle("chrome://global/locale/devtools/styleinspector.properties");
let inline = _strings.GetStringFromName("rule.sourceInline");

View File

@ -41,7 +41,7 @@ function checkSheets()
let elementStyle = ruleView()._elementStyle;
let _strings = Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties");
.createBundle("chrome://global/locale/devtools/styleinspector.properties");
let inline = _strings.GetStringFromName("rule.sourceInline");

View File

@ -163,6 +163,14 @@ PluginClickToActivate=Activate %S.
PluginVulnerableUpdatable=This plugin is vulnerable and should be updated.
PluginVulnerableNoUpdate=This plugin has security vulnerabilities.
# infobar UI
pluginContinueBlocking.label=Continue Blocking
pluginContinueBlocking.accesskey=B
# LOCALIZATION NOTE (pluginActivateTrigger): Use the unicode ellipsis char, \u2026,
# or use "..." if \u2026 doesn't suit traditions in your locale.
pluginActivateTrigger.label=Allow…
pluginActivateTrigger.accesskey=A
# Sanitize
# LOCALIZATION NOTE (sanitizeDialog2.everything.title): When "Time range to
# clear" is set to "Everything", the Clear Recent History dialog's title is

View File

@ -39,7 +39,6 @@
locale/browser/devtools/scratchpad.dtd (%chrome/browser/devtools/scratchpad.dtd)
locale/browser/devtools/styleeditor.properties (%chrome/browser/devtools/styleeditor.properties)
locale/browser/devtools/styleeditor.dtd (%chrome/browser/devtools/styleeditor.dtd)
locale/browser/devtools/styleinspector.properties (%chrome/browser/devtools/styleinspector.properties)
locale/browser/devtools/styleinspector.dtd (%chrome/browser/devtools/styleinspector.dtd)
locale/browser/devtools/webConsole.dtd (%chrome/browser/devtools/webConsole.dtd)
locale/browser/devtools/VariablesView.dtd (%chrome/browser/devtools/VariablesView.dtd)

View File

@ -39,30 +39,52 @@ var APZCObserver = {
handleEvent: function APZC_handleEvent(aEvent) {
switch (aEvent.type) {
case 'pageshow':
if (aEvent.target != Browser.selectedBrowser.contentDocument)
break;
// fall through to TabSelect:
case 'TabSelect':
// ROOT_ID doesn't really identify the view we want. When we call
// this on a content document (tab), findElementWithViewId will
// always return the root content document associated with the
// scrollable frame.
const ROOT_ID = 1;
let windowUtils = Browser.selectedBrowser.contentWindow.
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
// findElementWithViewId will throw if it can't find it
let element;
try {
element = windowUtils.findElementWithViewId(ROOT_ID);
} catch (e) {
// Not present; nothing to do here
if (aEvent.target != Browser.selectedBrowser.contentDocument) {
break;
}
windowUtils.setDisplayPortForElement(0, 0, ContentAreaObserver.width,
ContentAreaObserver.height,
element);
// intentional fall through
case 'TabSelect': {
// Start off with something reasonable. The apzc will handle these
// calculations once scrolling starts.
let doc = Browser.selectedBrowser.contentDocument.documentElement;
// While running tests, sometimes this can be null. If we don't have a
// root document, there's no point in setting a scrollable display port.
if (!doc) {
break;
}
let win = Browser.selectedBrowser.contentWindow;
let factor = 0.2;
let portX = 0;
let portY = 0;
let portWidth = ContentAreaObserver.width;
let portHeight = ContentAreaObserver.height;
if (portWidth < doc.scrollWidth) {
portWidth += ContentAreaObserver.width * factor;
if (portWidth > doc.scrollWidth) {
portWidth = doc.scrollWidth;
}
}
if (portHeight < doc.scrollHeight) {
portHeight += ContentAreaObserver.height * factor;
if (portHeight > doc.scrollHeight) {
portHeight = doc.scrollHeight;
}
}
if (win.scrollX > 0) {
portX -= ContentAreaObserver.width * factor;
}
if (win.scrollY > 0) {
portY -= ContentAreaObserver.height * factor;
}
let cwu = Browser.selectedBrowser.contentWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
cwu.setDisplayPortForElement(portX, portY,
portWidth, portHeight,
Browser.selectedBrowser.contentDocument.documentElement);
break;
}
case 'TabOpen': {
let browser = aEvent.originalTarget.linkedBrowser;
browser.addEventListener("pageshow", this, true);

View File

@ -253,6 +253,7 @@ var SelectionHelperUI = {
_endMark: null,
_caretMark: null,
_target: null,
_showAfterUpdate: false,
_movement: { active: false, x:0, y: 0 },
_activeSelectionRect: null,
_selectionMarkIds: [],
@ -350,13 +351,29 @@ var SelectionHelperUI = {
*/
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "attach_edit_session_to_content":
let event = aSubject;
SelectionHelperUI.attachEditSession(Browser.selectedTab.browser,
event.clientX, event.clientY);
break;
}
switch (aTopic) {
case "attach_edit_session_to_content":
let event = aSubject;
this.attachEditSession(Browser.selectedTab.browser,
event.clientX, event.clientY);
break;
case "apzc-handle-pan-begin":
if (this.isActive && this.layerMode == kContentLayer) {
this._hideMonocles();
}
break;
case "apzc-handle-pan-end":
// The selection range callback will check to see if the new
// position is off the screen, in which case it shuts down and
// clears the selection.
if (this.isActive && this.layerMode == kContentLayer) {
this._showAfterUpdate = true;
this._sendAsyncMessage("Browser:SelectionUpdate", {});
}
break;
}
},
/*
@ -530,7 +547,10 @@ var SelectionHelperUI = {
*/
init: function () {
Services.obs.addObserver(this, "attach_edit_session_to_content", false);
let os = Services.obs;
os.addObserver(this, "attach_edit_session_to_content", false);
os.addObserver(this, "apzc-handle-pan-begin", false);
os.addObserver(this, "apzc-handle-pan-end", false);
},
_init: function _init(aMsgTarget) {
@ -908,6 +928,16 @@ var SelectionHelperUI = {
this._shutdown();
},
_checkMonocleVisibility: function(aX, aY) {
if (aX < 0 || aY < 0 ||
aX > ContentAreaObserver.viewableWidth ||
aY > ContentAreaObserver.viewableHeight) {
this.closeEditSession(true);
return false;
}
return true;
},
/*
* Message handlers
*/
@ -920,26 +950,43 @@ var SelectionHelperUI = {
let haveSelectionRect = true;
if (json.updateStart) {
this.startMark.position(this._msgTarget.btocx(json.start.xPos, true),
this._msgTarget.btocy(json.start.yPos, true));
let x = this._msgTarget.btocx(json.start.xPos, true);
let y = this._msgTarget.btocx(json.start.yPos, true);
if (!this._checkMonocleVisibility(x, y)) {
return;
}
this.startMark.position(x, y);
}
if (json.updateEnd) {
this.endMark.position(this._msgTarget.btocx(json.end.xPos, true),
this._msgTarget.btocy(json.end.yPos, true));
let x = this._msgTarget.btocx(json.end.xPos, true);
let y = this._msgTarget.btocx(json.end.yPos, true);
if (!this._checkMonocleVisibility(x, y)) {
return;
}
this.endMark.position(x, y);
}
if (json.updateCaret) {
let x = this._msgTarget.btocx(json.caret.xPos, true);
let y = this._msgTarget.btocx(json.caret.yPos, true);
if (!this._checkMonocleVisibility(x, y)) {
return;
}
// If selectionRangeFound is set SelectionHelper found a range we can
// attach to. If not, there's no text in the control, and hence no caret
// position information we can use.
haveSelectionRect = json.selectionRangeFound;
if (json.selectionRangeFound) {
this.caretMark.position(this._msgTarget.btocx(json.caret.xPos, true),
this._msgTarget.btocy(json.caret.yPos, true));
this.caretMark.position(x, y);
this.caretMark.show();
}
}
if (this._showAfterUpdate) {
this._showAfterUpdate = false;
this._showMonocles(!json.updateCaret);
}
this._targetIsEditable = json.targetIsEditable;
this._activeSelectionRect = haveSelectionRect ?
this._msgTarget.rectBrowserToClient(json.selection, true) :

View File

@ -38,7 +38,7 @@
background-color: -moz-Dialog;
}
#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar) {
padding-top: 1px;
padding-bottom: 1px;
}

View File

@ -961,7 +961,7 @@ MediaDecoder::GetStatistics()
double MediaDecoder::ComputePlaybackRate(bool* aReliable)
{
GetReentrantMonitor().AssertCurrentThreadIn();
MOZ_ASSERT(NS_IsMainThread() || OnStateMachineThread());
MOZ_ASSERT(NS_IsMainThread() || OnStateMachineThread() || OnDecodeThread());
int64_t length = mResource ? mResource->GetLength() : -1;
if (mDuration >= 0 && length >= 0) {

View File

@ -1829,52 +1829,44 @@ bool MediaDecoderStateMachine::HasLowDecodedData(int64_t aAudioUsecs) const
AssertCurrentThreadInMonitor();
// We consider ourselves low on decoded data if we're low on audio,
// provided we've not decoded to the end of the audio stream, or
// if we're only playing video and we're low on video frames, provided
// if we're low on video frames, provided
// we've not decoded to the end of the video stream.
return ((HasAudio() &&
!mReader->AudioQueue().IsFinished() &&
AudioDecodedUsecs() < aAudioUsecs)
||
(!HasAudio() &&
HasVideo() &&
(HasVideo() &&
!mReader->VideoQueue().IsFinished() &&
static_cast<uint32_t>(mReader->VideoQueue().GetSize()) < LOW_VIDEO_FRAMES));
}
bool MediaDecoderStateMachine::HasLowUndecodedData() const
{
return GetUndecodedData() < mLowDataThresholdUsecs;
return HasLowUndecodedData(mLowDataThresholdUsecs);
}
int64_t MediaDecoderStateMachine::GetUndecodedData() const
bool MediaDecoderStateMachine::HasLowUndecodedData(double aUsecs) const
{
AssertCurrentThreadInMonitor();
NS_ASSERTION(mState > DECODER_STATE_DECODING_METADATA,
"Must have loaded metadata for GetBuffered() to work");
dom::TimeRanges buffered;
nsresult res = mDecoder->GetBuffered(&buffered);
NS_ENSURE_SUCCESS(res, 0);
double currentTime = GetCurrentTime();
nsIDOMTimeRanges* r = static_cast<nsIDOMTimeRanges*>(&buffered);
uint32_t length = 0;
res = r->GetLength(&length);
NS_ENSURE_SUCCESS(res, 0);
for (uint32_t index = 0; index < length; ++index) {
double start, end;
res = r->Start(index, &start);
NS_ENSURE_SUCCESS(res, 0);
res = r->End(index, &end);
NS_ENSURE_SUCCESS(res, 0);
if (start <= currentTime && end >= currentTime) {
return static_cast<int64_t>((end - currentTime) * USECS_PER_S);
}
bool reliable;
double bytesPerSecond = mDecoder->ComputePlaybackRate(&reliable);
if (!reliable) {
// Default to assuming we have enough
return false;
}
return 0;
MediaResource* stream = mDecoder->GetResource();
int64_t currentPos = stream->Tell();
int64_t requiredPos = currentPos + int64_t((aUsecs/1000000.0)*bytesPerSecond);
int64_t length = stream->GetLength();
if (length >= 0) {
requiredPos = std::min(requiredPos, length);
}
return stream->GetCachedDataEnd(currentPos) < requiredPos;
}
void MediaDecoderStateMachine::SetFrameBufferLength(uint32_t aLength)
@ -2282,14 +2274,13 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
if ((isLiveStream || !mDecoder->CanPlayThrough()) &&
elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
(mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_USECS)
: (GetUndecodedData() < mBufferingWait * mPlaybackRate * USECS_PER_S)) &&
: HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
!mDecoder->IsDataCachedToEndOfResource() &&
!resource->IsSuspended())
{
LOG(PR_LOG_DEBUG,
("%p Buffering: %.3lfs/%ds, timeout in %.3lfs %s",
("%p Buffering: wait %ds, timeout in %.3lfs %s",
mDecoder.get(),
GetUndecodedData() / static_cast<double>(USECS_PER_S),
mBufferingWait,
mBufferingWait - elapsed.ToSeconds(),
(mQuickBuffering ? "(quick exit)" : "")));
@ -2528,15 +2519,15 @@ void MediaDecoderStateMachine::AdvanceFrame()
mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) &&
!mDecoder->IsDataCachedToEndOfResource() &&
!resource->IsSuspended() &&
(JustExitedQuickBuffering() || HasLowUndecodedData()))
{
if (currentFrame) {
mReader->VideoQueue().PushFront(currentFrame.forget());
!resource->IsSuspended()) {
if (JustExitedQuickBuffering() || HasLowUndecodedData()) {
if (currentFrame) {
mReader->VideoQueue().PushFront(currentFrame.forget());
}
StartBuffering();
ScheduleStateMachine();
return;
}
StartBuffering();
ScheduleStateMachine();
return;
}
// We've got enough data to keep playing until at least the next frame.

View File

@ -394,9 +394,8 @@ private:
// The decoder monitor must be held.
bool HasLowUndecodedData() const;
// Returns the number of microseconds of undecoded data available for
// decoding. The decoder monitor must be held.
int64_t GetUndecodedData() const;
// Returns true if we have less than aUsecs of undecoded data available.
bool HasLowUndecodedData(double aUsecs) const;
// Returns the number of unplayed usecs of audio we've got decoded and/or
// pushed to the hardware waiting to play. This is how much audio we can

View File

@ -82,7 +82,6 @@ public:
v.get_ArrayOfBluetoothNamedValue();
nsTArray<nsRefPtr<BluetoothDevice> > devices;
JSObject* JsDevices;
for (uint32_t i = 0; i < values.Length(); i++) {
const BluetoothValue properties = values[i].value();
if (properties.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
@ -106,6 +105,7 @@ public:
}
AutoPushJSContext cx(sc->GetNativeContext());
JSObject* JsDevices = nullptr;
rv = nsTArrayToJSArray(cx, devices, &JsDevices);
if (!JsDevices) {
BT_WARNING("Cannot create JS array!");

File diff suppressed because it is too large Load Diff

View File

@ -7,11 +7,12 @@
#ifndef mozilla_dom_bluetooth_bluetoothhfpmanager_h__
#define mozilla_dom_bluetooth_bluetoothhfpmanager_h__
#include <hardware/bluetooth.h>
#include <hardware/bt_hf.h>
#include "BluetoothCommon.h"
#include "BluetoothProfileManagerBase.h"
#ifdef MOZ_B2G_RIL
#include "BluetoothRilListener.h"
#endif
#include "BluetoothSocketObserver.h"
#include "mozilla/ipc/UnixSocket.h"
#include "mozilla/Hal.h"
@ -20,8 +21,6 @@ BEGIN_BLUETOOTH_NAMESPACE
class BluetoothReplyRunnable;
class BluetoothSocket;
#ifdef MOZ_B2G_RIL
class Call;
/**
@ -67,14 +66,12 @@ public:
bool IsActive();
uint16_t mState;
bool mDirection; // true: incoming call; false: outgoing call
nsString mNumber;
int mType;
bthf_call_direction_t mDirection; // 0: outgoing call; 1: incoming call
bthf_call_addrtype_t mType;
};
#endif // MOZ_B2G_RIL
class BluetoothHfpManager : public BluetoothSocketObserver
, public BluetoothProfileManagerBase
class BluetoothHfpManager : public BluetoothProfileManagerBase
, public BatteryObserver
{
public:
@ -89,21 +86,10 @@ public:
static BluetoothHfpManager* Get();
~BluetoothHfpManager();
// The following functions are inherited from BluetoothSocketObserver
virtual void ReceiveSocketData(
BluetoothSocket* aSocket,
nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage) MOZ_OVERRIDE;
virtual void OnSocketConnectSuccess(BluetoothSocket* aSocket) MOZ_OVERRIDE;
virtual void OnSocketConnectError(BluetoothSocket* aSocket) MOZ_OVERRIDE;
virtual void OnSocketDisconnect(BluetoothSocket* aSocket) MOZ_OVERRIDE;
bool Listen();
bool ConnectSco(BluetoothReplyRunnable* aRunnable = nullptr);
bool ConnectSco();
bool DisconnectSco();
bool ListenSco();
bool IsScoConnected();
#ifdef MOZ_B2G_RIL
/**
* @param aSend A boolean indicates whether we need to notify headset or not
*/
@ -113,106 +99,89 @@ public:
void HandleIccInfoChanged();
void HandleVoiceConnectionChanged();
// Bluedroid hfp callback handlers
void ProcessConnectionState(bthf_connection_state_t aState, bt_bdaddr_t* aBdAddress);
void ProcessAudioState(bthf_audio_state_t aState, bt_bdaddr_t* aBdAddress);
void ProcessAnswerCall();
void ProcessHangupCall();
void ProcessVolumeControl(bthf_volume_type_t aType, int aVolume);
void ProcessDialCall(char *aNumber);
void ProcessDtmfCmd(char aDtmf);
void ProcessAtChld(bthf_chld_type_t aChld);
void ProcessAtCnum();
void ProcessAtCind();
void ProcessAtCops();
void ProcessAtClcc();
void ProcessUnknownAt(char *aAtString);
// CDMA-specific functions
void UpdateSecondNumber(const nsAString& aNumber);
void AnswerWaitingCall();
void IgnoreWaitingCall();
void ToggleCalls();
#endif
private:
class CloseScoTask;
class GetVolumeTask;
#ifdef MOZ_B2G_RIL
class CloseScoTask;
class RespondToBLDNTask;
class SendRingIndicatorTask;
#endif
class MainThreadTask;
friend class CloseScoTask;
friend class GetVolumeTask;
#ifdef MOZ_B2G_RIL
friend class RespondToBLDNTask;
friend class SendRingIndicatorTask;
#endif
friend class BluetoothHfpManagerObserver;
friend class GetVolumeTask;
friend class CloseScoTask;
friend class RespondToBLDNTask;
friend class MainThreadTask;
BluetoothHfpManager();
bool Init();
bool InitHfpInterface();
void DeinitHfpInterface();
void Reset();
void HandleShutdown();
void HandleVolumeChanged(const nsAString& aData);
bool Init();
void Notify(const hal::BatteryInformation& aBatteryInfo);
void Reset();
#ifdef MOZ_B2G_RIL
void NotifyConnectionStateChanged(const nsAString& aType);
void NotifyDialer(const nsAString& aCommand);
PhoneType GetPhoneType(const nsAString& aType);
void ResetCallArray();
uint32_t FindFirstCall(uint16_t aState);
uint32_t GetNumberOfCalls(uint16_t aState);
PhoneType GetPhoneType(const nsAString& aType);
#endif
bthf_call_state_t ConvertToBthfCallState(int aCallState);
void NotifyConnectionStatusChanged(const nsAString& aType);
void NotifyDialer(const nsAString& aCommand);
void UpdatePhoneCIND(uint32_t aCallIndex, bool aSend = true);
void UpdateDeviceCIND();
void SendCLCC(Call& aCall, int aIndex);
void SendLine(const char* aMessage);
void SendResponse(bthf_at_response_t aResponseCode);
#ifdef MOZ_B2G_RIL
void SendCCWA(const nsAString& aNumber, int aType);
bool SendCLCC(const Call& aCall, int aIndex);
#endif
bool SendCommand(const char* aCommand, uint32_t aValue = 0);
bool SendLine(const char* aMessage);
#ifdef MOZ_B2G_RIL
void UpdateCIND(uint8_t aType, uint8_t aValue, bool aSend = true);
#endif
void OnScoConnectSuccess();
void OnScoConnectError();
void OnScoDisconnect();
int mConnectionState;
int mAudioState;
// Phone CIND
int mCallSetupState;
// Device CIND
int mBattChg;
int mService;
int mRoam;
int mSignal;
int mCurrentVgs;
int mCurrentVgm;
#ifdef MOZ_B2G_RIL
bool mBSIR;
bool mCCWA;
bool mCLIP;
#endif
bool mCMEE;
bool mCMER;
#ifdef MOZ_B2G_RIL
bool mFirstCKPD;
int mNetworkSelectionMode;
PhoneType mPhoneType;
#endif
bool mReceiveVgsFlag;
#ifdef MOZ_B2G_RIL
bool mDialingRequestProcessed;
#endif
PhoneType mPhoneType;
nsString mDeviceAddress;
#ifdef MOZ_B2G_RIL
nsString mMsisdn;
nsString mOperatorName;
nsTArray<Call> mCurrentCallArray;
nsAutoPtr<BluetoothRilListener> mListener;
#endif
nsRefPtr<BluetoothProfileController> mController;
nsRefPtr<BluetoothReplyRunnable> mScoRunnable;
// If a connection has been established, mSocket will be the socket
// communicating with the remote socket. We maintain the invariant that if
// mSocket is non-null, mHandsfreeSocket and mHeadsetSocket must be null (and
// vice versa).
nsRefPtr<BluetoothSocket> mSocket;
// Server sockets. Once an inbound connection is established, it will hand
// over the ownership to mSocket, and get a new server socket while Listen()
// is called.
nsRefPtr<BluetoothSocket> mHandsfreeSocket;
nsRefPtr<BluetoothSocket> mHeadsetSocket;
nsRefPtr<BluetoothSocket> mScoSocket;
SocketConnectionStatus mScoSocketStatus;
#ifdef MOZ_B2G_RIL
// CDMA-specific variable
Call mCdmaSecondCall;
#endif
};
END_BLUETOOTH_NAMESPACE

View File

@ -18,7 +18,6 @@
#include "BluetoothServiceBluedroid.h"
#include <hardware/bluetooth.h>
#include <hardware/hardware.h>
#include "BluetoothProfileController.h"
@ -32,8 +31,6 @@ using namespace mozilla;
using namespace mozilla::ipc;
USING_BLUETOOTH_NAMESPACE
typedef char bdstr_t[18];
/**
* Classes only used in this file
*/
@ -159,39 +156,31 @@ ClassToIcon(uint32_t aClass, nsAString& aRetIcon)
}
}
static void
AdapterStateChangeCallback(bt_state_t aStatus)
static bool
IsReady()
{
MOZ_ASSERT(!NS_IsMainThread());
BT_LOGD("%s, BT_STATE:%d", __FUNCTION__, aStatus);
nsAutoString signalName;
if (aStatus == BT_STATE_ON) {
sIsBtEnabled = true;
signalName = NS_LITERAL_STRING("AdapterAdded");
// by default bluetooth scan mode is NONE
bt_property_t prop;
prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE;
bt_scan_mode_t mode = BT_SCAN_MODE_CONNECTABLE;
prop.val = (void*) &mode;
prop.len = sizeof(mode);
if (sBtInterface) {
int ret = sBtInterface->set_adapter_property(&prop);
if (ret != BT_STATUS_SUCCESS) {
BT_LOGR("Warning! Fail to set property to BT_SCAN_MODE_CONNECTABLE");
}
}
} else {
sIsBtEnabled = false;
signalName = NS_LITERAL_STRING("Disabled");
if (!sBtInterface || !sIsBtEnabled) {
BT_LOGR("Warning! Bluetooth Service is not ready");
return false;
}
return true;
}
BluetoothSignal signal(signalName, NS_LITERAL_STRING(KEY_MANAGER),
BluetoothValue(true));
nsRefPtr<DistributeBluetoothSignalTask>
t = new DistributeBluetoothSignalTask(signal);
if (NS_FAILED(NS_DispatchToMainThread(t))) {
NS_WARNING("Failed to dispatch to main thread!");
const bt_interface_t*
GetBluetoothInterface()
{
return (IsReady()) ? sBtInterface : nullptr;
}
void
StringToBdAddressType(const nsAString& aBdAddress,
bt_bdaddr_t *aRetBdAddressType)
{
const char* str = NS_ConvertUTF16toUTF8(aBdAddress).get();
for (int i = 0; i < 6; i++) {
aRetBdAddressType->address[i] = (uint8_t) strtoul(str, (char **)&str, 16);
str++;
}
}
@ -208,25 +197,47 @@ BdAddressTypeToString(bt_bdaddr_t* aBdAddressType, nsAString& aRetBdAddress)
aRetBdAddress = NS_ConvertUTF8toUTF16((char*)bdstr);
}
static bool
IsReady()
static void
Setup()
{
if (!sBtInterface || !sIsBtEnabled) {
BT_LOGR("Warning! Bluetooth Service is not ready");
return false;
// Bluetooth scan mode is NONE by default
bt_scan_mode_t mode = BT_SCAN_MODE_CONNECTABLE;
bt_property_t prop;
prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE;
prop.val = (void*)&mode;
prop.len = sizeof(mode);
NS_ENSURE_TRUE_VOID(sBtInterface);
int ret = sBtInterface->set_adapter_property(&prop);
if (ret != BT_STATUS_SUCCESS) {
BT_LOGR("%s: Fail to set: BT_SCAN_MODE_CONNECTABLE", __FUNCTION__);
}
return true;
}
static void
StringToBdAddressType(const nsAString& aBdAddress,
bt_bdaddr_t *aRetBdAddressType)
AdapterStateChangeCallback(bt_state_t aStatus)
{
const char* str = NS_ConvertUTF16toUTF8(aBdAddress).get();
MOZ_ASSERT(!NS_IsMainThread());
for (int i = 0; i < 6; i++) {
aRetBdAddressType->address[i] = (uint8_t) strtoul(str, (char **)&str, 16);
str++;
BT_LOGR("%s, BT_STATE:%d", __FUNCTION__, aStatus);
nsAutoString signalName;
if (aStatus == BT_STATE_ON) {
Setup();
sIsBtEnabled = true;
signalName = NS_LITERAL_STRING("AdapterAdded");
} else {
sIsBtEnabled = false;
signalName = NS_LITERAL_STRING("Disabled");
}
BluetoothSignal signal(signalName, NS_LITERAL_STRING(KEY_MANAGER),
BluetoothValue(true));
nsRefPtr<DistributeBluetoothSignalTask>
t = new DistributeBluetoothSignalTask(signal);
if (NS_FAILED(NS_DispatchToMainThread(t))) {
NS_WARNING("Failed to dispatch to main thread!");
}
}
@ -525,12 +536,13 @@ BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
nsAutoString remoteAddress;
BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
bool bonded;
if (aState == BT_BOND_STATE_BONDING) {
// We don't need to handle bonding state
return;
} else if (aState == BT_BOND_STATE_NONE) {
// We don't need to handle bonding state
NS_ENSURE_TRUE_VOID(aState != BT_BOND_STATE_BONDING);
NS_ENSURE_FALSE_VOID(aState == BT_BOND_STATE_BONDED &&
sAdapterBondedAddressArray.Contains(remoteAddress));
bool bonded;
if (aState == BT_BOND_STATE_NONE) {
bonded = false;
sAdapterBondedAddressArray.RemoveElement(remoteAddress);
} else if (aState == BT_BOND_STATE_BONDED) {
@ -731,9 +743,21 @@ BluetoothServiceBluedroid::GetDefaultAdapterPathInternal(
nsRefPtr<BluetoothReplyRunnable> runnable(aRunnable);
BluetoothValue v = InfallibleTArray<BluetoothNamedValue>();
v.get_ArrayOfBluetoothNamedValue().AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("Address"), sAdapterBdAddress));
v.get_ArrayOfBluetoothNamedValue().AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("Name"), sAdapterBdName));
v.get_ArrayOfBluetoothNamedValue().AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("Discoverable"),
sAdapterDiscoverable));
v.get_ArrayOfBluetoothNamedValue().AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("DiscoverableTimeout"),
sAdapterDiscoverableTimeout));
v.get_ArrayOfBluetoothNamedValue().AppendElement(
BluetoothNamedValue(NS_LITERAL_STRING("Devices"),
sAdapterBondedAddressArray));

View File

@ -7,9 +7,20 @@
#ifndef mozilla_dom_bluetooth_bluetoothservicebluedroid_h__
#define mozilla_dom_bluetooth_bluetoothservicebluedroid_h__
#include <hardware/bluetooth.h>
#include "BluetoothCommon.h"
#include "BluetoothService.h"
typedef char bdstr_t[18];
const bt_interface_t*
GetBluetoothInterface();
void
StringToBdAddressType(const nsAString& aBdAddress,
bt_bdaddr_t *aRetBdAddressType);
class DBusMessage;
BEGIN_BLUETOOTH_NAMESPACE

View File

@ -174,6 +174,7 @@ static nsRefPtr<RawDBusConnection> gThreadConnection;
static nsDataHashtable<nsStringHashKey, DBusMessage* >* sPairingReqTable;
static nsTArray<uint32_t> sAuthorizedServiceClass;
static nsString sAdapterPath;
static bool sAdapterNameIsReady = false;
static Atomic<int32_t> sIsPairing(0);
static int sConnectedDeviceCount = 0;
static StaticAutoPtr<Monitor> sStopBluetoothMonitor;
@ -700,6 +701,20 @@ GetProperty(DBusMessageIter aIter, Properties* aPropertyTypes,
nsString& data = propertyValue.get_ArrayOfnsString()[i];
data = GetAddressFromObjectPath(data);
}
} else if (!sAdapterNameIsReady &&
aPropertyTypes == sAdapterProperties &&
propertyName.EqualsLiteral("Name")) {
MOZ_ASSERT(propertyValue.type() == BluetoothValue::TnsString);
// Notify BluetoothManager whenever adapter name is ready.
if (!propertyValue.get_nsString().IsEmpty()) {
sAdapterNameIsReady = true;
BluetoothSignal signal(NS_LITERAL_STRING("AdapterAdded"),
NS_LITERAL_STRING(KEY_MANAGER), sAdapterPath);
nsRefPtr<DistributeBluetoothSignalTask> task =
new DistributeBluetoothSignalTask(signal);
NS_DispatchToMainThread(task);
}
}
aProperties.AppendElement(BluetoothNamedValue(propertyName, propertyValue));
@ -1534,6 +1549,13 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
} else {
v = NS_ConvertUTF8toUTF16(str);
NS_DispatchToMainThread(new PrepareAdapterRunnable(v.get_nsString()));
/**
* The adapter name isn't ready for the time being. Wait for the upcoming
* signal PropertyChanged of adapter name, and then propagate signal
* AdapterAdded to BluetoothManager.
*/
return DBUS_HANDLER_RESULT_HANDLED;
}
} else if (dbus_message_is_signal(aMsg, DBUS_MANAGER_IFACE,
"PropertyChanged")) {
@ -1773,6 +1795,8 @@ BluetoothDBusService::StopInternal()
sAuthorizedServiceClass.Clear();
sControllerArray.Clear();
sAdapterNameIsReady = false;
StopDBus();
return NS_OK;
}

View File

@ -10,11 +10,28 @@
USING_INDEXEDDB_NAMESPACE
namespace {
class CleanupFileRunnable MOZ_FINAL : public nsIRunnable
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE
CleanupFileRunnable(FileManager* aFileManager, int64_t aFileId);
private:
nsRefPtr<FileManager> mFileManager;
int64_t mFileId;
};
} // anonymous namespace
// static
FileInfo*
FileInfo::Create(FileManager* aFileManager, int64_t aId)
{
NS_ASSERTION(aId > 0, "Wrong id!");
MOZ_ASSERT(aId > 0, "Wrong id!");
if (aId <= INT16_MAX) {
return new FileInfo16(aFileManager, aId);
@ -98,16 +115,40 @@ FileInfo::UpdateReferences(mozilla::ThreadSafeAutoRefCnt& aRefCount,
void
FileInfo::Cleanup()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsRefPtr<CleanupFileRunnable> cleaner =
new CleanupFileRunnable(mFileManager, Id());
if (quota::QuotaManager::IsShuttingDown()) {
// IndexedDatabaseManager is main-thread only.
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(cleaner);
return;
}
nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "Shouldn't be null!");
cleaner->Run();
}
if (NS_FAILED(mgr->AsyncDeleteFile(mFileManager, Id()))) {
CleanupFileRunnable::CleanupFileRunnable(FileManager* aFileManager,
int64_t aFileId)
: mFileManager(aFileManager), mFileId(aFileId)
{
}
NS_IMPL_ISUPPORTS1(CleanupFileRunnable,
nsIRunnable)
NS_IMETHODIMP
CleanupFileRunnable::Run()
{
if (mozilla::dom::quota::QuotaManager::IsShuttingDown()) {
return NS_OK;
}
nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
MOZ_ASSERT(mgr);
if (NS_FAILED(mgr->AsyncDeleteFile(mFileManager, mFileId))) {
NS_WARNING("Failed to delete file asynchronously!");
}
return NS_OK;
}

View File

@ -344,7 +344,6 @@ IndexedDBDatabaseChild::EnsureDatabase(
void
IndexedDBDatabaseChild::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_ASSERT(!mStrongDatabase);
if (mDatabase) {
mDatabase->SetActor(static_cast<IndexedDBDatabaseChild*>(NULL));
#ifdef DEBUG

View File

@ -0,0 +1,98 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Test</title>
<script type="text/javascript">
function report(result) {
var message = { source: "iframe" };
message.result = result;
window.parent.postMessage(message, "*");
}
function runIndexedDBTest() {
var db = null;
// Create the data-store
function createDatastore() {
try {
var request = indexedDB.open(window.location.pathname, 1);
request.onupgradeneeded = function(event) {
event.target.result.createObjectStore("foo");
}
request.onsuccess = function(event) {
db = event.target.result;
createAndStoreBlob();
}
}
catch (e) {
dump("EXCEPTION IN CREATION: " + e + "\n " + e.stack + "\n");
report(false);
}
}
function createAndStoreBlob() {
const BLOB_DATA = ["fun ", "times ", "all ", "around!"];
var blob = new Blob(BLOB_DATA, { type: "text/plain" });
var objectStore = db.transaction("foo", "readwrite").objectStore("foo");
objectStore.add({ blob: blob }, 42).onsuccess = refetchBlob;
}
function refetchBlob() {
var foo = db.transaction("foo").objectStore("foo");
foo.get(42).onsuccess = fetchedBlobCreateWorkerAndSendBlob;
}
function fetchedBlobCreateWorkerAndSendBlob(event) {
var idbBlob = event.target.result.blob;
var compositeBlob = new Blob(['I like the following blob: ', idbBlob],
{ type: "text/fancy" });
function workerScript() {
onmessage = function(event) {
// Save the Blob to the worker's global scope.
self.holdOntoBlob = event.data;
// Send any message so we can serialize and keep our runtime behaviour
// consistent.
postMessage('kung fu death grip established');
}
}
var url =
URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"]));
// Keep a reference to the worker on the window.
var worker = window.worker = new Worker(url);
worker.postMessage(compositeBlob);
worker.onmessage = workerLatchedBlobDeleteFromDB;
}
function workerLatchedBlobDeleteFromDB() {
// Delete the reference to the Blob from the database leaving the worker
// thread reference as the only live reference once a GC has cleaned
// out our references that we sent to the worker. The page that owns
// us triggers a GC just for that reason.
var objectStore = db.transaction("foo", "readwrite").objectStore("foo");
objectStore.delete(42).onsuccess = closeDBTellOwningThread;
}
function closeDBTellOwningThread(event) {
// Now that worker has latched the blob, clean up the database.
db.close();
db = null;
report('ready');
}
createDatastore();
}
</script>
</head>
<body onload="runIndexedDBTest();">
</body>
</html>

View File

@ -2,6 +2,7 @@
support-files =
bfcache_iframe1.html
bfcache_iframe2.html
blob_worker_crash_iframe.html
error_events_abort_transactions_iframe.html
event_propagation_iframe.html
exceptions_in_events_iframe.html
@ -26,6 +27,7 @@ support-files =
[test_bfcache.html]
[test_blob_archive.html]
[test_blob_simple.html]
[test_blob_worker_crash.html]
[test_clear.html]
[test_complex_keyPaths.html]
[test_count.html]

View File

@ -0,0 +1,62 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Blob Worker Crash Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
/*
* This tests ensures that if the last live reference to a Blob is on the
* worker and the database has already been shutdown, that there is no crash
* when the owning page gets cleaned up which causes the termination of the
* worker which in turn garbage collects during its shutdown.
*
* We do the IndexedDB stuff in the iframe so we can kill it as part of our
* test. Doing it out here is no good.
*/
function testSteps()
{
info("Open iframe, wait for it to do its IndexedDB stuff.");
let iframe = document.getElementById("iframe1");
window.addEventListener("message", grabEventAndContinueHandler, false);
// Put it in a different origin to be safe
//allowUnlimitedQuota("http://example.org/");
iframe.src = //"http://example.org" +
window.location.pathname.replace(
"test_blob_worker_crash.html",
"blob_worker_crash_iframe.html");
let event = yield unexpectedSuccessHandler;
is(event.data.result, "ready", "worker initialized correctly");
info("Trigger a GC to clean-up the iframe's main-thread IndexedDB");
scheduleGC();
yield undefined;
info("Kill the iframe, forget about it, trigger a GC.");
iframe.parentNode.removeChild(iframe);
iframe = null;
scheduleGC();
yield undefined;
info("If we are still alive, then we win!");
ok('Did not crash / trigger an assert!');
finishTest();
yield undefined;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
<iframe id="iframe1"></iframe>
</html>

View File

@ -206,24 +206,38 @@ MobileMessageManager::Send(const JS::Value& aNumber_,
JS::Rooted<JSObject*> numbers(aCx, &aNumber.toObject());
uint32_t size;
JS_ALWAYS_TRUE(JS_GetArrayLength(aCx, numbers, &size));
if (!JS_GetArrayLength(aCx, numbers, &size)) {
return NS_ERROR_FAILURE;
}
JS::Value* requests = new JS::Value[size];
JS::AutoValueVector requests(aCx);
if (!requests.resize(size)) {
return NS_ERROR_FAILURE;
}
JS::Rooted<JS::Value> number(aCx);
JS::Rooted<JSString*> str(aCx);
for (uint32_t i = 0; i < size; ++i) {
if (!JS_GetElement(aCx, numbers, i, &number)) {
return NS_ERROR_INVALID_ARG;
}
JS::Rooted<JSString*> str(aCx, number.toString());
str = JS::ToString(aCx, number);
if (!str) {
return NS_ERROR_FAILURE;
}
nsresult rv = Send(aCx, global, serviceId, str, aMessage, &requests[i]);
NS_ENSURE_SUCCESS(rv, rv);
}
aReturn->setObjectOrNull(JS_NewArrayObject(aCx, size, requests));
NS_ENSURE_TRUE(aReturn->isObject(), NS_ERROR_FAILURE);
JS::Rooted<JSObject*> obj(aCx);
obj = JS_NewArrayObject(aCx, requests.length(), requests.begin());
if (!obj) {
return NS_ERROR_FAILURE;
}
aReturn->setObject(*obj);
return NS_OK;
}

View File

@ -353,7 +353,7 @@ TelephonyProvider.prototype = {
this._getClient(aClientId).sendWorkerMessage("enumerateCalls", null,
(function(response) {
for (let call of response.calls) {
call.clienId = aClientId;
call.clientId = aClientId;
call.state = this._convertRILCallState(call.state);
call.isActive = this._matchActiveCall(call);

View File

@ -23,6 +23,8 @@ import org.mozilla.gecko.home.SearchEngine;
import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.preferences.GeckoPreferences;
import org.mozilla.gecko.prompts.Prompt;
import org.mozilla.gecko.toolbar.AutocompleteHandler;
import org.mozilla.gecko.toolbar.BrowserToolbar;
import org.mozilla.gecko.util.Clipboard;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.HardwareUtils;

View File

@ -14,7 +14,7 @@ import android.view.inputmethod.InputMethodManager;
import java.util.Collection;
import java.util.Locale;
final class InputMethods {
final public class InputMethods {
public static final String METHOD_ANDROID_LATINIME = "com.android.inputmethod.latin/.LatinIME";
public static final String METHOD_ATOK = "com.justsystems.atokmobile.service/.AtokInputMethodService";
public static final String METHOD_GOOGLE_JAPANESE_INPUT = "com.google.android.inputmethod.japanese/.MozcService";

View File

@ -5,7 +5,6 @@
package org.mozilla.gecko.home;
import org.mozilla.gecko.AutocompleteHandler;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.PrefsHelper;
@ -16,6 +15,7 @@ import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
import org.mozilla.gecko.home.SearchEngine;
import org.mozilla.gecko.home.SearchLoader.SearchCursorLoader;
import org.mozilla.gecko.toolbar.AutocompleteHandler;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.util.ThreadUtils;

View File

@ -91,15 +91,10 @@ gbjar.sources += [
'animation/ViewHelper.java',
'ANRReporter.java',
'AppNotificationClient.java',
'AutocompleteHandler.java',
'BackButton.java',
'BaseGeckoInterface.java',
'BrowserApp.java',
'BrowserToolbar.java',
'BrowserToolbarBackground.java',
'CameraImageResultHandler.java',
'CameraVideoResultHandler.java',
'CanvasDelegate.java',
'ContactService.java',
'ContextGetter.java',
'CustomEditText.java',
@ -127,7 +122,6 @@ gbjar.sources += [
'FilePickerResultHandlerSync.java',
'FindInPageBar.java',
'FormAssistPopup.java',
'ForwardButton.java',
'GeckoAccessibility.java',
'GeckoActivity.java',
'GeckoActivityStatus.java',
@ -245,7 +239,6 @@ gbjar.sources += [
'NotificationService.java',
'NSSBridge.java',
'OrderedBroadcastHelper.java',
'PageActionLayout.java',
'preferences/AlignRightLinkPreference.java',
'preferences/AndroidImport.java',
'preferences/AndroidImportPreference.java',
@ -272,7 +265,6 @@ gbjar.sources += [
'ScrollAnimator.java',
'ServiceNotificationClient.java',
'SessionParser.java',
'ShapedButton.java',
'SharedPreferencesHelper.java',
'SiteIdentityPopup.java',
'SmsManager.java',
@ -282,7 +274,6 @@ gbjar.sources += [
'sqlite/SQLiteBridgeException.java',
'SurfaceBits.java',
'Tab.java',
'TabCounter.java',
'Tabs.java',
'TabsAccessor.java',
'TabsPanel.java',
@ -291,6 +282,15 @@ gbjar.sources += [
'TextSelection.java',
'TextSelectionHandle.java',
'ThumbnailHelper.java',
'toolbar/AutocompleteHandler.java',
'toolbar/BackButton.java',
'toolbar/BrowserToolbar.java',
'toolbar/BrowserToolbarBackground.java',
'toolbar/CanvasDelegate.java',
'toolbar/ForwardButton.java',
'toolbar/PageActionLayout.java',
'toolbar/ShapedButton.java',
'toolbar/TabCounter.java',
'TouchEventInterceptor.java',
'updater/UpdateService.java',
'updater/UpdateServiceHelper.java',

View File

@ -6,20 +6,20 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto">
<org.mozilla.gecko.BrowserToolbarBackground android:id="@+id/url_bar_bg"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/url_bar_bg"/>
<org.mozilla.gecko.toolbar.BrowserToolbarBackground android:id="@+id/url_bar_bg"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/url_bar_bg"/>
<org.mozilla.gecko.ShapedButton android:id="@+id/tabs"
style="@style/UrlBar.ImageButton"
android:layout_width="84dip"
android:layout_alignParentLeft="true"
gecko:curveTowards="left"
android:background="@drawable/shaped_button"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:paddingRight="38dip"/>
<org.mozilla.gecko.toolbar.ShapedButton android:id="@+id/tabs"
style="@style/UrlBar.ImageButton"
android:layout_width="84dip"
android:layout_alignParentLeft="true"
gecko:curveTowards="left"
android:background="@drawable/shaped_button"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:paddingRight="38dip"/>
<!-- The TextSwitcher should be shifted 28dp on the right, to avoid
the curve. On a 56dp space, centering 24dp image will leave
@ -27,7 +27,7 @@
2 layers. Hence to center this, an additional 4dp is added to the right.
The margins will be 12dp on left, 48dp on right, instead of ideal 16dp
and 44dp. -->
<org.mozilla.gecko.TabCounter android:id="@+id/tabs_counter"
<org.mozilla.gecko.toolbar.TabCounter android:id="@+id/tabs_counter"
style="@style/UrlBar.ImageButton.TabCount"
android:layout_width="24dip"
android:layout_height="24dip"
@ -49,21 +49,21 @@
android:focusable="false"
android:background="@drawable/url_bar_entry"/>
<org.mozilla.gecko.ForwardButton style="@style/UrlBar.ImageButton.Forward"
android:id="@+id/forward"
android:layout_toRightOf="@+id/tabs"/>
<org.mozilla.gecko.toolbar.ForwardButton style="@style/UrlBar.ImageButton.Forward"
android:id="@+id/forward"
android:layout_toRightOf="@+id/tabs"/>
<org.mozilla.gecko.BackButton android:id="@+id/back"
style="@style/UrlBar.ImageButton"
android:layout_width="50dip"
android:layout_height="50dip"
android:layout_toRightOf="@id/tabs"
android:layout_marginLeft="-28dp"
android:layout_centerVertical="true"
android:padding="13dp"
android:src="@drawable/ic_menu_back"
android:contentDescription="@string/back"
android:background="@drawable/url_bar_nav_button"/>
<org.mozilla.gecko.toolbar.BackButton android:id="@+id/back"
style="@style/UrlBar.ImageButton"
android:layout_width="50dip"
android:layout_height="50dip"
android:layout_toRightOf="@id/tabs"
android:layout_marginLeft="-28dp"
android:layout_centerVertical="true"
android:padding="13dp"
android:src="@drawable/ic_menu_back"
android:contentDescription="@string/back"
android:background="@drawable/url_bar_nav_button"/>
<LinearLayout android:id="@+id/url_edit_container"
style="@style/UrlBar.Button"
@ -142,12 +142,12 @@
android:layout_gravity="center_vertical"
gecko:autoUpdateTheme="false"/>
<org.mozilla.gecko.PageActionLayout android:id="@+id/page_action_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="@dimen/browser_toolbar_button_padding"
android:visibility="gone"
android:orientation="horizontal"/>
<org.mozilla.gecko.toolbar.PageActionLayout android:id="@+id/page_action_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="@dimen/browser_toolbar_button_padding"
android:visibility="gone"
android:orientation="horizontal"/>
<ImageButton android:id="@+id/stop"
style="@style/UrlBar.ImageButton.Icon"

View File

@ -12,10 +12,10 @@
<ImageButton android:id="@+id/forward"
style="@style/UrlBar.ImageButton.Unused"/>
<org.mozilla.gecko.BrowserToolbarBackground android:id="@+id/url_bar_bg"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/url_bar_bg"/>
<org.mozilla.gecko.toolbar.BrowserToolbarBackground android:id="@+id/url_bar_bg"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/url_bar_bg"/>
<ImageView android:id="@+id/url_bar_entry"
style="@style/UrlBar.Button"
@ -48,13 +48,13 @@
<LinearLayout android:id="@+id/menu_items"
style="@style/UrlBar.ImageButton.Unused"/>
<org.mozilla.gecko.ShapedButton android:id="@+id/menu"
style="@style/UrlBar.ImageButton"
android:layout_width="48dip"
android:layout_alignParentRight="true"
android:contentDescription="@string/menu"
android:background="@drawable/shaped_button"
android:visibility="gone"/>
<org.mozilla.gecko.toolbar.ShapedButton android:id="@+id/menu"
style="@style/UrlBar.ImageButton"
android:layout_width="48dip"
android:layout_alignParentRight="true"
android:contentDescription="@string/menu"
android:background="@drawable/shaped_button"
android:visibility="gone"/>
<org.mozilla.gecko.widget.GeckoImageView android:id="@+id/menu_icon"
style="@style/UrlBar.ImageButton"
@ -64,16 +64,16 @@
android:src="@drawable/menu_level"
android:visibility="gone"/>
<org.mozilla.gecko.ShapedButton android:id="@+id/tabs"
style="@style/UrlBar.ImageButton"
android:layout_width="72dip"
android:layout_toLeftOf="@id/menu"
android:layout_alignWithParentIfMissing="true"
gecko:curveTowards="right"
android:background="@drawable/shaped_button"
android:gravity="center_vertical"
android:paddingLeft="37dip"
android:paddingRight="11dip"/>
<org.mozilla.gecko.toolbar.ShapedButton android:id="@+id/tabs"
style="@style/UrlBar.ImageButton"
android:layout_width="72dip"
android:layout_toLeftOf="@id/menu"
android:layout_alignWithParentIfMissing="true"
gecko:curveTowards="right"
android:background="@drawable/shaped_button"
android:gravity="center_vertical"
android:paddingLeft="37dip"
android:paddingRight="11dip"/>
<!-- The TextSwitcher should be shifted 24dp on the left, to avoid
the curve. On a 48dp space, centering 24dp image will leave
@ -81,7 +81,7 @@
2 layers. Hence to center this, an additional 4dp is added to the left.
The margins will be 40dp on left, 8dp on right, instead of ideal 30dp
and 12dp. -->
<org.mozilla.gecko.TabCounter android:id="@+id/tabs_counter"
<org.mozilla.gecko.toolbar.TabCounter android:id="@+id/tabs_counter"
style="@style/UrlBar.ImageButton.TabCount"
android:layout_width="24dip"
android:layout_height="24dip"
@ -166,12 +166,12 @@
android:layout_gravity="center_vertical"
gecko:autoUpdateTheme="false"/>
<org.mozilla.gecko.PageActionLayout android:id="@+id/page_action_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="12dp"
android:visibility="gone"
android:orientation="horizontal"/>
<org.mozilla.gecko.toolbar.PageActionLayout android:id="@+id/page_action_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="12dp"
android:visibility="gone"
android:orientation="horizontal"/>
<ImageButton android:id="@+id/stop"
style="@style/UrlBar.ImageButton.Icon"

View File

@ -67,7 +67,8 @@
view. To make sure the EditText is not the first focusable view in
the root view, BrowserToolbar should be specified as low in the
view hierarchy as possible. -->
<org.mozilla.gecko.BrowserToolbar android:id="@id/browser_toolbar"
<org.mozilla.gecko.toolbar.BrowserToolbar
android:id="@id/browser_toolbar"
style="@style/BrowserToolbar"
android:layout_width="fill_parent"
android:layout_height="@dimen/browser_toolbar_height"

View File

@ -3,7 +3,7 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.toolbar;
public interface AutocompleteHandler {
void onAutocomplete(String res);

View File

@ -2,7 +2,9 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.R;
import android.content.Context;
import android.graphics.Canvas;

View File

@ -3,8 +3,19 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.CustomEditText;
import org.mozilla.gecko.InputMethods;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.LightweightTheme;
import org.mozilla.gecko.R;
import org.mozilla.gecko.SiteIdentityPopup;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
@ -12,7 +23,6 @@ import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.menu.GeckoMenu;
import org.mozilla.gecko.menu.MenuPopup;
import org.mozilla.gecko.PageActionLayout;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.util.Clipboard;
import org.mozilla.gecko.util.StringUtils;

View File

@ -2,8 +2,11 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.LightweightTheme;
import org.mozilla.gecko.R;
import org.mozilla.gecko.widget.GeckoLinearLayout;
import android.content.Context;

View File

@ -2,7 +2,7 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.toolbar;
import android.graphics.Bitmap;
import android.graphics.Canvas;

View File

@ -2,7 +2,9 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.R;
import android.content.Context;
import android.graphics.Canvas;

View File

@ -3,8 +3,11 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.R;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;

View File

@ -2,8 +2,12 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.LightweightTheme;
import org.mozilla.gecko.LightweightThemeDrawable;
import org.mozilla.gecko.R;
import org.mozilla.gecko.widget.GeckoImageButton;
import android.content.Context;

View File

@ -3,9 +3,10 @@
* 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/. */
package org.mozilla.gecko;
package org.mozilla.gecko.toolbar;
import org.mozilla.gecko.animation.Rotate3DAnimation;
import org.mozilla.gecko.R;
import org.mozilla.gecko.widget.GeckoTextSwitcher;
import android.content.Context;

View File

@ -17,6 +17,7 @@ var SelectionHandler = {
_cache: null,
_activeType: 0, // TYPE_NONE
_ignoreSelectionChanges: false, // True while user drags text selection handles
_ignoreCompositionChanges: false, // Persist caret during IME composition updates
// The window that holds the selection (can be a sub-frame)
get _contentWindow() {
@ -108,6 +109,9 @@ var SelectionHandler = {
this._ignoreSelectionChanges = true;
this._moveSelection(data.handleType == this.HANDLE_TYPE_START, data.x, data.y);
} else if (this._activeType == this.TYPE_CURSOR) {
// Ignore IMM composition notifications when caret movement starts
this._ignoreCompositionChanges = true;
// Send a click event to the text box, which positions the caret
this._sendMouseEvents(data.x, data.y);
@ -133,6 +137,10 @@ var SelectionHandler = {
}
// Act on selectionChange notifications after handle movement ends
this._ignoreSelectionChanges = false;
} else if (this._activeType == this.TYPE_CURSOR) {
// Act on IMM composition notifications after caret movement ends
this._ignoreCompositionChanges = false;
}
this._positionHandles();
break;
@ -158,7 +166,8 @@ var SelectionHandler = {
break;
case "compositionend":
if (this._activeType == this.TYPE_CURSOR) {
// compositionend messages normally terminate caret display
if (this._activeType == this.TYPE_CURSOR && !this._ignoreCompositionChanges) {
this._deactivate();
}
break;
@ -530,6 +539,7 @@ var SelectionHandler = {
this._isRTL = false;
this._cache = null;
this._ignoreSelectionChanges = false;
this._ignoreCompositionChanges = false;
},
_getViewOffset: function sh_getViewOffset() {

View File

@ -86,6 +86,11 @@
#include <limits>
#ifdef MOZ_WIDGET_GONK
#include "nsINetworkManager.h"
#include "nsThreadUtils.h" // for NS_IsMainThread
#endif
#ifdef MOZILLA_INTERNAL_API
#include "nsReadableUtils.h"
@ -2360,4 +2365,28 @@ NS_IsSrcdocChannel(nsIChannel *aChannel)
return false;
}
// The following members are used for network per-app metering.
const static uint64_t NETWORK_STATS_THRESHOLD = 65536;
#ifdef MOZ_WIDGET_GONK
inline nsresult
NS_GetActiveNetworkInterface(nsCOMPtr<nsINetworkInterface> &aNetworkInterface)
{
MOZ_ASSERT(NS_IsMainThread());
nsresult rv;
nsCOMPtr<nsINetworkManager> networkManager =
do_GetService("@mozilla.org/network/manager;1", &rv);
if (NS_FAILED(rv) || !networkManager) {
aNetworkInterface = nullptr;
return rv;
}
networkManager->GetActive(getter_AddRefs(aNetworkInterface));
return NS_OK;
}
#endif
#endif // !nsNetUtil_h__

View File

@ -1691,6 +1691,10 @@ nsFtpState::Init(nsFtpChannel *channel)
// initialize counter for network metering
mCountRecv = 0;
#ifdef MOZ_WIDGET_GONK
NS_GetActiveNetworkInterface(mActiveNetwork);
#endif
mKeepRunning = true;
mSuppliedEntityID = channel->EntityID();
@ -2199,22 +2203,6 @@ nsresult
nsFtpState::SaveNetworkStats(bool enforce)
{
#ifdef MOZ_WIDGET_GONK
MOZ_ASSERT(NS_IsMainThread());
// Obtain active network
nsresult rv;
if (!mActiveNetwork) {
nsCOMPtr<nsINetworkManager> networkManager =
do_GetService("@mozilla.org/network/manager;1", &rv);
if (NS_FAILED(rv) || !networkManager) {
mActiveNetwork = nullptr;
return rv;
}
networkManager->GetActive(getter_AddRefs(mActiveNetwork));
}
// Obtain app id
uint32_t appId;
bool isInBrowser;
@ -2237,6 +2225,7 @@ nsFtpState::SaveNetworkStats(bool enforce)
return NS_OK;
}
nsresult rv;
nsCOMPtr<nsINetworkStatsServiceProxy> networkStatsServiceProxy =
do_GetService("@mozilla.org/networkstatsServiceProxy;1", &rv);
if (NS_FAILED(rv)) {

View File

@ -262,10 +262,6 @@ private:
// These members are used for network per-app metering (bug 855948)
// Currently, they are only available on gonk.
public:
const static uint64_t NETWORK_STATS_THRESHOLD = 65536;
private:
uint64_t mCountRecv;
#ifdef MOZ_WIDGET_GONK
nsCOMPtr<nsINetworkInterface> mActiveNetwork;

View File

@ -230,17 +230,20 @@ nsHttpTransaction::Init(uint32_t caps,
mActivityDistributor = nullptr;
}
// obtain app info
bool isInBrowser;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(eventsink);
if (channel) {
bool isInBrowser;
NS_GetAppInfo(channel, &mAppId, &isInBrowser);
}
// obtain active connection type
#ifdef MOZ_WIDGET_GONK
if (mAppId != NECKO_NO_APP_ID) {
GetActiveNetwork();
nsCOMPtr<nsINetworkInterface> activeNetwork;
NS_GetActiveNetworkInterface(activeNetwork);
mActiveNetwork =
new nsMainThreadPtrHolder<nsINetworkInterface>(activeNetwork);
}
#endif
// create transport event sink proxy. it coalesces all events if and only
// if the activity observer is not active. when the observer is active
@ -707,28 +710,6 @@ nsHttpTransaction::WriteSegments(nsAHttpSegmentWriter *writer,
return rv;
}
void
nsHttpTransaction::GetActiveNetwork()
{
#ifdef MOZ_WIDGET_GONK
MOZ_ASSERT(NS_IsMainThread());
nsresult rv;
nsCOMPtr<nsINetworkManager> networkManager =
do_GetService("@mozilla.org/network/manager;1", &rv);
if (NS_FAILED(rv) || !networkManager) {
mActiveNetwork = nullptr;
return;
}
nsCOMPtr<nsINetworkInterface> activeNetwork;
networkManager->GetActive(getter_AddRefs(activeNetwork));
mActiveNetwork =
new nsMainThreadPtrHolder<nsINetworkInterface>(activeNetwork);
#endif
}
//-----------------------------------------------------------------------------
// nsHttpTransaction save network statistics event
//-----------------------------------------------------------------------------

View File

@ -340,10 +340,6 @@ private:
// These members are used for network per-app metering (bug 746073)
// Currently, they are only available on gonk.
public:
const static uint64_t NETWORK_STATS_THRESHOLD = 65536;
private:
uint64_t mCountRecv;
uint64_t mCountSent;
uint32_t mAppId;
@ -351,7 +347,6 @@ private:
nsMainThreadPtrHandle<nsINetworkInterface> mActiveNetwork;
#endif
nsresult SaveNetworkStats(bool);
void GetActiveNetwork();
void CountRecvBytes(uint64_t recvBytes)
{
mCountRecv += recvBytes;

View File

@ -965,8 +965,7 @@ WebSocketChannel::WebSocketChannel() :
mConnectionLogService(nullptr),
mCountRecv(0),
mCountSent(0),
mAppId(0),
mIsInBrowser(false)
mAppId(NECKO_NO_APP_ID)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
@ -1075,15 +1074,16 @@ WebSocketChannel::BeginOpen()
return;
}
// obtain app info
if (localChannel) {
NS_GetAppInfo(localChannel, &mAppId, &mIsInBrowser);
bool isInBrowser;
NS_GetAppInfo(localChannel, &mAppId, &isInBrowser);
}
// obtain active network
#ifdef MOZ_WIDGET_GONK
if (mAppId != NECKO_NO_APP_ID) {
GetActiveNetwork();
NS_GetActiveNetworkInterface(mActiveNetwork);
}
#endif
rv = localChannel->AsyncOpen(this, mHttpChannel);
if (NS_FAILED(rv)) {
@ -3271,28 +3271,6 @@ WebSocketChannel::OnDataAvailable(nsIRequest *aRequest,
return NS_OK;
}
nsresult
WebSocketChannel::GetActiveNetwork()
{
#ifdef MOZ_WIDGET_GONK
MOZ_ASSERT(NS_IsMainThread());
nsresult result;
nsCOMPtr<nsINetworkManager> networkManager = do_GetService("@mozilla.org/network/manager;1", &result);
if (NS_FAILED(result) || !networkManager) {
mActiveNetwork = nullptr;
return NS_ERROR_UNEXPECTED;
}
result = networkManager->GetActive(getter_AddRefs(mActiveNetwork));
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
nsresult
WebSocketChannel::SaveNetworkStats(bool enforce)
{

View File

@ -257,18 +257,12 @@ private:
// These members are used for network per-app metering (bug 855949)
// Currently, they are only available on gonk.
public:
const static uint64_t NETWORK_STATS_THRESHOLD = 65536;
private:
uint64_t mCountRecv;
uint64_t mCountSent;
uint32_t mAppId;
bool mIsInBrowser;
#ifdef MOZ_WIDGET_GONK
nsCOMPtr<nsINetworkInterface> mActiveNetwork;
#endif
nsresult GetActiveNetwork();
nsresult SaveNetworkStats(bool);
void CountRecvBytes(uint64_t recvBytes)
{

View File

@ -504,6 +504,7 @@
"dom/indexedDB/test/test_autoIncrement_indexes.html": "Bug 931116, b2g desktop specific, initial triage",
"dom/indexedDB/test/test_bfcache.html": "Bug 931116, b2g desktop specific, initial triage",
"dom/indexedDB/test/test_blob_archive.html": "Bug 931116, b2g desktop specific, initial triage",
"dom/indexedDB/test/test_blob_worker_crash.html": "Bug 931116, b2g desktop specific, bug 927889 still present",
"dom/indexedDB/test/test_blob_simple.html": "Bug 931116, b2g desktop specific, initial triage",
"dom/indexedDB/test/test_clear.html": "Bug 931116, b2g desktop specific, initial triage",
"dom/indexedDB/test/test_complex_keyPaths.html": "Bug 931116, b2g desktop specific, initial triage",

426
testing/modules/Assert.jsm Normal file
View File

@ -0,0 +1,426 @@
/* 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/. */
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
// When you see a javadoc comment that contains a number, it's a reference to a
// specific section of the CommonJS spec.
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
// MIT license: http://opensource.org/licenses/MIT
"use strict";
this.EXPORTED_SYMBOLS = [
"Assert"
];
/**
* 1. The assert module provides functions that throw AssertionError's when
* particular conditions are not met.
*
* To use the module you'll need to instantiate it first, which allows consumers
* to override certain behavior on the newly obtained instance. For examples,
* see the javadoc comments for the `report` member function.
*/
let Assert = this.Assert = function(reporterFunc) {
if (reporterFunc)
this.setReporter(reporterFunc);
};
function instanceOf(object, type) {
return Object.prototype.toString.call(object) == "[object " + type + "]";
}
function replacer(key, value) {
if (value === undefined) {
return "" + value;
}
if (typeof value === "number" && (isNaN(value) || !isFinite(value))) {
return value.toString();
}
if (typeof value === "function" || instanceOf(value, "RegExp")) {
return value.toString();
}
return value;
}
const kTruncateLength = 128;
function truncate(text, newLength = kTruncateLength) {
if (typeof text == "string") {
return text.length < newLength ? text : text.slice(0, newLength);
} else {
return text;
}
}
function getMessage(error) {
return truncate(JSON.stringify(error.actual, replacer)) + " " +
(error.operator ? error.operator + " " : "") +
truncate(JSON.stringify(error.expected, replacer));
}
/**
* 2. The AssertionError is defined in assert.
*
* Example:
* new assert.AssertionError({
* message: message,
* actual: actual,
* expected: expected,
* operator: operator
* });
*
* At present only the four keys mentioned above are used and
* understood by the spec. Implementations or sub modules can pass
* other keys to the AssertionError's constructor - they will be
* ignored.
*/
Assert.AssertionError = function(options) {
this.name = "AssertionError";
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
this.message = options.message || getMessage(this);
// The part of the stack that comes from this module is not interesting.
let stack = Components.stack;
do {
stack = stack.caller;
} while(stack.filename && stack.filename.contains("Assert.jsm"))
this.stack = stack;
};
// assert.AssertionError instanceof Error
Assert.AssertionError.prototype = Object.create(Error.prototype, {
constructor: {
value: Assert.AssertionError,
enumerable: false,
writable: true,
configurable: true
}
});
let proto = Assert.prototype;
proto._reporter = null;
/**
* Set a custom assertion report handler function. Arguments passed in to this
* function are:
* err (AssertionError|null) An error object when the assertion failed or null
* when it passed
* message (string) Message describing the assertion
* stack (stack) Stack trace of the assertion function
*
* Example:
* ```js
* Assert.setReporter(function customReporter(err, message, stack) {
* if (err) {
* do_report_result(false, err.message, err.stack);
* } else {
* do_report_result(true, message, stack);
* }
* });
* ```
*
* @param reporterFunc
* (function) Report handler function
*/
proto.setReporter = function(reporterFunc) {
this._reporter = reporterFunc;
};
/**
* 3. All of the following functions must throw an AssertionError when a
* corresponding condition is not met, with a message that may be undefined if
* not provided. All assertion methods provide both the actual and expected
* values to the assertion error for display purposes.
*
* This report method only throws errors on assertion failures, as per spec,
* but consumers of this module (think: xpcshell-test, mochitest) may want to
* override this default implementation.
*
* Example:
* ```js
* // The following will report an assertion failure.
* this.report(1 != 2, 1, 2, "testing JS number math!", "==");
* ```
*
* @param failed
* (boolean) Indicates if the assertion failed or not
* @param actual
* (mixed) The result of evaluating the assertion
* @param expected (optional)
* (mixed) Expected result from the test author
* @param message (optional)
* (string) Short explanation of the expected result
* @param operator (optional)
* (string) Operation qualifier used by the assertion method (ex: '==')
*/
proto.report = function(failed, actual, expected, message, operator) {
let err = new Assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator
});
if (!this._reporter) {
// If no custom reporter is set, throw the error.
if (failed) {
throw err;
}
} else {
this._reporter(failed ? err : null, message, err.stack);
}
};
/**
* 4. Pure assertion tests whether a value is truthy, as determined by !!guard.
* assert.ok(guard, message_opt);
* This statement is equivalent to assert.equal(true, !!guard, message_opt);.
* To test strictly for the value true, use assert.strictEqual(true, guard,
* message_opt);.
*
* @param value
* (mixed) Test subject to be evaluated as truthy
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.ok = function(value, message) {
this.report(!value, value, true, message, "==");
};
/**
* 5. The equality assertion tests shallow, coercive equality with ==.
* assert.equal(actual, expected, message_opt);
*
* @param actual
* (mixed) Test subject to be evaluated as equivalent to `expected`
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.equal = function equal(actual, expected, message) {
this.report(actual != expected, actual, expected, message, "==");
};
/**
* 6. The non-equality assertion tests for whether two objects are not equal
* with != assert.notEqual(actual, expected, message_opt);
*
* @param actual
* (mixed) Test subject to be evaluated as NOT equivalent to `expected`
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.notEqual = function notEqual(actual, expected, message) {
this.report(actual == expected, actual, expected, message, "!=");
};
/**
* 7. The equivalence assertion tests a deep equality relation.
* assert.deepEqual(actual, expected, message_opt);
*
* We check using the most exact approximation of equality between two objects
* to keep the chance of false positives to a minimum.
* `JSON.stringify` is not designed to be used for this purpose; objects may
* have ambiguous `toJSON()` implementations that would influence the test.
*
* @param actual
* (mixed) Test subject to be evaluated as equivalent to `expected`, including nested properties
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.deepEqual = function deepEqual(actual, expected, message) {
this.report(!_deepEqual(actual, expected), actual, expected, message, "deepEqual");
};
function _deepEqual(actual, expected) {
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (instanceOf(actual, "Date") && instanceOf(expected, "Date")) {
return actual.getTime() === expected.getTime();
// 7.3 If the expected value is a RegExp object, the actual value is
// equivalent if it is also a RegExp object with the same source and
// properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
} else if (instanceOf(actual, "RegExp") && instanceOf(expected, "RegExp")) {
return actual.source === expected.source &&
actual.global === expected.global &&
actual.multiline === expected.multiline &&
actual.lastIndex === expected.lastIndex &&
actual.ignoreCase === expected.ignoreCase;
// 7.4. Other pairs that do not both pass typeof value == "object",
// equivalence is determined by ==.
} else if (typeof actual != "object" && typeof expected != "object") {
return actual == expected;
// 7.5 For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical 'prototype' property. Note: this
// accounts for both named and indexed properties on Arrays.
} else {
return objEquiv(actual, expected);
}
}
function isUndefinedOrNull(value) {
return value === null || value === undefined;
}
function isArguments(object) {
return instanceOf(object, "Arguments");
}
function objEquiv(a, b) {
if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) {
return false;
}
// An identical 'prototype' property.
if (a.prototype !== b.prototype) {
return false;
}
// Object.keys may be broken through screwy arguments passing. Converting to
// an array solves the problem.
if (isArguments(a)) {
if (!isArguments(b)) {
return false;
}
a = pSlice.call(a);
b = pSlice.call(b);
return _deepEqual(a, b);
}
let ka, kb, key, i;
try {
ka = Object.keys(a);
kb = Object.keys(b);
} catch (e) {
// Happens when one is a string literal and the other isn't
return false;
}
// Having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length != kb.length)
return false;
// The same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
// Equivalent values for every corresponding key, and possibly expensive deep
// test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!_deepEqual(a[key], b[key])) {
return false;
}
}
return true;
}
/**
* 8. The non-equivalence assertion tests for any deep inequality.
* assert.notDeepEqual(actual, expected, message_opt);
*
* @param actual
* (mixed) Test subject to be evaluated as NOT equivalent to `expected`, including nested properties
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.notDeepEqual = function notDeepEqual(actual, expected, message) {
this.report(_deepEqual(actual, expected), actual, expected, message, "notDeepEqual");
};
/**
* 9. The strict equality assertion tests strict equality, as determined by ===.
* assert.strictEqual(actual, expected, message_opt);
*
* @param actual
* (mixed) Test subject to be evaluated as strictly equivalent to `expected`
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.strictEqual = function strictEqual(actual, expected, message) {
this.report(actual !== expected, actual, expected, message, "===");
};
/**
* 10. The strict non-equality assertion tests for strict inequality, as
* determined by !==. assert.notStrictEqual(actual, expected, message_opt);
*
* @param actual
* (mixed) Test subject to be evaluated as NOT strictly equivalent to `expected`
* @param expected
* (mixed) Test reference to evaluate against `actual`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.notStrictEqual = function notStrictEqual(actual, expected, message) {
this.report(actual === expected, actual, expected, message, "!==");
};
function expectedException(actual, expected) {
if (!actual || !expected) {
return false;
}
if (instanceOf(expected, "RegExp")) {
return expected.test(actual);
} else if (actual instanceof expected) {
return true;
} else if (expected.call({}, actual) === true) {
return true;
}
return false;
}
/**
* 11. Expected to throw an error:
* assert.throws(block, Error_opt, message_opt);
*
* @param block
* (function) Function block to evaluate and catch eventual thrown errors
* @param expected (optional)
* (mixed) Test reference to evaluate against the thrown result from `block`
* @param message (optional)
* (string) Short explanation of the expected result
*/
proto.throws = function(block, expected, message) {
let actual;
if (typeof expected === "string") {
message = expected;
expected = null;
}
try {
block();
} catch (e) {
actual = e;
}
message = (expected && expected.name ? " (" + expected.name + ")." : ".") +
(message ? " " + message : ".");
if (!actual) {
this.report(true, actual, expected, "Missing expected exception" + message);
}
if ((actual && expected && !expectedException(actual, expected))) {
throw actual;
}
this.report(false, expected, expected, message);
};

View File

@ -4,4 +4,5 @@
TESTING_JS_MODULES := \
AppInfo.jsm \
Assert.jsm \
$(NULL)

View File

@ -4,3 +4,4 @@
# 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/.
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']

View File

@ -0,0 +1,291 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test cases borrowed and adapted from:
// https://github.com/joyent/node/blob/6101eb184db77d0b11eb96e48744e57ecce4b73d/test/simple/test-assert.js
// MIT license: http://opensource.org/licenses/MIT
function run_test() {
let ns = {};
Components.utils.import("resource://testing-common/Assert.jsm", ns);
let assert = new ns.Assert();
function makeBlock(f, ...args) {
return function() {
return f.apply(assert, args);
};
}
function protoCtrChain(o) {
let result = [];
while (o = o.__proto__) {
result.push(o.constructor);
}
return result.join();
}
function indirectInstanceOf(obj, cls) {
if (obj instanceof cls) {
return true;
}
let clsChain = protoCtrChain(cls.prototype);
let objChain = protoCtrChain(obj);
return objChain.slice(-clsChain.length) === clsChain;
};
assert.ok(indirectInstanceOf(ns.Assert.AssertionError.prototype, Error),
"Assert.AssertionError instanceof Error");
assert.throws(makeBlock(assert.ok, false),
ns.Assert.AssertionError, "ok(false)");
assert.ok(true, "ok(true)");
assert.ok("test", "ok('test')");
assert.throws(makeBlock(assert.equal, true, false), ns.Assert.AssertionError, "equal");
assert.equal(null, null, "equal");
assert.equal(undefined, undefined, "equal");
assert.equal(null, undefined, "equal");
assert.equal(true, true, "equal");
assert.notEqual(true, false, "notEqual");
assert.throws(makeBlock(assert.notEqual, true, true),
ns.Assert.AssertionError, "notEqual");
assert.throws(makeBlock(assert.strictEqual, 2, "2"),
ns.Assert.AssertionError, "strictEqual");
assert.throws(makeBlock(assert.strictEqual, null, undefined),
ns.Assert.AssertionError, "strictEqual");
assert.notStrictEqual(2, "2", "notStrictEqual");
// deepEquals joy!
// 7.2
assert.deepEqual(new Date(2000, 3, 14), new Date(2000, 3, 14), "deepEqual date");
assert.throws(makeBlock(assert.deepEqual, new Date(), new Date(2000, 3, 14)),
ns.Assert.AssertionError,
"deepEqual date");
// 7.3
assert.deepEqual(/a/, /a/);
assert.deepEqual(/a/g, /a/g);
assert.deepEqual(/a/i, /a/i);
assert.deepEqual(/a/m, /a/m);
assert.deepEqual(/a/igm, /a/igm);
assert.throws(makeBlock(assert.deepEqual, /ab/, /a/));
assert.throws(makeBlock(assert.deepEqual, /a/g, /a/));
assert.throws(makeBlock(assert.deepEqual, /a/i, /a/));
assert.throws(makeBlock(assert.deepEqual, /a/m, /a/));
assert.throws(makeBlock(assert.deepEqual, /a/igm, /a/im));
let re1 = /a/;
re1.lastIndex = 3;
assert.throws(makeBlock(assert.deepEqual, re1, /a/));
// 7.4
assert.deepEqual(4, "4", "deepEqual == check");
assert.deepEqual(true, 1, "deepEqual == check");
assert.throws(makeBlock(assert.deepEqual, 4, "5"),
ns.Assert.AssertionError,
"deepEqual == check");
// 7.5
// having the same number of owned properties && the same set of keys
assert.deepEqual({a: 4}, {a: 4});
assert.deepEqual({a: 4, b: "2"}, {a: 4, b: "2"});
assert.deepEqual([4], ["4"]);
assert.throws(makeBlock(assert.deepEqual, {a: 4}, {a: 4, b: true}),
ns.Assert.AssertionError);
assert.deepEqual(["a"], {0: "a"});
let a1 = [1, 2, 3];
let a2 = [1, 2, 3];
a1.a = "test";
a1.b = true;
a2.b = true;
a2.a = "test";
assert.throws(makeBlock(assert.deepEqual, Object.keys(a1), Object.keys(a2)),
ns.Assert.AssertionError);
assert.deepEqual(a1, a2);
let nbRoot = {
toString: function() { return this.first + " " + this.last; }
};
function nameBuilder(first, last) {
this.first = first;
this.last = last;
return this;
}
nameBuilder.prototype = nbRoot;
function nameBuilder2(first, last) {
this.first = first;
this.last = last;
return this;
}
nameBuilder2.prototype = nbRoot;
let nb1 = new nameBuilder("Ryan", "Dahl");
let nb2 = new nameBuilder2("Ryan", "Dahl");
assert.deepEqual(nb1, nb2);
nameBuilder2.prototype = Object;
nb2 = new nameBuilder2("Ryan", "Dahl");
assert.throws(makeBlock(assert.deepEqual, nb1, nb2), ns.Assert.AssertionError);
// String literal + object
assert.throws(makeBlock(assert.deepEqual, "a", {}), ns.Assert.AssertionError);
// Testing the throwing
function thrower(errorConstructor) {
throw new errorConstructor("test");
}
let aethrow = makeBlock(thrower, ns.Assert.AssertionError);
aethrow = makeBlock(thrower, ns.Assert.AssertionError);
// the basic calls work
assert.throws(makeBlock(thrower, ns.Assert.AssertionError),
ns.Assert.AssertionError, "message");
assert.throws(makeBlock(thrower, ns.Assert.AssertionError), ns.Assert.AssertionError);
assert.throws(makeBlock(thrower, ns.Assert.AssertionError));
// if not passing an error, catch all.
assert.throws(makeBlock(thrower, TypeError));
// when passing a type, only catch errors of the appropriate type
let threw = false;
try {
assert.throws(makeBlock(thrower, TypeError), ns.Assert.AssertionError);
} catch (e) {
threw = true;
assert.ok(e instanceof TypeError, "type");
}
assert.equal(true, threw,
"Assert.throws with an explicit error is eating extra errors",
ns.Assert.AssertionError);
threw = false;
function ifError(err) {
if (err) {
throw err;
}
}
assert.throws(function() {
ifError(new Error("test error"));
});
// make sure that validating using constructor really works
threw = false;
try {
assert.throws(
function() {
throw ({});
},
Array
);
} catch (e) {
threw = true;
}
assert.ok(threw, "wrong constructor validation");
// use a RegExp to validate error message
assert.throws(makeBlock(thrower, TypeError), /test/);
// use a fn to validate error object
assert.throws(makeBlock(thrower, TypeError), function(err) {
if ((err instanceof TypeError) && /test/.test(err)) {
return true;
}
});
// Make sure deepEqual doesn't loop forever on circular refs
let b = {};
b.b = b;
let c = {};
c.b = c;
let gotError = false;
try {
assert.deepEqual(b, c);
} catch (e) {
gotError = true;
}
dump("All OK\n");
assert.ok(gotError);
function testAssertionMessage(actual, expected) {
try {
assert.equal(actual, "");
} catch (e) {
assert.equal(e.toString(),
["AssertionError:", expected, "==", '""'].join(" "));
}
}
testAssertionMessage(undefined, '"undefined"');
testAssertionMessage(null, "null");
testAssertionMessage(true, "true");
testAssertionMessage(false, "false");
testAssertionMessage(0, "0");
testAssertionMessage(100, "100");
testAssertionMessage(NaN, '"NaN"');
testAssertionMessage(Infinity, '"Infinity"');
testAssertionMessage(-Infinity, '"-Infinity"');
testAssertionMessage("", '""');
testAssertionMessage("foo", '"foo"');
testAssertionMessage([], "[]");
testAssertionMessage([1, 2, 3], "[1,2,3]");
testAssertionMessage(/a/, '"/a/"');
testAssertionMessage(/abc/gim, '"/abc/gim"');
testAssertionMessage(function f() {}, '"function f() {}"');
testAssertionMessage({}, "{}");
testAssertionMessage({a: undefined, b: null}, '{"a":"undefined","b":null}');
testAssertionMessage({a: NaN, b: Infinity, c: -Infinity},
'{"a":"NaN","b":"Infinity","c":"-Infinity"}');
// https://github.com/joyent/node/issues/2893
try {
assert.throws(function () {
ifError(null);
});
} catch (e) {
threw = true;
assert.equal(e.message, "Missing expected exception..");
}
assert.ok(threw);
// https://github.com/joyent/node/issues/5292
try {
assert.equal(1, 2);
} catch (e) {
assert.equal(e.toString().split("\n")[0], "AssertionError: 1 == 2")
}
try {
assert.equal(1, 2, "oh no");
} catch (e) {
assert.equal(e.toString().split("\n")[0], "AssertionError: oh no")
}
// Export Assert.jsm methods to become globally accessible.
export_assertions();
// Test XPCShell-test integration:
ok(true, "OK, this went well");
deepEqual(/a/g, /a/g, "deep equal should work on RegExp");
deepEqual(/a/igm, /a/igm, "deep equal should work on RegExp");
deepEqual({a: 4, b: "1"}, {b: "1", a: 4}, "deep equal should work on regular Object");
deepEqual(a1, a2, "deep equal should work on Array with Object properties");
}

View File

@ -0,0 +1,5 @@
[DEFAULT]
head =
tail =
[test_assert.js]

View File

@ -184,6 +184,15 @@ function _do_quit() {
}
function _format_exception_stack(stack) {
if (typeof stack == "object" && stack.caller) {
let frame = stack;
let strStack = "";
while (frame != null) {
strStack += frame + "\n";
frame = frame.caller;
}
stack = strStack;
}
// frame is of the form "fname@file:line"
let frame_regexp = new RegExp("(.*)@(.*):(\\d*)", "g");
return stack.split("\n").reduce(function(stack_msg, frame) {
@ -343,6 +352,24 @@ function _execute_test() {
// _TEST_FILE is dynamically defined by <runxpcshelltests.py>.
_load_files(_TEST_FILE);
// Support a common assertion library, Assert.jsm.
let Assert = Components.utils.import("resource://testing-common/Assert.jsm", null).Assert;
// Pass a custom report function for xpcshell-test style reporting.
let assertImpl = new Assert(function(err, message, stack) {
if (err) {
do_report_result(false, err.message, err.stack);
} else {
do_report_result(true, message, stack);
}
});
// Allow Assert.jsm methods to be tacked to the current scope.
this.export_assertions = function() {
for (let func in assertImpl) {
this[func] = assertImpl[func].bind(assertImpl);
}
};
this.Assert = assertImpl;
try {
do_test_pending("MAIN run_test");
run_test();

View File

@ -3671,6 +3671,18 @@
"n_values": 3,
"description": "User actions taken in the plugin notification: 0: allownow 1: allowalways 2: block"
},
"PLUGINS_INFOBAR_SHOWN": {
"kind": "boolean",
"description": "Count of when the hidden-plugin infobar was displayed."
},
"PLUGINS_INFOBAR_BLOCK": {
"kind": "boolean",
"description": "Count the number of times the user clicked 'block' on the hidden-plugin infobar."
},
"PLUGINS_INFOBAR_ALLOW": {
"kind": "boolean",
"description": "Count the number of times the user clicked 'allow' on the hidden-plugin infobar."
},
"POPUP_NOTIFICATION_MAINACTION_TRIGGERED_MS": {
"kind": "linear",
"low": 25,

View File

@ -452,6 +452,7 @@ var PageStyleActor = protocol.ActorClass({
// We compute and update the values of margins & co.
let style = node.rawNode.ownerDocument.defaultView.getComputedStyle(node.rawNode);
for (let prop of [
"position",
"margin-top",
"margin-right",
"margin-bottom",

View File

@ -730,7 +730,7 @@ CssLogic.getSelectors = function CssLogic_getSelectors(aDOMRule)
CssLogic.l10n = function(aName) CssLogic._strings.GetStringFromName(aName);
XPCOMUtils.defineLazyGetter(CssLogic, "_strings", function() Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
.createBundle("chrome://global/locale/devtools/styleinspector.properties"));
/**
* Is the given property sheet a content stylesheet?

View File

@ -32,6 +32,7 @@
locale/@AB_CD@/global/datetimepicker.dtd (%chrome/global/datetimepicker.dtd)
locale/@AB_CD@/global/dateFormat.properties (%chrome/global/dateFormat.properties)
locale/@AB_CD@/global/devtools/debugger.properties (%chrome/global/devtools/debugger.properties)
locale/@AB_CD@/global/devtools/styleinspector.properties (%chrome/global/devtools/styleinspector.properties)
locale/@AB_CD@/global/dialogOverlay.dtd (%chrome/global/dialogOverlay.dtd)
locale/@AB_CD@/global/editMenuOverlay.dtd (%chrome/global/editMenuOverlay.dtd)
locale/@AB_CD@/global/filefield.properties (%chrome/global/filefield.properties)

View File

@ -1461,30 +1461,33 @@ function recursiveRemove(aFile) {
* Returns the timestamp and leaf file name of the most recently modified
* entry in a directory,
* or simply the file's own timestamp if it is not a directory.
* Also returns the total number of items (directories and files) visited in the scan
*
* @param aFile
* A non-null nsIFile object
* @return [File Name, Epoch time], as described above.
* @return [File Name, Epoch time, items visited], as described above.
*/
function recursiveLastModifiedTime(aFile) {
try {
let modTime = aFile.lastModifiedTime;
let fileName = aFile.leafName;
if (aFile.isFile())
return [fileName, modTime];
return [fileName, modTime, 1];
if (aFile.isDirectory()) {
let entries = aFile.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
let entry;
let totalItems = 1;
while ((entry = entries.nextFile)) {
let [subName, subTime] = recursiveLastModifiedTime(entry);
let [subName, subTime, items] = recursiveLastModifiedTime(entry);
totalItems += items;
if (subTime > modTime) {
modTime = subTime;
fileName = subName;
}
}
entries.close();
return [fileName, modTime];
return [fileName, modTime, totalItems];
}
}
catch (e) {
@ -1492,7 +1495,7 @@ function recursiveLastModifiedTime(aFile) {
}
// If the file is something else, just ignore it.
return ["", 0];
return ["", 0, 0];
}
/**
@ -1638,6 +1641,49 @@ var Prefs = {
}
}
// Helper function to compare JSON saved version of the directory state
// with the new state returned by getInstallLocationStates()
// Structure is: ordered array of {'name':?, 'addons': {addonID: {'descriptor':?, 'mtime':?} ...}}
function directoryStateDiffers(aState, aCache)
{
// check equality of an object full of addons; fortunately we can destroy the 'aOld' object
function addonsMismatch(aNew, aOld) {
for (let [id, val] of aNew) {
if (!id in aOld)
return true;
if (val.descriptor != aOld[id].descriptor ||
val.mtime != aOld[id].mtime)
return true;
delete aOld[id];
}
// make sure aOld doesn't have any extra entries
for (let id in aOld)
return true;
return false;
}
if (!aCache)
return true;
try {
let old = JSON.parse(aCache);
if (aState.length != old.length)
return true;
for (let i = 0; i < aState.length; i++) {
// conveniently, any missing fields would require a 'true' return, which is
// handled by our catch wrapper
if (aState[i].name != old[i].name)
return true;
if (addonsMismatch(aState[i].addons, old[i].addons))
return true;
}
}
catch (e) {
return true;
}
return false;
}
var XPIProvider = {
// An array of known install locations
installLocations: null,
@ -2178,9 +2224,10 @@ var XPIProvider = {
getAddonStates: function XPI_getAddonStates(aLocation) {
let addonStates = {};
for (let file of aLocation.addonLocations) {
let scanStarted = Date.now();
let id = aLocation.getIDForLocation(file);
let unpacked = 0;
let [modFile, modTime] = recursiveLastModifiedTime(file);
let [modFile, modTime, items] = recursiveLastModifiedTime(file);
addonStates[id] = {
descriptor: file.persistentDescriptor,
mtime: modTime
@ -2196,6 +2243,8 @@ var XPIProvider = {
this._mostRecentlyModifiedFile[id] = modFile;
this.setTelemetry(id, "unpacked", unpacked);
this.setTelemetry(id, "location", aLocation.name);
this.setTelemetry(id, "scan_MS", Date.now() - scanStarted);
this.setTelemetry(id, "scan_items", items);
}
return addonStates;
@ -3372,8 +3421,15 @@ var XPIProvider = {
// If the install directory state has changed then we must update the database
let cache = Prefs.getCharPref(PREF_INSTALL_CACHE, null);
// For a little while, gather telemetry on whether the deep comparison
// makes a difference
if (cache != JSON.stringify(state)) {
updateReasons.push("directoryState");
if (directoryStateDiffers(state, cache)) {
updateReasons.push("directoryState");
}
else {
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startup_state_badCompare", 1);
}
}
// If the database doesn't exist and there are add-ons installed then we
@ -5500,7 +5556,9 @@ AddonInstall.prototype = {
// Update the metadata in the database
this.addon._sourceBundle = file;
this.addon._installLocation = this.installLocation;
let [mFile, mTime] = recursiveLastModifiedTime(file);
let scanStarted = Date.now();
let [, mTime, scanItems] = recursiveLastModifiedTime(file);
let scanTime = Date.now() - scanStarted;
this.addon.updateDate = mTime;
this.addon.visible = true;
if (isUpgrade) {
@ -5547,6 +5605,8 @@ AddonInstall.prototype = {
}
XPIProvider.setTelemetry(this.addon.id, "unpacked", installedUnpacked);
XPIProvider.setTelemetry(this.addon.id, "location", this.installLocation.name);
XPIProvider.setTelemetry(this.addon.id, "scan_MS", scanTime);
XPIProvider.setTelemetry(this.addon.id, "scan_items", scanItems);
let loc = this.addon.defaultLocale;
if (loc) {
XPIProvider.setTelemetry(this.addon.id, "name", loc.name);

View File

@ -104,6 +104,13 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf()
// no associated phdrs
if (strcmp(name, "/dev/ashmem/dalvik-jit-code-cache") != 0)
continue;
#else
if (strcmp(perm, "r-xp") != 0) {
// Ignore entries that are writable and/or shared.
// At least one graphics driver uses short-lived "rwxs" mappings
// (see bug 926734 comment 5), so just checking for 'x' isn't enough.
continue;
}
#endif
SharedLibrary shlib(start, end, offset, "", name);
info.AddSharedLibrary(shlib);

View File

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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
@ -26,6 +26,7 @@
#include "BasicLayers.h"
#include "FrameMetrics.h"
#include "Windows.Graphics.Display.h"
#include "nsNativeDragTarget.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
@ -333,6 +334,28 @@ MetroWidget::IsVisible() const
return mView->IsVisible();
}
NS_IMETHODIMP
MetroWidget::EnableDragDrop(bool aEnable) {
if (aEnable) {
if (nullptr == mNativeDragTarget) {
mNativeDragTarget = new nsNativeDragTarget(this);
if (!mNativeDragTarget) {
return NS_ERROR_FAILURE;
}
}
HRESULT hr = ::RegisterDragDrop(mWnd, static_cast<LPDROPTARGET>(mNativeDragTarget));
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
} else {
if (nullptr == mNativeDragTarget) {
return NS_OK;
}
HRESULT hr = ::RevokeDragDrop(mWnd);
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
}
}
NS_IMETHODIMP
MetroWidget::IsEnabled(bool *aState)
{

View File

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
@ -34,6 +34,7 @@
#include <Windows.ApplicationModel.h>
#include <Windows.Applicationmodel.Activation.h>
class nsNativeDragTarget;
namespace mozilla {
namespace widget {
@ -94,6 +95,7 @@ public:
nsDeviceContext *aContext,
nsWidgetInitData *aInitData = nullptr);
NS_IMETHOD Destroy();
NS_IMETHOD EnableDragDrop(bool aEnable);
NS_IMETHOD SetParent(nsIWidget *aNewParent);
NS_IMETHOD Show(bool bState);
NS_IMETHOD IsVisible(bool & aState);
@ -260,4 +262,5 @@ protected:
nsDeque mEventQueue;
nsDeque mKeyEventQueue;
nsRefPtr<APZController> mController;
nsRefPtr<nsNativeDragTarget> mNativeDragTarget;
};

View File

@ -2816,6 +2816,11 @@ nsCycleCollector::Shutdown()
// Always delete snow white objects.
FreeSnowWhite(true);
#ifdef MOZ_VALGRIND
char *e = PR_GetEnv("XPCOM_CC_RUN_DURING_SHUTDOWN");
fprintf(stderr, "XPCOM_CC_RUN_DURING_SHUTDOWN = %s\n", e);
#endif
#ifndef DEBUG
if (PR_GetEnv("XPCOM_CC_RUN_DURING_SHUTDOWN"))
#endif