mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 20:17:37 +00:00
Merge fx-team to m-c. a=merge
This commit is contained in:
commit
30db5a9c73
@ -551,14 +551,15 @@ SocialShare = {
|
||||
},
|
||||
|
||||
update: function() {
|
||||
let shareButton = this.shareButton;
|
||||
if (!shareButton)
|
||||
let widget = CustomizableUI.getWidget("social-share-button");
|
||||
if (!widget)
|
||||
return;
|
||||
// if we got here, the button is in the window somewhere, update it's hidden
|
||||
// state based on available providers.
|
||||
shareButton.hidden = !SocialUI.enabled ||
|
||||
[p for (p of Social.providers) if (p.shareURL)].length == 0;
|
||||
let disabled = shareButton.hidden || !this.canSharePage(gBrowser.currentURI);
|
||||
let shareButton = widget.forWindow(window).node;
|
||||
// hidden state is based on available share providers and location of
|
||||
// button. It's always visible and disabled in the customization palette.
|
||||
shareButton.hidden = !SocialUI.enabled || (widget.areaType &&
|
||||
[p for (p of Social.providers) if (p.shareURL)].length == 0);
|
||||
let disabled = !widget.areaType || shareButton.hidden || !this.canSharePage(gBrowser.currentURI);
|
||||
|
||||
// 1. update the relevent command's disabled state so the keyboard
|
||||
// shortcut only works when available.
|
||||
|
@ -939,6 +939,7 @@
|
||||
tooltiptext="&sharePageCmd.label;"
|
||||
cui-areatype="toolbar"
|
||||
removable="true"
|
||||
hidden="true"
|
||||
command="Social:SharePage"/>
|
||||
</hbox>
|
||||
|
||||
|
@ -13,7 +13,6 @@ Cu.import("resource://gre/modules/PageThumbs.jsm");
|
||||
Cu.import("resource://gre/modules/BackgroundPageThumbs.jsm");
|
||||
Cu.import("resource://gre/modules/DirectoryLinksProvider.jsm");
|
||||
Cu.import("resource://gre/modules/NewTabUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Rect",
|
||||
"resource://gre/modules/Geometry.jsm");
|
||||
|
@ -179,19 +179,18 @@ let gTransformation = {
|
||||
if (!aSite || aSite == gDrag.draggedSite)
|
||||
return;
|
||||
|
||||
let deferred = Promise.defer();
|
||||
batch.push(deferred.promise);
|
||||
let cb = deferred.resolve;
|
||||
|
||||
if (!cells[aIndex])
|
||||
// The site disappeared from the grid, hide it.
|
||||
this.hideSite(aSite, cb);
|
||||
else if (this._getNodeOpacity(aSite.node) != 1)
|
||||
// The site disappeared before but is now back, show it.
|
||||
this.showSite(aSite, cb);
|
||||
else
|
||||
// The site's position has changed, move it around.
|
||||
this._moveSite(aSite, aIndex, {unfreeze: unfreeze, callback: cb});
|
||||
batch.push(new Promise(resolve => {
|
||||
if (!cells[aIndex]) {
|
||||
// The site disappeared from the grid, hide it.
|
||||
this.hideSite(aSite, resolve);
|
||||
} else if (this._getNodeOpacity(aSite.node) != 1) {
|
||||
// The site disappeared before but is now back, show it.
|
||||
this.showSite(aSite, resolve);
|
||||
} else {
|
||||
// The site's position has changed, move it around.
|
||||
this._moveSite(aSite, aIndex, {unfreeze: unfreeze, callback: resolve});
|
||||
}
|
||||
}));
|
||||
}, this);
|
||||
|
||||
if (callback) {
|
||||
|
@ -134,17 +134,16 @@ let gUpdater = {
|
||||
if (!aSite || aSites.indexOf(aSite) != -1)
|
||||
return;
|
||||
|
||||
let deferred = Promise.defer();
|
||||
batch.push(deferred.promise);
|
||||
batch.push(new Promise(resolve => {
|
||||
// Fade out the to-be-removed site.
|
||||
gTransformation.hideSite(aSite, function () {
|
||||
let node = aSite.node;
|
||||
|
||||
// Fade out the to-be-removed site.
|
||||
gTransformation.hideSite(aSite, function () {
|
||||
let node = aSite.node;
|
||||
|
||||
// Remove the site from the DOM.
|
||||
node.parentNode.removeChild(node);
|
||||
deferred.resolve();
|
||||
});
|
||||
// Remove the site from the DOM.
|
||||
node.parentNode.removeChild(node);
|
||||
resolve();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
Promise.all(batch).then(aCallback);
|
||||
@ -164,19 +163,18 @@ let gUpdater = {
|
||||
if (aSite || !aLinks[aIndex])
|
||||
return;
|
||||
|
||||
let deferred = Promise.defer();
|
||||
batch.push(deferred.promise);
|
||||
batch.push(new Promise(resolve => {
|
||||
// Create the new site and fade it in.
|
||||
let site = gGrid.createSite(aLinks[aIndex], cells[aIndex]);
|
||||
|
||||
// Create the new site and fade it in.
|
||||
let site = gGrid.createSite(aLinks[aIndex], cells[aIndex]);
|
||||
// Set the site's initial opacity to zero.
|
||||
site.node.style.opacity = 0;
|
||||
|
||||
// Set the site's initial opacity to zero.
|
||||
site.node.style.opacity = 0;
|
||||
|
||||
// Flush all style changes for the dynamically inserted site to make
|
||||
// the fade-in transition work.
|
||||
window.getComputedStyle(site.node).opacity;
|
||||
gTransformation.showSite(site, function () deferred.resolve());
|
||||
// Flush all style changes for the dynamically inserted site to make
|
||||
// the fade-in transition work.
|
||||
window.getComputedStyle(site.node).opacity;
|
||||
gTransformation.showSite(site, resolve);
|
||||
}));
|
||||
});
|
||||
|
||||
Promise.all(batch).then(aCallback);
|
||||
|
@ -47,6 +47,7 @@ function runTests() {
|
||||
expected.action = "unpin";
|
||||
expected.pinned = true;
|
||||
yield EventUtils.synthesizeMouseAtCenter(pinButton, {}, getContentWindow());
|
||||
yield whenPagesUpdated();
|
||||
|
||||
// Block the site in the 0th tile spot
|
||||
let blockedSite = getCell(0).node.querySelector(".newtab-site");
|
||||
|
@ -11,7 +11,8 @@ pref("startup.homepage_welcome_url","");
|
||||
pref("app.update.interval", 28800); // 8 hours
|
||||
// The time interval between the downloading of mar file chunks in the
|
||||
// background (in seconds)
|
||||
pref("app.update.download.backgroundInterval", 60);
|
||||
// 0 means "download everything at once"
|
||||
pref("app.update.download.backgroundInterval", 0);
|
||||
// Give the user x seconds to react before showing the big UI. default=168 hours
|
||||
pref("app.update.promptWaitTime", 604800);
|
||||
// URL user can browse to manually if for some reason all update installation
|
||||
|
@ -8,7 +8,8 @@ pref("startup.homepage_welcome_url", "https://www.mozilla.org/projects/firefox/%
|
||||
pref("app.update.interval", 7200); // 2 hours
|
||||
// The time interval between the downloading of mar file chunks in the
|
||||
// background (in seconds)
|
||||
pref("app.update.download.backgroundInterval", 60);
|
||||
// 0 means "download everything at once"
|
||||
pref("app.update.download.backgroundInterval", 0);
|
||||
// Give the user x seconds to react before showing the big UI. default=12 hours
|
||||
pref("app.update.promptWaitTime", 43200);
|
||||
// URL user can browse to manually if for some reason all update installation
|
||||
|
@ -78,7 +78,7 @@
|
||||
<!-- Tracking -->
|
||||
<groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" align="start">
|
||||
<caption><label>&tracking.label;</label></caption>
|
||||
<radiogroup id="doNotTrackSelection" orient="vertical"
|
||||
<radiogroup id="doNotTrackSelection" orient="vertical" align="start"
|
||||
preference="privacy.donottrackheader.value"
|
||||
onsynctopreference="return gPrivacyPane.setTrackingPrefs()"
|
||||
onsyncfrompreference="return gPrivacyPane.getTrackingPrefs()">
|
||||
@ -151,37 +151,31 @@
|
||||
<vbox id="historyCustomPane">
|
||||
<separator class="thin"/>
|
||||
<vbox class="indent">
|
||||
<hbox>
|
||||
<vbox align="start">
|
||||
<checkbox id="privateBrowsingAutoStart"
|
||||
label="&privateBrowsingPermanent2.label;"
|
||||
accesskey="&privateBrowsingPermanent2.accesskey;"
|
||||
preference="browser.privatebrowsing.autostart"
|
||||
oncommand="gPrivacyPane.updateAutostart()"/>
|
||||
<spacer flex="1"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<vbox class="indent">
|
||||
<hbox>
|
||||
<vbox align="start">
|
||||
<checkbox id="rememberHistory"
|
||||
label="&rememberHistory2.label;"
|
||||
accesskey="&rememberHistory2.accesskey;"
|
||||
preference="places.history.enabled"/>
|
||||
<spacer flex="1"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<checkbox id="rememberForms"
|
||||
label="&rememberSearchForm.label;"
|
||||
accesskey="&rememberSearchForm.accesskey;"
|
||||
preference="browser.formfill.enable"/>
|
||||
<spacer flex="1"/>
|
||||
</hbox>
|
||||
|
||||
</vbox>
|
||||
<hbox id="cookiesBox">
|
||||
<checkbox id="acceptCookies" label="&acceptCookies.label;"
|
||||
preference="network.cookie.cookieBehavior"
|
||||
accesskey="&acceptCookies.accesskey;"
|
||||
onsyncfrompreference="return gPrivacyPane.readAcceptCookies();"
|
||||
onsynctopreference="return gPrivacyPane.writeAcceptCookies();"/>
|
||||
<spacer flex="1"/>
|
||||
<spacer flex="1" />
|
||||
<button id="cookieExceptions" oncommand="gPrivacyPane.showCookieExceptions();"
|
||||
label="&cookieExceptions.label;" accesskey="&cookieExceptions.accesskey;"
|
||||
preference="pref.privacy.disable_button.cookie_exceptions"/>
|
||||
|
@ -3618,6 +3618,7 @@ notification[value="translation"] {
|
||||
border-bottom: 1px solid #c4c4c4;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
min-height: 35px;
|
||||
}
|
||||
|
||||
.translate-infobar-element {
|
||||
|
@ -10,6 +10,11 @@ import android.content.Context;
|
||||
public class PrivateTab extends Tab {
|
||||
public PrivateTab(Context context, int id, String url, boolean external, int parentId, String title) {
|
||||
super(context, id, url, external, parentId, title);
|
||||
|
||||
// Init background to background_private to ensure flicker-free
|
||||
// private tab creation. Page loads will reset it to white as expected.
|
||||
final int bgColor = context.getResources().getColor(R.color.background_private);
|
||||
setBackgroundColor(bgColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -136,10 +136,8 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
|
||||
|
||||
public LayerRenderer(LayerView view) {
|
||||
mView = view;
|
||||
try {
|
||||
mOverscrollColor = view.getContext().getResources().getColor(R.color.background_normal);
|
||||
} catch (Resources.NotFoundException nfe) { mOverscrollColor = Color.BLACK; }
|
||||
|
||||
setOverscrollColor(R.color.background_normal);
|
||||
|
||||
Bitmap scrollbarImage = view.getScrollbarImage();
|
||||
IntSize size = new IntSize(scrollbarImage.getWidth(), scrollbarImage.getHeight());
|
||||
scrollbarImage = expandCanvasToPowerOfTwo(scrollbarImage, size);
|
||||
@ -199,6 +197,12 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
|
||||
activateDefaultProgram();
|
||||
}
|
||||
|
||||
void setOverscrollColor(int colorId) {
|
||||
try {
|
||||
mOverscrollColor = mView.getContext().getResources().getColor(colorId);
|
||||
} catch (Resources.NotFoundException nfe) { mOverscrollColor = Color.BLACK; }
|
||||
}
|
||||
|
||||
public void createDefaultProgram() {
|
||||
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, DEFAULT_VERTEX_SHADER);
|
||||
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, DEFAULT_FRAGMENT_SHADER);
|
||||
@ -717,6 +721,10 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
|
||||
// thread, so this may need to be changed if any problems appear.
|
||||
if (msg == Tabs.TabEvents.SELECTED) {
|
||||
if (mView != null) {
|
||||
final int overscrollColor =
|
||||
(tab.isPrivate() ? R.color.background_private : R.color.background_normal);
|
||||
setOverscrollColor(overscrollColor);
|
||||
|
||||
if (mView.getChildAt(0) != null) {
|
||||
mView.getChildAt(0).setBackgroundColor(tab.getBackgroundColor());
|
||||
}
|
||||
|
@ -3,11 +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/. -->
|
||||
|
||||
<org.mozilla.gecko.tabspanel.RemoteTabsSetupPanel
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<LinearLayout android:id="@+id/remote_tabs_setup_containing_layout"
|
||||
style="@style/TabsPanelFrame"
|
||||
@ -56,4 +52,4 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.mozilla.gecko.tabspanel.RemoteTabsSetupPanel>
|
||||
</merge>
|
||||
|
@ -3,11 +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/. -->
|
||||
|
||||
<org.mozilla.gecko.tabspanel.RemoteTabsVerificationPanel
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<LinearLayout android:id="@+id/remote_tabs_verification_containing_layout"
|
||||
style="@style/TabsPanelFrame"
|
||||
@ -51,4 +47,4 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.mozilla.gecko.tabspanel.RemoteTabsVerificationPanel>
|
||||
</merge>
|
||||
|
@ -99,25 +99,25 @@ class RemoteTabsPanel extends FrameLayout implements PanelView {
|
||||
}
|
||||
|
||||
private PanelView inflatePanel(final RemotePanelType panelType) {
|
||||
final LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
final View inflatedView;
|
||||
final PanelView view;
|
||||
switch (panelType) {
|
||||
case SETUP:
|
||||
inflatedView = inflater.inflate(R.layout.remote_tabs_setup_panel, null);
|
||||
view = new RemoteTabsSetupPanel(getContext());
|
||||
break;
|
||||
|
||||
case VERIFICATION:
|
||||
inflatedView = inflater.inflate(R.layout.remote_tabs_verification_panel, null);
|
||||
view = new RemoteTabsVerificationPanel(getContext());
|
||||
break;
|
||||
|
||||
case CONTAINER:
|
||||
inflatedView = inflater.inflate(R.layout.remote_tabs_container_panel, null);
|
||||
final LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
view = (PanelView) inflater.inflate(R.layout.remote_tabs_container_panel, null);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown panelType, " + panelType);
|
||||
}
|
||||
|
||||
return (PanelView) inflatedView;
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import org.mozilla.gecko.tabspanel.TabsPanel.PanelView;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
@ -25,18 +25,14 @@ import android.widget.ScrollView;
|
||||
* contained by the {@link RemoteTabsPanel}.
|
||||
*/
|
||||
class RemoteTabsSetupPanel extends ScrollView implements PanelView {
|
||||
private LinearLayout containingLayout;
|
||||
private final LinearLayout containingLayout;
|
||||
|
||||
private TabsPanel tabsPanel;
|
||||
|
||||
public RemoteTabsSetupPanel(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
public RemoteTabsSetupPanel(Context context) {
|
||||
super(context);
|
||||
|
||||
LayoutInflater.from(context).inflate(R.layout.remote_tabs_setup_panel, this);
|
||||
containingLayout = (LinearLayout) findViewById(R.id.remote_tabs_setup_containing_layout);
|
||||
|
||||
final View setupGetStartedButton =
|
||||
|
@ -10,8 +10,8 @@ import org.mozilla.gecko.fxa.login.State;
|
||||
import org.mozilla.gecko.tabspanel.TabsPanel.PanelView;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
@ -25,18 +25,14 @@ import android.widget.TextView;
|
||||
class RemoteTabsVerificationPanel extends ScrollView implements PanelView {
|
||||
private static final String LOG_TAG = RemoteTabsVerificationPanel.class.getSimpleName();
|
||||
|
||||
private LinearLayout containingLayout;
|
||||
private final LinearLayout containingLayout;
|
||||
|
||||
private TabsPanel tabsPanel;
|
||||
|
||||
public RemoteTabsVerificationPanel(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
public RemoteTabsVerificationPanel(Context context) {
|
||||
super(context);
|
||||
|
||||
LayoutInflater.from(context).inflate(R.layout.remote_tabs_verification_panel, this);
|
||||
containingLayout = (LinearLayout) findViewById(R.id.remote_tabs_verification_containing_layout);
|
||||
|
||||
final View resendLink = containingLayout.findViewById(R.id.remote_tabs_confirm_resend);
|
||||
|
@ -172,9 +172,15 @@ public class TabsPanel extends LinearLayout
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
final Menu menu = mPopupMenu.getMenu();
|
||||
|
||||
// Each panel has a "+" shortcut button, so don't show it for that panel.
|
||||
menu.findItem(R.id.new_tab).setVisible(mCurrentPanel != Panel.NORMAL_TABS);
|
||||
menu.findItem(R.id.new_private_tab).setVisible(mCurrentPanel != Panel.PRIVATE_TABS);
|
||||
|
||||
// Only show "Clear * tabs" for current panel.
|
||||
menu.findItem(R.id.close_all_tabs).setVisible(mCurrentPanel == Panel.NORMAL_TABS);
|
||||
menu.findItem(R.id.close_private_tabs).setVisible(mCurrentPanel == Panel.PRIVATE_TABS);
|
||||
|
||||
|
||||
mPopupMenu.show();
|
||||
}
|
||||
});
|
||||
|
@ -1073,6 +1073,35 @@ org.mozilla.crashes.crashes
|
||||
|
||||
This measurement contains a historical record of application crashes.
|
||||
|
||||
Version 4
|
||||
^^^^^^^^^
|
||||
|
||||
This version follows up from version 3, adding submissions which are now
|
||||
tracked by the :ref:`crashes_crashmanager`.
|
||||
|
||||
This measurement will be reported on each day there was a crash or crash
|
||||
submission. Records may contain the following fields, whose values indicate
|
||||
the number of crashes, hangs, or submissions that occurred on the given day:
|
||||
|
||||
* main-crash
|
||||
* main-crash-submission-succeeded
|
||||
* main-crash-submission-failed
|
||||
* main-hang
|
||||
* main-hang-submission-succeeded
|
||||
* main-hang-submission-failed
|
||||
* content-crash
|
||||
* content-crash-submission-succeeded
|
||||
* content-crash-submission-failed
|
||||
* content-hang
|
||||
* content-hang-submission-succeeded
|
||||
* content-hang-submission-failed
|
||||
* plugin-crash
|
||||
* plugin-crash-submission-succeeded
|
||||
* plugin-crash-submission-failed
|
||||
* plugin-hang
|
||||
* plugin-hang-submission-succeeded
|
||||
* plugin-hang-submission-failed
|
||||
|
||||
Version 3
|
||||
^^^^^^^^^
|
||||
|
||||
@ -1152,6 +1181,14 @@ Example
|
||||
"_v": 2,
|
||||
"mainCrash": 2
|
||||
}
|
||||
"org.mozilla.crashes.crashes": {
|
||||
"_v": 4,
|
||||
"main-crash": 2,
|
||||
"main-crash-submission-succeeded": 1,
|
||||
"main-crash-submission-failed": 1,
|
||||
"main-hang": 1,
|
||||
"plugin-crash": 2
|
||||
}
|
||||
|
||||
org.mozilla.healthreport.submissions
|
||||
------------------------------------
|
||||
|
@ -1047,6 +1047,38 @@ DailyCrashesMeasurement3.prototype = Object.freeze({
|
||||
},
|
||||
});
|
||||
|
||||
function DailyCrashesMeasurement4() {
|
||||
Metrics.Measurement.call(this);
|
||||
}
|
||||
|
||||
DailyCrashesMeasurement4.prototype = Object.freeze({
|
||||
__proto__: Metrics.Measurement.prototype,
|
||||
|
||||
name: "crashes",
|
||||
version: 4,
|
||||
|
||||
fields: {
|
||||
"main-crash": DAILY_LAST_NUMERIC_FIELD,
|
||||
"main-crash-submission-succeeded": DAILY_LAST_NUMERIC_FIELD,
|
||||
"main-crash-submission-failed": DAILY_LAST_NUMERIC_FIELD,
|
||||
"main-hang": DAILY_LAST_NUMERIC_FIELD,
|
||||
"main-hang-submission-succeeded": DAILY_LAST_NUMERIC_FIELD,
|
||||
"main-hang-submission-failed": DAILY_LAST_NUMERIC_FIELD,
|
||||
"content-crash": DAILY_LAST_NUMERIC_FIELD,
|
||||
"content-crash-submission-succeeded": DAILY_LAST_NUMERIC_FIELD,
|
||||
"content-crash-submission-failed": DAILY_LAST_NUMERIC_FIELD,
|
||||
"content-hang": DAILY_LAST_NUMERIC_FIELD,
|
||||
"content-hang-submission-succeeded": DAILY_LAST_NUMERIC_FIELD,
|
||||
"content-hang-submission-failed": DAILY_LAST_NUMERIC_FIELD,
|
||||
"plugin-crash": DAILY_LAST_NUMERIC_FIELD,
|
||||
"plugin-crash-submission-succeeded": DAILY_LAST_NUMERIC_FIELD,
|
||||
"plugin-crash-submission-failed": DAILY_LAST_NUMERIC_FIELD,
|
||||
"plugin-hang": DAILY_LAST_NUMERIC_FIELD,
|
||||
"plugin-hang-submission-succeeded": DAILY_LAST_NUMERIC_FIELD,
|
||||
"plugin-hang-submission-failed": DAILY_LAST_NUMERIC_FIELD,
|
||||
},
|
||||
});
|
||||
|
||||
this.CrashesProvider = function () {
|
||||
Metrics.Provider.call(this);
|
||||
|
||||
@ -1063,6 +1095,7 @@ CrashesProvider.prototype = Object.freeze({
|
||||
DailyCrashesMeasurement1,
|
||||
DailyCrashesMeasurement2,
|
||||
DailyCrashesMeasurement3,
|
||||
DailyCrashesMeasurement4,
|
||||
],
|
||||
|
||||
pullOnly: true,
|
||||
@ -1075,8 +1108,8 @@ CrashesProvider.prototype = Object.freeze({
|
||||
this._log.info("Grabbing crash counts from crash manager.");
|
||||
let crashCounts = yield this._manager.getCrashCountsByDay();
|
||||
|
||||
let m = this.getMeasurement("crashes", 3);
|
||||
let fields = DailyCrashesMeasurement3.prototype.fields;
|
||||
let m = this.getMeasurement("crashes", 4);
|
||||
let fields = DailyCrashesMeasurement4.prototype.fields;
|
||||
|
||||
for (let [day, types] of crashCounts) {
|
||||
let date = Metrics.daysToDate(day);
|
||||
|
@ -50,9 +50,17 @@ add_task(function* test_collect() {
|
||||
yield manager.addCrash(manager.PROCESS_TYPE_MAIN,
|
||||
manager.CRASH_TYPE_CRASH,
|
||||
"mc1", day1);
|
||||
yield manager.addSubmission(manager.PROCESS_TYPE_MAIN,
|
||||
manager.CRASH_TYPE_CRASH,
|
||||
true,
|
||||
"mc1", day1)
|
||||
yield manager.addCrash(manager.PROCESS_TYPE_MAIN,
|
||||
manager.CRASH_TYPE_CRASH,
|
||||
"mc2", day1);
|
||||
yield manager.addSubmission(manager.PROCESS_TYPE_MAIN,
|
||||
manager.CRASH_TYPE_CRASH,
|
||||
false,
|
||||
"mc2", day1)
|
||||
yield manager.addCrash(manager.PROCESS_TYPE_CONTENT,
|
||||
manager.CRASH_TYPE_HANG,
|
||||
"ch", day1);
|
||||
@ -66,13 +74,17 @@ add_task(function* test_collect() {
|
||||
yield manager.addCrash(manager.PROCESS_TYPE_CONTENT,
|
||||
manager.CRASH_TYPE_CRASH,
|
||||
"cc", day2);
|
||||
yield manager.addSubmission(manager.PROCESS_TYPE_CONTENT,
|
||||
manager.CRASH_TYPE_CRASH,
|
||||
true,
|
||||
"cc", day2)
|
||||
yield manager.addCrash(manager.PROCESS_TYPE_PLUGIN,
|
||||
manager.CRASH_TYPE_HANG,
|
||||
"ph", day2);
|
||||
|
||||
yield provider.collectDailyData();
|
||||
|
||||
let m = provider.getMeasurement("crashes", 3);
|
||||
let m = provider.getMeasurement("crashes", 4);
|
||||
let values = yield m.getValues();
|
||||
do_check_eq(values.days.size, 2);
|
||||
do_check_true(values.days.hasDay(day1));
|
||||
@ -81,6 +93,10 @@ add_task(function* test_collect() {
|
||||
let value = values.days.getDay(day1);
|
||||
do_check_true(value.has("main-crash"));
|
||||
do_check_eq(value.get("main-crash"), 2);
|
||||
do_check_true(value.has("main-crash-submission-succeeded"));
|
||||
do_check_eq(value.get("main-crash-submission-succeeded"), 1);
|
||||
do_check_true(value.has("main-crash-submission-failed"));
|
||||
do_check_eq(value.get("main-crash-submission-failed"), 1);
|
||||
do_check_true(value.has("content-hang"));
|
||||
do_check_eq(value.get("content-hang"), 1);
|
||||
do_check_true(value.has("plugin-crash"));
|
||||
@ -91,6 +107,8 @@ add_task(function* test_collect() {
|
||||
do_check_eq(value.get("main-hang"), 1);
|
||||
do_check_true(value.has("content-crash"));
|
||||
do_check_eq(value.get("content-crash"), 1);
|
||||
do_check_true(value.has("content-crash-submission-succeeded"));
|
||||
do_check_eq(value.get("content-crash-submission-succeeded"), 1);
|
||||
do_check_true(value.has("plugin-hang"));
|
||||
do_check_eq(value.get("plugin-hang"), 1);
|
||||
|
||||
|
@ -130,12 +130,21 @@ this.CrashManager.prototype = Object.freeze({
|
||||
// A crash in a plugin process.
|
||||
PROCESS_TYPE_PLUGIN: "plugin",
|
||||
|
||||
// A submission of a crash.
|
||||
PROCESS_TYPE_SUBMISSION: "submission",
|
||||
|
||||
// A real crash.
|
||||
CRASH_TYPE_CRASH: "crash",
|
||||
|
||||
// A hang.
|
||||
CRASH_TYPE_HANG: "hang",
|
||||
|
||||
// A successful submission.
|
||||
SUBMISSION_TYPE_SUCCEEDED: "succeeded",
|
||||
|
||||
// A failed submission.
|
||||
SUBMISSION_TYPE_FAILED: "failed",
|
||||
|
||||
DUMP_REGEX: /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.dmp$/i,
|
||||
SUBMITTED_REGEX: /^bp-(?:hr-)?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.txt$/i,
|
||||
ALL_REGEX: /^(.*)$/,
|
||||
@ -360,6 +369,38 @@ this.CrashManager.prototype = Object.freeze({
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Record the occurrence of a crash submission.
|
||||
*
|
||||
* @param processType (string) One of the PROCESS_TYPE constants.
|
||||
* @param crashType (string) One of the CRASH_TYPE constants.
|
||||
* @param succeeded (boolean) Whether the submission succeeded.
|
||||
* @param id (string) Crash ID. Likely a UUID.
|
||||
* @param date (Date) When the crash occurred.
|
||||
*
|
||||
* @return boolean True if the crash submission was recorded and false if not.
|
||||
*/
|
||||
addSubmission: function (processType, crashType, succeeded, id, date) {
|
||||
return Task.spawn(function* () {
|
||||
let store = yield this._getStore();
|
||||
if (this._addSubmissionAsCrash(store, processType, crashType, succeeded,
|
||||
id, date)) {
|
||||
yield store.save();
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_addSubmissionAsCrash: function (store, processType, crashType, succeeded,
|
||||
id, date) {
|
||||
let id = id + "-" + this.PROCESS_TYPE_SUBMISSION;
|
||||
let process = processType + "-" + crashType + "-" +
|
||||
this.PROCESS_TYPE_SUBMISSION;
|
||||
let submission_type = (
|
||||
succeeded ? this.SUBMISSION_TYPE_SUCCEEDED : this.SUBMISSION_TYPE_FAILED);
|
||||
|
||||
return store.addCrash(process, submission_type, id, date);
|
||||
},
|
||||
|
||||
/**
|
||||
* Obtain the paths of all unprocessed events files.
|
||||
*
|
||||
@ -425,27 +466,35 @@ this.CrashManager.prototype = Object.freeze({
|
||||
// The payload types and formats are documented in docs/crash-events.rst.
|
||||
// Do not change the format of an existing type. Instead, invent a new
|
||||
// type.
|
||||
// DO NOT ADD NEW TYPES WITHOUT DOCUMENTING!
|
||||
let lines = payload.split("\n");
|
||||
|
||||
// type in event file => [processType, crashType]
|
||||
let eventMap = {
|
||||
"crash.main.1": ["main", "crash"],
|
||||
};
|
||||
switch (type) {
|
||||
case "crash.main.1":
|
||||
if (lines.length > 1) {
|
||||
this._log.warn("Multiple lines unexpected in payload for " +
|
||||
entry.path);
|
||||
return this.EVENT_FILE_ERROR_MALFORMED;
|
||||
}
|
||||
store.addCrash(this.PROCESS_TYPE_MAIN, this.CRASH_TYPE_CRASH,
|
||||
payload, date);
|
||||
break;
|
||||
|
||||
if (type in eventMap) {
|
||||
let lines = payload.split("\n");
|
||||
if (lines.length > 1) {
|
||||
this._log.warn("Multiple lines unexpected in payload for " +
|
||||
entry.path);
|
||||
return this.EVENT_FILE_ERROR_MALFORMED;
|
||||
}
|
||||
case "crash.submission.1":
|
||||
if (lines.length == 3) {
|
||||
this._addSubmissionAsCrash(store, this.PROCESS_TYPE_MAIN,
|
||||
this.CRASH_TYPE_CRASH,
|
||||
lines[1] === "true", lines[0], date);
|
||||
} else {
|
||||
return this.EVENT_FILE_ERROR_MALFORMED;
|
||||
}
|
||||
break;
|
||||
|
||||
store.addCrash(...eventMap[type], payload, date);
|
||||
return this.EVENT_FILE_SUCCESS;
|
||||
default:
|
||||
return this.EVENT_FILE_ERROR_UNKNOWN_EVENT;
|
||||
}
|
||||
|
||||
// DO NOT ADD NEW TYPES WITHOUT DOCUMENTING!
|
||||
|
||||
return this.EVENT_FILE_ERROR_UNKNOWN_EVENT;
|
||||
return this.EVENT_FILE_SUCCESS;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -74,6 +74,18 @@ The payload of this event is the string crash ID, very likely a UUID.
|
||||
There should be ``UUID.dmp`` and ``UUID.extra`` files on disk, saved by
|
||||
Breakpad.
|
||||
|
||||
crash.submission.1
|
||||
^^^^^^^^^^^^
|
||||
|
||||
This event is produced when a crash is submitted.
|
||||
|
||||
The payload of this event is delimited by UNIX newlines (*\n*) and contains the
|
||||
following fields:
|
||||
|
||||
* The crash ID string
|
||||
* "true" if the submission succeeded or "false" otherwise
|
||||
* The remote crash ID string if the submission succeeded
|
||||
|
||||
Aggregated Event Log
|
||||
====================
|
||||
|
||||
|
@ -304,3 +304,42 @@ add_task(function* test_addCrash() {
|
||||
Assert.equal(crash.type, m.PROCESS_TYPE_PLUGIN + "-" + m.CRASH_TYPE_HANG);
|
||||
Assert.ok(crash.isOfType(m.PROCESS_TYPE_PLUGIN, m.CRASH_TYPE_HANG));
|
||||
});
|
||||
|
||||
add_task(function* test_addSubmission() {
|
||||
let m = yield getManager();
|
||||
|
||||
let crashes = yield m.getCrashes();
|
||||
Assert.equal(crashes.length, 0);
|
||||
|
||||
yield m.addSubmission(m.PROCESS_TYPE_MAIN, m.CRASH_TYPE_CRASH, true,
|
||||
"success", DUMMY_DATE);
|
||||
yield m.addSubmission(m.PROCESS_TYPE_MAIN, m.CRASH_TYPE_CRASH, false,
|
||||
"failure", DUMMY_DATE);
|
||||
|
||||
crashes = yield m.getCrashes();
|
||||
Assert.equal(crashes.length, 2);
|
||||
|
||||
let map = new Map(crashes.map(crash => [crash.id, crash]));
|
||||
|
||||
let crash = map.get("success-submission");
|
||||
Assert.ok(!!crash);
|
||||
Assert.equal(crash.crashDate, DUMMY_DATE);
|
||||
Assert.equal(crash.type,
|
||||
m.PROCESS_TYPE_MAIN + "-" + m.CRASH_TYPE_CRASH + "-" +
|
||||
m.PROCESS_TYPE_SUBMISSION + "-" + m.SUBMISSION_TYPE_SUCCEEDED);
|
||||
Assert.ok(
|
||||
crash.isOfType(m.PROCESS_TYPE_MAIN + "-" + m.CRASH_TYPE_CRASH + "-" +
|
||||
m.PROCESS_TYPE_SUBMISSION, m.SUBMISSION_TYPE_SUCCEEDED));
|
||||
|
||||
let crash = map.get("failure-submission");
|
||||
Assert.ok(!!crash);
|
||||
Assert.equal(crash.crashDate, DUMMY_DATE);
|
||||
Assert.equal(crash.type,
|
||||
m.PROCESS_TYPE_MAIN + "-" + m.CRASH_TYPE_CRASH + "-" +
|
||||
m.PROCESS_TYPE_SUBMISSION + "-" + m.SUBMISSION_TYPE_FAILED);
|
||||
Assert.ok(
|
||||
crash.isOfType(m.PROCESS_TYPE_MAIN + "-" + m.CRASH_TYPE_CRASH + "-" +
|
||||
m.PROCESS_TYPE_SUBMISSION, m.SUBMISSION_TYPE_FAILED));
|
||||
|
||||
});
|
||||
|
||||
|
@ -17,8 +17,11 @@ const {
|
||||
PROCESS_TYPE_MAIN,
|
||||
PROCESS_TYPE_CONTENT,
|
||||
PROCESS_TYPE_PLUGIN,
|
||||
PROCESS_TYPE_SUBMISSION,
|
||||
CRASH_TYPE_CRASH,
|
||||
CRASH_TYPE_HANG,
|
||||
SUBMISSION_TYPE_SUCCEEDED,
|
||||
SUBMISSION_TYPE_FAILED,
|
||||
} = CrashManager.prototype;
|
||||
|
||||
const CrashStore = bsp.CrashStore;
|
||||
@ -273,6 +276,44 @@ add_task(function* test_add_plugin_hang() {
|
||||
Assert.equal(crashes.length, 2);
|
||||
});
|
||||
|
||||
add_task(function* test_add_submission() {
|
||||
let s = yield getStore();
|
||||
|
||||
Assert.ok(
|
||||
s.addCrash(PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_CRASH + "-" +
|
||||
PROCESS_TYPE_SUBMISSION, SUBMISSION_TYPE_SUCCEEDED,
|
||||
"id1", new Date())
|
||||
);
|
||||
Assert.equal(s.crashesCount, 1);
|
||||
|
||||
let c = s.crashes[0];
|
||||
Assert.ok(c.crashDate);
|
||||
Assert.equal(c.type, PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_CRASH + "-" +
|
||||
PROCESS_TYPE_SUBMISSION + "-" + SUBMISSION_TYPE_SUCCEEDED);
|
||||
Assert.ok(c.isOfType(PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_CRASH + "-" +
|
||||
PROCESS_TYPE_SUBMISSION, SUBMISSION_TYPE_SUCCEEDED));
|
||||
|
||||
Assert.ok(
|
||||
s.addCrash(PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_CRASH + "-" +
|
||||
PROCESS_TYPE_SUBMISSION, SUBMISSION_TYPE_FAILED,
|
||||
"id2", new Date())
|
||||
);
|
||||
Assert.equal(s.crashesCount, 2);
|
||||
|
||||
// Duplicate.
|
||||
Assert.ok(
|
||||
s.addCrash(PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_CRASH + "-" +
|
||||
PROCESS_TYPE_SUBMISSION, SUBMISSION_TYPE_SUCCEEDED,
|
||||
"id1", new Date())
|
||||
);
|
||||
Assert.equal(s.crashesCount, 2);
|
||||
|
||||
let crashes = s.getCrashesOfType(PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_CRASH +
|
||||
"-" + PROCESS_TYPE_SUBMISSION,
|
||||
SUBMISSION_TYPE_SUCCEEDED);
|
||||
Assert.equal(crashes.length, 1);
|
||||
});
|
||||
|
||||
add_task(function* test_add_mixed_types() {
|
||||
let s = yield getStore();
|
||||
|
||||
|
@ -32,9 +32,12 @@ namespace CrashReporter {
|
||||
|
||||
StringTable gStrings;
|
||||
string gSettingsPath;
|
||||
string gEventsPath;
|
||||
int gArgc;
|
||||
char** gArgv;
|
||||
|
||||
enum SubmissionResult {Succeeded, Failed};
|
||||
|
||||
static auto_ptr<ofstream> gLogStream(nullptr);
|
||||
static string gReporterDumpFile;
|
||||
static string gExtraFile;
|
||||
@ -172,6 +175,53 @@ bool WriteStringsToFile(const string& path,
|
||||
return success;
|
||||
}
|
||||
|
||||
static string Basename(const string& file)
|
||||
{
|
||||
string::size_type slashIndex = file.rfind(UI_DIR_SEPARATOR);
|
||||
if (slashIndex != string::npos)
|
||||
return file.substr(slashIndex + 1);
|
||||
else
|
||||
return file;
|
||||
}
|
||||
|
||||
static string GetDumpLocalID()
|
||||
{
|
||||
string localId = Basename(gReporterDumpFile);
|
||||
string::size_type dot = localId.rfind('.');
|
||||
|
||||
if (dot == string::npos)
|
||||
return "";
|
||||
|
||||
return localId.substr(0, dot);
|
||||
}
|
||||
|
||||
static void WriteSubmissionEvent(SubmissionResult result,
|
||||
const string& remoteId)
|
||||
{
|
||||
if (gEventsPath.empty()) {
|
||||
// If there is no path for writing the submission event, skip it.
|
||||
return;
|
||||
}
|
||||
|
||||
string localId = GetDumpLocalID();
|
||||
string fpath = gEventsPath + UI_DIR_SEPARATOR + localId + "-submission";
|
||||
ofstream* f = UIOpenWrite(fpath.c_str());
|
||||
time_t tm;
|
||||
time(&tm);
|
||||
|
||||
if (f->is_open()) {
|
||||
*f << "crash.submission.1\n";
|
||||
*f << tm << "\n";
|
||||
*f << localId << "\n";
|
||||
*f << (result == Succeeded ? "true" : "false") << "\n";
|
||||
*f << remoteId;
|
||||
|
||||
f->close();
|
||||
}
|
||||
|
||||
delete f;
|
||||
}
|
||||
|
||||
void LogMessage(const std::string& message)
|
||||
{
|
||||
if (gLogStream.get()) {
|
||||
@ -218,15 +268,6 @@ static string GetExtraDataFilename(const string& dumpfile)
|
||||
return filename;
|
||||
}
|
||||
|
||||
static string Basename(const string& file)
|
||||
{
|
||||
int slashIndex = file.rfind(UI_DIR_SEPARATOR);
|
||||
if (slashIndex >= 0)
|
||||
return file.substr(slashIndex + 1);
|
||||
else
|
||||
return file;
|
||||
}
|
||||
|
||||
static bool MoveCrashData(const string& toDir,
|
||||
string& dumpfile,
|
||||
string& extrafile)
|
||||
@ -316,6 +357,7 @@ static bool AddSubmittedReport(const string& serverResponse)
|
||||
file->close();
|
||||
delete file;
|
||||
|
||||
WriteSubmissionEvent(Succeeded, responseItems["CrashID"]);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -343,7 +385,10 @@ void SendCompleted(bool success, const string& serverResponse)
|
||||
return;
|
||||
directory.resize(slashpos);
|
||||
UIPruneSavedDumps(directory);
|
||||
WriteSubmissionEvent(Failed, "");
|
||||
}
|
||||
} else {
|
||||
WriteSubmissionEvent(Failed, "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,6 +559,23 @@ int main(int argc, char** argv)
|
||||
|
||||
OpenLogFile();
|
||||
|
||||
#ifdef XP_WIN32
|
||||
static const wchar_t kEventsDirKey[] = L"MOZ_CRASHREPORTER_EVENTS_DIRECTORY";
|
||||
const wchar_t *eventsPath = _wgetenv(kEventsDirKey);
|
||||
if (eventsPath && *eventsPath) {
|
||||
gEventsPath = WideToUTF8(eventsPath);
|
||||
}
|
||||
#else
|
||||
static const char kEventsDirKey[] = "MOZ_CRASHREPORTER_EVENTS_DIRECTORY";
|
||||
const char *eventsPath = getenv(kEventsDirKey);
|
||||
if (eventsPath && *eventsPath) {
|
||||
gEventsPath = eventsPath;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
gEventsPath.clear();
|
||||
}
|
||||
|
||||
if (!UIFileExists(gReporterDumpFile)) {
|
||||
UIError(gStrings[ST_ERROR_DUMPFILEEXISTS]);
|
||||
return 0;
|
||||
|
@ -82,6 +82,7 @@ typedef std::map<std::string, std::string> StringTable;
|
||||
namespace CrashReporter {
|
||||
extern StringTable gStrings;
|
||||
extern std::string gSettingsPath;
|
||||
extern std::string gEventsPath;
|
||||
extern int gArgc;
|
||||
extern char** gArgv;
|
||||
|
||||
|
@ -163,6 +163,7 @@ static XP_CHAR* crashReporterPath;
|
||||
|
||||
// Where crash events should go.
|
||||
static XP_CHAR* eventsDirectory;
|
||||
static char* eventsEnv = nullptr;
|
||||
|
||||
// If this is false, we don't launch the crash reporter
|
||||
static bool doReport = true;
|
||||
@ -2107,10 +2108,29 @@ SetCrashEventsDir(nsIFile* aDir)
|
||||
nsString path;
|
||||
eventsDir->GetPath(path);
|
||||
eventsDirectory = reinterpret_cast<wchar_t*>(ToNewUnicode(path));
|
||||
|
||||
// Save the path in the environment for the crash reporter application.
|
||||
nsAutoString eventsDirEnv(NS_LITERAL_STRING("MOZ_CRASHREPORTER_EVENTS_DIRECTORY="));
|
||||
eventsDirEnv.Append(path);
|
||||
_wputenv(eventsDirEnv.get());
|
||||
#else
|
||||
nsCString path;
|
||||
eventsDir->GetNativePath(path);
|
||||
eventsDirectory = ToNewCString(path);
|
||||
|
||||
// Save the path in the environment for the crash reporter application.
|
||||
nsAutoCString eventsDirEnv("MOZ_CRASHREPORTER_EVENTS_DIRECTORY=");
|
||||
eventsDirEnv.Append(path);
|
||||
|
||||
// PR_SetEnv() wants the string to be available for the lifetime
|
||||
// of the app, so dup it here.
|
||||
char* oldEventsEnv = eventsEnv;
|
||||
eventsEnv = ToNewCString(eventsDirEnv);
|
||||
PR_SetEnv(eventsEnv);
|
||||
|
||||
if (oldEventsEnv) {
|
||||
NS_Free(oldEventsEnv);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
<script type="application/javascript"
|
||||
src="utils.js"/>
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
|
@ -353,6 +353,7 @@ notification > button > .button-box > .button-text {
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.close-icon > .button-icon,
|
||||
.close-icon > .button-box > .button-icon,
|
||||
.close-icon > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
* the code you put here can be evaluated by both! */
|
||||
|
||||
Cu.import("resource://webapprt/modules/WebappRT.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
// When WebappsHandler opens an install confirmation dialog for apps we install,
|
||||
// close it, which will be seen as the equivalent of cancelling the install.
|
||||
@ -42,7 +43,7 @@ Services.ww.registerNotification({
|
||||
* The callback to call once the transmogrification is complete.
|
||||
*/
|
||||
function becomeWebapp(manifestURL, parameters, onBecome) {
|
||||
function observeInstall(subj, topic, data) {
|
||||
let observeInstall = Task.async(function*(subj, topic, data) {
|
||||
Services.obs.removeObserver(observeInstall, "webapps-ask-install");
|
||||
|
||||
// Step 2: Configure the runtime session to represent the app.
|
||||
@ -52,7 +53,7 @@ function becomeWebapp(manifestURL, parameters, onBecome) {
|
||||
let scope = {};
|
||||
Cu.import("resource://gre/modules/Webapps.jsm", scope);
|
||||
Cu.import("resource://webapprt/modules/Startup.jsm", scope);
|
||||
scope.DOMApplicationRegistry.confirmInstall(JSON.parse(data));
|
||||
yield scope.DOMApplicationRegistry.confirmInstall(JSON.parse(data));
|
||||
|
||||
let installRecord = JSON.parse(data);
|
||||
installRecord.mm = subj;
|
||||
@ -68,20 +69,20 @@ function becomeWebapp(manifestURL, parameters, onBecome) {
|
||||
null);
|
||||
}
|
||||
|
||||
let promise = scope.startup(win);
|
||||
|
||||
// During chrome tests, we use the same window to load all the tests. We
|
||||
// need to change the buildID so that the permissions for the currently
|
||||
// tested application get installed.
|
||||
Services.prefs.setCharPref("webapprt.buildID", WebappRT.config.app.manifestURL);
|
||||
|
||||
// During tests, the webapps registry is already loaded.
|
||||
// The Startup module needs to be notified when the webapps registry
|
||||
// gets loaded, so we do that now.
|
||||
// During tests, the webapps registry is already loaded,
|
||||
// but SystemMessageInternal expects to be notified when the registry
|
||||
// start and then when it's ready, so we do that now.
|
||||
Services.obs.notifyObservers(this, "webapps-registry-start", null);
|
||||
Services.obs.notifyObservers(this, "webapps-registry-ready", null);
|
||||
|
||||
promise.then(onBecome);
|
||||
}
|
||||
yield scope.startup(win);
|
||||
onBecome();
|
||||
});
|
||||
Services.obs.addObserver(observeInstall, "webapps-ask-install", false);
|
||||
|
||||
// Step 1: Install the app at the URL specified by the manifest.
|
||||
|
@ -6,7 +6,8 @@
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<window windowtype="webapprt:mochitest"
|
||||
<window id="browserTestHarness"
|
||||
windowtype="webapprt:mochitest"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript" src="chrome://webapprt/content/mochitest.js"/>
|
||||
|
Loading…
Reference in New Issue
Block a user