merge fx-team to mozilla-central a=merge

--HG--
extra : amend_source : 6b1927dd9d7d8eedfc694b66e8aceb7c3fc24935
This commit is contained in:
Carsten "Tomcat" Book 2014-07-02 15:00:10 +02:00
Родитель aa323b03a4 e5625c5dae
Коммит 8248ac6196
38 изменённых файлов: 785 добавлений и 160 удалений

Просмотреть файл

@ -782,7 +782,7 @@ let CustomizableUIInternal = {
}
if (!widgetNode || !container.contains(widgetNode)) {
INFO("Widget not found, unable to remove");
INFO("Widget " + aWidgetId + " not found, unable to remove from " + aArea);
continue;
}

Просмотреть файл

@ -5,6 +5,7 @@ support-files =
doc_simple-canvas-bitmasks.html
doc_simple-canvas-deep-stack.html
doc_simple-canvas-transparent.html
doc_webgl-enum.html
head.js
[browser_canvas-actor-test-01.js]
@ -15,6 +16,7 @@ support-files =
[browser_canvas-actor-test-06.js]
[browser_canvas-actor-test-07.js]
[browser_canvas-actor-test-08.js]
[browser_canvas-actor-test-09.js]
[browser_canvas-frontend-call-highlight.js]
[browser_canvas-frontend-call-list.js]
[browser_canvas-frontend-call-search.js]

Просмотреть файл

@ -0,0 +1,31 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that integers used in arguments are not cast to their constant, enum value
* forms if the method's signature does not expect an enum. Bug 999687.
*/
function ifTestingSupported() {
let [target, debuggee, front] = yield initCanavsDebuggerBackend(WEBGL_ENUM_URL);
let navigated = once(target, "navigate");
yield front.setup({ reload: true });
ok(true, "The front was setup up successfully.");
yield navigated;
ok(true, "Target automatically navigated when the front was set up.");
let snapshotActor = yield front.recordAnimationFrame();
let animationOverview = yield snapshotActor.getOverview();
let functionCalls = animationOverview.calls;
is(functionCalls[0].name, "clear",
"The function's name is correct.");
is(functionCalls[0].argsPreview, "DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT",
"The bits passed into `gl.clear` have been cast to their enum values.");
yield removeTab(target.tab);
finish();
}

Просмотреть файл

@ -0,0 +1,33 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>WebGL editor test page</title>
</head>
<body>
<canvas id="canvas" width="128" height="128"></canvas>
<script type="text/javascript;version=1.8">
"use strict";
let canvas, gl;
window.onload = function() {
canvas = document.querySelector("canvas");
gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
gl.clearColor(0.0, 0.0, 0.0, 1.0);
drawScene();
}
function drawScene() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
window.requestAnimationFrame(drawScene);
}
</script>
</body>
</html>

Просмотреть файл

@ -29,6 +29,7 @@ const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html";
const SIMPLE_BITMASKS_URL = EXAMPLE_URL + "doc_simple-canvas-bitmasks.html";
const SIMPLE_CANVAS_TRANSPARENT_URL = EXAMPLE_URL + "doc_simple-canvas-transparent.html";
const SIMPLE_CANVAS_DEEP_STACK_URL = EXAMPLE_URL + "doc_simple-canvas-deep-stack.html";
const WEBGL_ENUM_URL = EXAMPLE_URL + "doc_webgl-enum.html";
// All tests are asynchronous.
waitForExplicitFinish();

Просмотреть файл

@ -398,6 +398,8 @@ HTMLBreadcrumbs.prototype = {
this.separators = null;
this.nodeHierarchy = null;
this.isDestroyed = true;
},
/**
@ -625,6 +627,10 @@ HTMLBreadcrumbs.prototype = {
updateSelectors: function BC_updateSelectors()
{
if (this.isDestroyed) {
return;
}
for (let i = this.nodeHierarchy.length - 1; i >= 0; i--) {
let crumb = this.nodeHierarchy[i];
let button = crumb.button;
@ -642,6 +648,10 @@ HTMLBreadcrumbs.prototype = {
*/
update: function BC_update(reason)
{
if (this.isDestroyed) {
return;
}
if (reason !== "markupmutation") {
this.inspector.hideNodeMenu();
}
@ -688,6 +698,10 @@ HTMLBreadcrumbs.prototype = {
let doneUpdating = this.inspector.updating("breadcrumbs");
// Add the first child of the very last node of the breadcrumbs if possible.
this.ensureFirstChild().then(this.selectionGuard()).then(() => {
if (this.isDestroyed) {
return;
}
this.updateSelectors();
// Make sure the selected node and its neighbours are visible.

Просмотреть файл

@ -1,78 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
"use strict";
let DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
// Test that the inspector has the correct pseudo-class locking menu items and
// that these items actually work
let pseudos = ["hover", "active", "focus"];
const DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
const PSEUDOS = ["hover", "active", "focus"];
let doc;
let div;
let menu;
let inspector;
let test = asyncTest(function*() {
yield addTab("data:text/html,pseudo-class lock node menu tests");
ignoreAllUncaughtExceptions();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
doc = content.document;
waitForFocus(createDocument, content);
info("Creating the test element");
let div = content.document.createElement("div");
div.textContent = "test div";
content.document.body.appendChild(div);
let {inspector} = yield openInspector();
yield selectNode(div, inspector);
info("Getting the inspector ctx menu and opening it");
let menu = inspector.panelDoc.getElementById("inspector-node-popup");
yield openMenu(menu);
yield testMenuItems(div, menu, inspector);
gBrowser.removeCurrentTab();
});
function openMenu(menu) {
let def = promise.defer();
menu.addEventListener("popupshowing", function onOpen() {
menu.removeEventListener("popupshowing", onOpen, true);
def.resolve();
}, true);
menu.openPopup();
content.location = "data:text/html,pseudo-class lock node menu tests";
return def.promise;
}
function createDocument()
{
div = doc.createElement("div");
div.textContent = "test div";
function* testMenuItems(div,menu, inspector) {
for (let pseudo of PSEUDOS) {
let menuitem = inspector.panelDoc.getElementById("node-menu-pseudo-" + pseudo);
ok(menuitem, ":" + pseudo + " menuitem exists");
doc.body.appendChild(div);
// Give the inspector panels a chance to update when the pseudoclass changes
let onPseudo = inspector.selection.once("pseudoclass");
let onRefresh = inspector.once("rule-view-refreshed");
let onMutations = waitForMutation(inspector);
openInspector(selectNode);
}
menuitem.doCommand();
function selectNode(aInspector)
{
inspector = aInspector;
inspector.selection.setNode(div);
inspector.once("inspector-updated", performTests);
}
yield onPseudo;
yield onRefresh;
yield onMutations;
function performTests()
{
menu = inspector.panelDoc.getElementById("inspector-node-popup");
menu.addEventListener("popupshowing", testMenuItems, true);
menu.openPopup();
}
function testMenuItems()
{
menu.removeEventListener("popupshowing", testMenuItems, true);
var tryNext = () => {
if (pseudos.length === 0) {
finishUp();
return;
}
let pseudo = pseudos.shift();
let menuitem = inspector.panelDoc.getElementById("node-menu-pseudo-" + pseudo);
ok(menuitem, ":" + pseudo + " menuitem exists");
menuitem.doCommand();
inspector.selection.once("pseudoclass", () => {
is(DOMUtils.hasPseudoClassLock(div, ":" + pseudo), true,
"pseudo-class lock has been applied");
tryNext();
});
}
tryNext();
}
function finishUp()
{
gBrowser.removeCurrentTab();
finish();
is(DOMUtils.hasPseudoClassLock(div, ":" + pseudo), true,
"pseudo-class lock has been applied");
}
}
function waitForMutation(inspector) {
let def = promise.defer();
inspector.walker.once("mutations", def.resolve);
return def.promise;
}

Просмотреть файл

@ -16,38 +16,31 @@ const TEST_URL = 'data:text/html,' +
' </div>' +
'</body>';
function test() {
ignoreAllUncaughtExceptions();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
waitForFocus(startTests, content);
}, true);
content.location = TEST_URL;
}
let startTests = Task.async(function*() {
let test = asyncTest(function*() {
info("Creating the test tab and opening the rule-view");
yield addTab(TEST_URL);
let {toolbox, inspector, view} = yield openRuleView();
info("Selecting the test node");
yield selectNode("#div-1", inspector);
yield performTests(inspector, view);
yield finishUp(toolbox);
finish();
});
function* performTests(inspector, ruleview) {
yield togglePseudoClass(inspector);
yield assertPseudoAddedToNode(inspector, ruleview);
yield assertPseudoAddedToNode(inspector, view);
yield togglePseudoClass(inspector);
yield assertPseudoRemovedFromNode();
yield assertPseudoRemovedFromView(inspector, ruleview);
yield assertPseudoRemovedFromView(inspector, view);
yield togglePseudoClass(inspector);
yield testNavigate(inspector, ruleview);
}
yield testNavigate(inspector, view);
info("Destroying the toolbox");
yield toolbox.destroy();
yield assertPseudoRemovedFromNode(getNode("#div-1"));
gBrowser.removeCurrentTab();
});
function* togglePseudoClass(inspector) {
info("Toggle the pseudoclass, wait for it to be applied");
@ -139,12 +132,3 @@ function* assertPseudoRemovedFromView(inspector, ruleview) {
is(pseudoClassesBox.textContent, "", "pseudo-class removed from infobar selector");
yield inspector.toolbox.highlighter.hideBoxModel();
}
function* finishUp(toolbox) {
let onDestroy = gDevTools.once("toolbox-destroyed");
toolbox.destroy();
yield onDestroy;
yield assertPseudoRemovedFromNode(getNode("#div-1"));
gBrowser.removeCurrentTab();
}

Просмотреть файл

@ -218,7 +218,7 @@ SyntaxTreesPool.prototype = {
// Can't guarantee that the tree traversal logic is forever perfect :)
// Language features may be added, in which case the recursive methods
// need to be updated. If an exception is thrown here, file a bug.
DevToolsUtils.reportException("Syntax tree visitor for " + aUrl, e);
DevToolsUtils.reportException("Syntax tree visitor for " + this._url, e);
}
}
this._cache.set(requestId, results);

Просмотреть файл

@ -195,11 +195,13 @@ function Tooltip(doc, options) {
// Listen to keypress events to close the tooltip if configured to do so
let win = this.doc.querySelector("window");
this._onKeyPress = event => {
if (this.panel.hidden) {
return;
}
this.emit("keypress", event.keyCode);
if (this.options.get("closeOnKeys").indexOf(event.keyCode) !== -1) {
if (!this.panel.hidden) {
event.stopPropagation();
}
event.stopPropagation();
this.hide();
}
};

Просмотреть файл

@ -225,7 +225,8 @@ StyleSheetEditor.prototype = {
fetchSource: function(callback) {
return this.styleSheet.getText().then((longStr) => {
longStr.string().then((source) => {
this._state.text = CssLogic.prettifyCSS(source);
let ruleCount = this.styleSheet.ruleCount;
this._state.text = CssLogic.prettifyCSS(source, ruleCount);
this.sourceLoaded = true;
if (callback) {

Просмотреть файл

@ -23,7 +23,7 @@ let editorTestedCount = 0;
function testEditor(aEditor)
{
if (aEditor.styleSheet.styleSheetIndex == 0) {
let prettifiedSource = "body\{\r?\n\tbackground\:white;\r?\n\}\r?\n\r?\ndiv\{\r?\n\tfont\-size\:4em;\r?\n\tcolor\:red\r?\n\}\r?\n";
let prettifiedSource = "body\{\r?\n\tbackground\:white;\r?\n\}\r?\n\r?\ndiv\{\r?\n\tfont\-size\:4em;\r?\n\tcolor\:red\r?\n\}\r?\n\r?\nspan\{\r?\n\tcolor\:green;\r?\n\}\r?\n";
let prettifiedSourceRE = new RegExp(prettifiedSource);
ok(prettifiedSourceRE.test(aEditor.sourceEditor.getText()),

Просмотреть файл

@ -1,5 +1,2 @@
body{background:white;}div{font-size:4em;color:red}
body{background:white;}div{font-size:4em;color:red}span{color:green;}

Просмотреть файл

@ -5,8 +5,6 @@
"use strict";
// Testing various inplace-editor behaviors in the rule-view
// FIXME: To be split in several test files, and some of the inplace-editor
// focus/blur/commit/revert stuff should be factored out in head.js
let TEST_URL = 'url("' + TEST_URL_ROOT + 'doc_test_image.png")';
let PAGE_CONTENT = [
@ -14,11 +12,8 @@ let PAGE_CONTENT = [
' #testid {',
' background-color: blue;',
' }',
' .testclass {',
' background-color: green;',
' }',
'</style>',
'<div id="testid" class="testclass" style="background-color:red;">Styled Node</div>'
'<div id="testid">Styled Node</div>'
].join("\n");
let test = asyncTest(function*() {
@ -33,13 +28,9 @@ let test = asyncTest(function*() {
info("Selecting the test element");
yield selectNode("#testid", inspector);
yield testCreateNewEscape(view);
});
function* testCreateNewEscape(view) {
info("Test creating a new property and escaping");
let elementRuleEditor = getRuleViewRuleEditor(view, 0);
let elementRuleEditor = getRuleViewRuleEditor(view, 1);
info("Focusing a new property name in the rule-view");
let editor = yield focusEditableField(elementRuleEditor.closeBrace);
@ -48,7 +39,9 @@ function* testCreateNewEscape(view) {
let input = editor.input;
info("Entering a value in the property name editor");
let onModifications = elementRuleEditor.rule._applyingModifications;
input.value = "color";
yield onModifications;
info("Pressing return to commit and focus the new value field");
let onValueFocus = once(elementRuleEditor.element, "focus", true);
@ -69,7 +62,9 @@ function* testCreateNewEscape(view) {
editor.input.value = "red";
info("Escaping out of the field");
let onModifications = elementRuleEditor.rule._applyingModifications;
EventUtils.synthesizeKey("VK_ESCAPE", {}, view.doc.defaultView);
yield onModifications;
info("Checking that the previous field is focused");
let focusedElement = inplaceEditor(elementRuleEditor.rule.textProps[0].editor.valueSpan).input;
@ -81,4 +76,4 @@ function* testCreateNewEscape(view) {
is(elementRuleEditor.rule.textProps.length, 1, "Removed the new text property.");
is(elementRuleEditor.propertyList.children.length, 1, "Removed the property editor.");
}
});

Просмотреть файл

@ -5,6 +5,8 @@
* Tests that SVG nodes and edges were created for the Graph View.
*/
let connectCount = 0;
function spawnTest() {
let [target, debuggee, panel] = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
let { panelWin } = panel;
@ -14,6 +16,8 @@ function spawnTest() {
reload(target);
panelWin.on(EVENTS.CONNECT_NODE, onConnectNode);
let [actors] = yield Promise.all([
get3(gFront, "create-node"),
waitForGraphRendered(panelWin, 3, 2)
@ -27,7 +31,16 @@ function spawnTest() {
is(findGraphEdge(panelWin, oscId, gainId).toString(), "[object SVGGElement]", "found edge for osc -> gain");
is(findGraphEdge(panelWin, gainId, destId).toString(), "[object SVGGElement]", "found edge for gain -> dest");
yield wait(1000);
is(connectCount, 2, "Only two node connect events should be fired.");
panelWin.off(EVENTS.CONNECT_NODE, onConnectNode);
yield teardown(panel);
finish();
}
function onConnectNode () {
++connectCount;
}

Просмотреть файл

@ -17,8 +17,15 @@
let osc = ctx.createOscillator();
let gain = ctx.createGain();
gain.gain.value = 0;
// Connect multiple times to test that it's disregarded.
osc.connect(gain);
gain.connect(ctx.destination);
gain.connect(ctx.destination);
gain.connect(ctx.destination);
gain.connect(ctx.destination);
gain.connect(ctx.destination);
gain.connect(ctx.destination);
osc.start(0);
</script>
</body>

Просмотреть файл

@ -94,19 +94,24 @@ AudioNodeView.prototype.getType = Task.async(function* () {
});
// Helper method to create connections in the AudioNodeConnections
// WeakMap for rendering
// WeakMap for rendering. Returns a boolean indicating
// if the connection was successfully created. Will return `false`
// when the connection was previously made.
AudioNodeView.prototype.connect = function (destination) {
let connections = AudioNodeConnections.get(this);
if (!connections) {
connections = [];
AudioNodeConnections.set(this, connections);
let connections = AudioNodeConnections.get(this) || new Set();
AudioNodeConnections.set(this, connections);
// Don't duplicate add.
if (!connections.has(destination)) {
connections.add(destination);
return true;
}
connections.push(destination);
return false;
};
// Helper method to remove audio connections from the current AudioNodeView
AudioNodeView.prototype.disconnect = function () {
AudioNodeConnections.set(this, []);
AudioNodeConnections.set(this, new Set());
};
// Returns a promise that resolves to an array of objects containing
@ -293,8 +298,10 @@ let WebAudioEditorController = {
// adding an edge.
let [source, dest] = yield waitForNodeCreation(sourceActor, destActor);
source.connect(dest);
window.emit(EVENTS.CONNECT_NODE, source.id, dest.id);
// Connect nodes, and only emit if it's a new connection.
if (source.connect(dest)) {
window.emit(EVENTS.CONNECT_NODE, source.id, dest.id);
}
function waitForNodeCreation (sourceActor, destActor) {
let deferred = defer();

Просмотреть файл

@ -161,7 +161,7 @@ let WebAudioGraphView = {
// Add all of the connections from this node to the edge array to be added
// after all the nodes are added, otherwise edges will attempted to be created
// for nodes that have not yet been added
AudioNodeConnections.get(node, []).forEach(dest => edges.push([node, dest]));
AudioNodeConnections.get(node, new Set()).forEach(dest => edges.push([node, dest]));
});
edges.forEach(([node, dest]) => graph.addEdge(null, node.id, dest.id, {

Просмотреть файл

@ -2095,6 +2095,8 @@ public class GeckoAppShell
@WrapElementForJNI(allowMultithread = true)
public static Context getContext() {
if (sContextGetter == null)
return null;
return sContextGetter.getContext();
}

Просмотреть файл

@ -102,6 +102,8 @@ public class GeckoApplication extends Application
}
public void onActivityResume(GeckoActivityStatus activity) {
GeckoAppShell.setContextGetter(this);
if (mPausedGecko) {
GeckoAppShell.sendEventToGecko(GeckoEvent.createAppForegroundingEvent());
mPausedGecko = false;

Просмотреть файл

@ -33,6 +33,9 @@ public class BrowserContract {
public static final String READING_LIST_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.readinglist";
public static final Uri READING_LIST_AUTHORITY_URI = Uri.parse("content://" + READING_LIST_AUTHORITY);
public static final String SEARCH_HISTORY_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.searchhistory";
public static final Uri SEARCH_HISTORY_AUTHORITY_URI = Uri.parse("content://" + SEARCH_HISTORY_AUTHORITY);
public static final String PARAM_PROFILE = "profile";
public static final String PARAM_PROFILE_PATH = "profilePath";
public static final String PARAM_LIMIT = "limit";
@ -433,6 +436,17 @@ public class BrowserContract {
public static final String TYPE = "type";
}
@RobocopTarget
public static final class SearchHistory implements CommonColumns, HistoryColumns {
private SearchHistory() {}
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/searchhistory";
public static final String QUERY = "query";
public static final String TABLE_NAME = "searchhistory";
public static final Uri CONTENT_URI = Uri.withAppendedPath(SEARCH_HISTORY_AUTHORITY_URI, "searchhistory");
}
@RobocopTarget
public static final class SuggestedSites implements CommonColumns, URLColumns {
private SuggestedSites() {}

Просмотреть файл

@ -16,6 +16,7 @@ import org.mozilla.gecko.db.BrowserContract.Favicons;
import org.mozilla.gecko.db.BrowserContract.History;
import org.mozilla.gecko.db.BrowserContract.Obsolete;
import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
import org.mozilla.gecko.db.BrowserContract.Thumbnails;
import org.mozilla.gecko.sync.Utils;
@ -34,7 +35,7 @@ import android.util.Log;
final class BrowserDatabaseHelper extends SQLiteOpenHelper {
private static final String LOGTAG = "GeckoBrowserDBHelper";
public static final int DATABASE_VERSION = 18;
public static final int DATABASE_VERSION = 19;
public static final String DATABASE_NAME = "browser.db";
final protected Context mContext;
@ -749,6 +750,20 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
createOrUpdateAllSpecialFolders(db);
createReadingListTable(db);
createSearchHistoryTable(db);
}
private void createSearchHistoryTable(SQLiteDatabase db) {
debug("Creating " + SearchHistory.TABLE_NAME + " table");
db.execSQL("CREATE TABLE " + SearchHistory.TABLE_NAME + "(" +
SearchHistory._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
SearchHistory.QUERY + " TEXT UNIQUE NOT NULL, " +
SearchHistory.DATE_LAST_VISITED + " INTEGER, " +
SearchHistory.VISITS + " INTEGER ) ");
db.execSQL("CREATE INDEX idx_search_history_last_visited ON " +
SearchHistory.TABLE_NAME + "(" + SearchHistory.DATE_LAST_VISITED + ")");
}
private void createReadingListTable(SQLiteDatabase db) {
@ -1378,6 +1393,10 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
}
}
private void upgradeDatabaseFrom18to19(SQLiteDatabase db) {
createSearchHistoryTable(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
debug("Upgrading browser.db: " + db.getPath() + " from " +
@ -1454,6 +1473,10 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
case 18:
upgradeDatabaseFrom17to18(db);
break;
case 19:
upgradeDatabaseFrom18to19(db);
break;
}
}
@ -1566,4 +1589,4 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
bookmark.remove("folder");
}
}
}
}

Просмотреть файл

@ -0,0 +1,112 @@
/* 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/. */
package org.mozilla.gecko.db;
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;
public class SearchHistoryProvider extends SharedBrowserDatabaseProvider {
/**
* Collapse whitespace.
*/
private String stripWhitespace(String query) {
if (TextUtils.isEmpty(query)) {
return "";
}
// Collapse whitespace
return query.trim().replaceAll("\\s+", " ");
}
@Override
public Uri insertInTransaction(Uri uri, ContentValues cv) {
final String query = stripWhitespace(cv.getAsString(SearchHistory.QUERY));
// We don't support inserting empty search queries.
if (TextUtils.isEmpty(query)) {
return null;
}
final SQLiteDatabase db = getWritableDatabase(uri);
/*
* FIRST: Try incrementing the VISITS counter and updating the DATE_LAST_VISITED.
*/
final String sql = "UPDATE " + SearchHistory.TABLE_NAME + " SET " +
SearchHistory.VISITS + " = " + SearchHistory.VISITS + " + 1, " +
SearchHistory.DATE_LAST_VISITED + " = " + System.currentTimeMillis() +
" WHERE " + SearchHistory.QUERY + " = ?";
final Cursor c = db.rawQuery(sql, new String[] { query });
try {
if (c.getCount() > 1) {
// There is a UNIQUE constraint on the QUERY column,
// so there should only be one match.
return null;
}
if (c.moveToFirst()) {
return ContentUris
.withAppendedId(uri, c.getInt(c.getColumnIndex(SearchHistory._ID)));
}
} finally {
c.close();
}
/*
* SECOND: If the update failed, then insert a new record.
*/
cv.put(SearchHistory.QUERY, query);
cv.put(SearchHistory.VISITS, 1);
cv.put(SearchHistory.DATE_LAST_VISITED, System.currentTimeMillis());
long id = db.insert(SearchHistory.TABLE_NAME, null, cv);
if (id < 0) {
return null;
}
return ContentUris.withAppendedId(uri, id);
}
@Override
public int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
return getWritableDatabase(uri)
.delete(SearchHistory.TABLE_NAME, selection, selectionArgs);
}
/**
* Since we are managing counts and the full-text db, an update
* could mangle the internal state. So we disable it.
*/
@Override
public int updateInTransaction(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
throw new UnsupportedOperationException(
"This content provider does not support updating items");
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
String groupBy = null;
String having = null;
return getReadableDatabase(uri)
.query(SearchHistory.TABLE_NAME, projection, selection, selectionArgs,
groupBy, having, sortOrder);
}
@Override
public String getType(Uri uri) {
return SearchHistory.CONTENT_TYPE;
}
}

Просмотреть файл

@ -150,6 +150,7 @@ gbjar.sources += [
'db/PerProfileDatabaseProvider.java',
'db/PerProfileDatabases.java',
'db/ReadingListProvider.java',
'db/SearchHistoryProvider.java',
'db/SharedBrowserDatabaseProvider.java',
'db/SQLiteBridgeContentProvider.java',
'db/SuggestedSites.java',

Просмотреть файл

@ -122,7 +122,9 @@ public class GeckoPreferenceFragment extends PreferenceFragment {
if (Build.VERSION.SDK_INT >= 14) {
final ActionBar actionBar = activity.getActionBar();
actionBar.setTitle(newTitle);
if (actionBar != null) {
actionBar.setTitle(newTitle);
}
}
}

Просмотреть файл

@ -140,7 +140,9 @@ OnSharedPreferenceChangeListener
Log.v(LOGTAG, "Setting action bar title to " + newTitle);
final ActionBar actionBar = getActionBar();
actionBar.setTitle(newTitle);
if (actionBar != null) {
actionBar.setTitle(newTitle);
}
}
}
}
@ -360,7 +362,9 @@ OnSharedPreferenceChangeListener
if (Build.VERSION.SDK_INT >= 14) {
final ActionBar actionBar = getActionBar();
actionBar.setHomeButtonEnabled(true);
if (actionBar != null) {
actionBar.setHomeButtonEnabled(true);
}
}
// N.B., if we ever need to redisplay the locale selection UI without
@ -977,15 +981,15 @@ OnSharedPreferenceChangeListener
} else if (PREFS_ANNOUNCEMENTS_ENABLED.equals(prefName)) {
// Send a broadcast intent to the product announcements service, either to start or
// to stop the repeated background checks.
broadcastAnnouncementsPref(GeckoAppShell.getContext(), ((Boolean) newValue).booleanValue());
broadcastAnnouncementsPref(this, ((Boolean) newValue).booleanValue());
} else if (PREFS_UPDATER_AUTODOWNLOAD.equals(prefName)) {
org.mozilla.gecko.updater.UpdateServiceHelper.registerForUpdates(GeckoAppShell.getContext(), (String) newValue);
org.mozilla.gecko.updater.UpdateServiceHelper.registerForUpdates(this, (String) newValue);
} else if (PREFS_HEALTHREPORT_UPLOAD_ENABLED.equals(prefName)) {
// The healthreport pref only lives in Android, so we do not persist
// to Gecko, but we do broadcast intent to the health report
// background uploader service, which will start or stop the
// repeated background upload attempts.
broadcastHealthReportUploadPref(GeckoAppShell.getContext(), ((Boolean) newValue).booleanValue());
broadcastHealthReportUploadPref(this, ((Boolean) newValue).booleanValue());
} else if (PREFS_GEO_REPORTING.equals(prefName)) {
// Translate boolean value to int for geo reporting pref.
newValue = ((Boolean) newValue) ? 1 : 0;
@ -1013,7 +1017,7 @@ OnSharedPreferenceChangeListener
}
private EditText getTextBox(int aHintText) {
EditText input = new FloatingHintEditText(GeckoAppShell.getContext());
EditText input = new FloatingHintEditText(this);
int inputtype = InputType.TYPE_CLASS_TEXT;
inputtype |= InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
input.setInputType(inputtype);

Просмотреть файл

@ -27,7 +27,7 @@ public final class WaitHelper {
// assertion from waitFor)?
private static final int DEFAULT_MAX_WAIT_MS = 5000;
private static final int PAGE_LOAD_WAIT_MS = 10000;
private static final int CHANGE_WAIT_MS = 10000;
private static final int CHANGE_WAIT_MS = 15000;
// TODO: via lucasr - Add ThrobberVisibilityChangeVerifier?
private static final ChangeVerifier[] PAGE_LOAD_VERIFIERS = new ChangeVerifier[] {

Просмотреть файл

@ -56,7 +56,7 @@ skip-if = android_version == "10" || processor == "x86"
[testHomeProvider]
[testLoad]
[testMailToContextMenu]
[testMasterPassword]
# [testMasterPassword] disabled for being finicky, see bug 1033013
# disabled on 2.3; bug 979603
# disabled on 4.0; bug 1006242
skip-if = android_version == "10" || android_version == "15"
@ -80,6 +80,7 @@ skip-if = processor == "x86"
skip-if = processor == "x86"
# [testReaderMode] # see bug 913254, 936224
[testReadingListProvider]
[testSearchHistoryProvider]
[testSearchSuggestions]
# disabled on x86; bug 907768
skip-if = processor == "x86"

Просмотреть файл

@ -0,0 +1,269 @@
/* 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/. */
package org.mozilla.gecko.tests;
import java.util.concurrent.Callable;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
import org.mozilla.gecko.db.SearchHistoryProvider;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
public class testSearchHistoryProvider extends ContentProviderTest {
// Translations of "United Kingdom" in several different languages
private static final String[] testStrings = {"An Ríocht Aontaithe", // Irish
"Angli", // Albanian
"Britanniarum Regnum", // Latin
"Britio", // Esperanto
"Büyük Britanya", // Turkish
"Egyesült Királyság", // Hungarian
"Erresuma Batua", // Basque
"Inggris Raya", // Indonesian
"Ir-Renju Unit", // Maltese
"Iso-Britannia", // Finnish
"Jungtinė Karalystė", // Lithuanian
"Lielbritānija", // Latvian
"Regatul Unit", // Romanian
"Regne Unit", // Catalan, Valencian
"Regno Unito", // Italian
"Royaume-Uni", // French
"Spojené království", // Czech
"Spojené kráľovstvo", // Slovak
"Storbritannia", // Norwegian
"Storbritannien", // Danish
"Suurbritannia", // Estonian
"Ujedinjeno Kraljevstvo", // Bosnian
"United Alaeze", // Igbo
"United Kingdom", // English
"Vereinigtes Königreich", // German
"Verenigd Koninkrijk", // Dutch
"Verenigde Koninkryk", // Afrikaans
"Vương quốc Anh", // Vietnamese
"Wayòm Ini", // Haitian, Haitian Creole
"Y Deyrnas Unedig", // Welsh
"Združeno kraljestvo", // Slovene
"Zjednoczone Królestwo", // Polish
"Ηνωμένο Βασίλειο", // Greek (modern)
"Великобритания", // Russian
"Нэгдсэн Вант Улс", // Mongolian
"Обединетото Кралство", // Macedonian
"Уједињено Краљевство", // Serbian
"Միացյալ Թագավորություն", // Armenian
"בריטניה", // Hebrew (modern)
"פֿאַראייניקטע מלכות", // Yiddish
"المملكة المتحدة", // Arabic
"برطانیہ", // Urdu
"پادشاهی متحده", // Persian (Farsi)
"यूनाइटेड किंगडम", // Hindi
"संयुक्त राज्य", // Nepali
"যুক্তরাজ্য", // Bengali, Bangla
"યુનાઇટેડ કિંગડમ", // Gujarati
"ஐக்கிய ராஜ்யம்", // Tamil
"สหราชอาณาจักร", // Thai
"ສະ​ຫະ​ປະ​ຊາ​ຊະ​ອາ​ນາ​ຈັກ", // Lao
"გაერთიანებული სამეფო", // Georgian
"イギリス", // Japanese
"联合王国" // Chinese
};
private static final String DB_NAME = "searchhistory.db";
/**
* Boilerplate alert.
* <p/>
* Make sure this method is present and that it returns a new
* instance of your class.
*/
private static Callable<ContentProvider> sProviderFactory =
new Callable<ContentProvider>() {
@Override
public ContentProvider call() {
return new SearchHistoryProvider();
}
};
@Override
public void setUp() throws Exception {
super.setUp(sProviderFactory, BrowserContract.SEARCH_HISTORY_AUTHORITY, DB_NAME);
mTests.add(new TestInsert());
mTests.add(new TestUnicodeQuery());
mTests.add(new TestTimestamp());
mTests.add(new TestDelete());
mTests.add(new TestIncrement());
}
public void testSearchHistory() throws Exception {
for (Runnable test : mTests) {
String testName = test.getClass().getSimpleName();
setTestName(testName);
mAsserter.dumpLog(
"testBrowserProvider: Database empty - Starting " + testName + ".");
// Clear the db
mProvider.delete(SearchHistory.CONTENT_URI, null, null);
test.run();
}
}
/**
* Verify that we can insert values into the DB, including unicode.
*/
private class TestInsert extends TestCase {
@Override
public void test() throws Exception {
ContentValues cv;
for (int i = 0; i < testStrings.length; i++) {
cv = new ContentValues();
cv.put(SearchHistory.QUERY, testStrings[i]);
mProvider.insert(SearchHistory.CONTENT_URI, cv);
}
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
mAsserter.is(c.getCount(), testStrings.length,
"Should have one row for each insert");
c.close();
}
}
/**
* Verify that we can insert values into the DB, including unicode.
*/
private class TestUnicodeQuery extends TestCase {
@Override
public void test() throws Exception {
ContentValues cv;
Cursor c = null;
String selection = SearchHistory.QUERY + " = ?";
for (int i = 0; i < testStrings.length; i++) {
cv = new ContentValues();
cv.put(SearchHistory.QUERY, testStrings[i]);
mProvider.insert(SearchHistory.CONTENT_URI, cv);
c = mProvider.query(SearchHistory.CONTENT_URI, null, selection,
new String[]{ testStrings[i] }, null);
mAsserter.is(c.getCount(), 1,
"Should have one row for insert of " + testStrings[i]);
}
if (c != null) {
c.close();
}
}
}
/**
* Verify that timestamps are updated on insert.
*/
private class TestTimestamp extends TestCase {
@Override
public void test() throws Exception {
String insertedTerm = "Courtside Seats";
long insertStart;
long insertFinish;
long t1Db;
long t2Db;
ContentValues cv = new ContentValues();
cv.put(SearchHistory.QUERY, insertedTerm);
// First check that the DB has a value that is close to the
// system time.
insertStart = System.currentTimeMillis();
mProvider.insert(SearchHistory.CONTENT_URI, cv);
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
c.moveToFirst();
t1Db = c.getLong(c.getColumnIndex(SearchHistory.DATE_LAST_VISITED));
c.close();
insertFinish = System.currentTimeMillis();
mAsserter.ok(t1Db >= insertStart, "DATE_LAST_VISITED",
"Date last visited should be set on insert.");
mAsserter.ok(t1Db <= insertFinish, "DATE_LAST_VISITED",
"Date last visited should be set on insert.");
cv = new ContentValues();
cv.put(SearchHistory.QUERY, insertedTerm);
insertStart = System.currentTimeMillis();
mProvider.insert(SearchHistory.CONTENT_URI, cv);
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
c.moveToFirst();
t2Db = c.getLong(c.getColumnIndex(SearchHistory.DATE_LAST_VISITED));
c.close();
insertFinish = System.currentTimeMillis();
mAsserter.ok(t2Db >= insertStart, "DATE_LAST_VISITED",
"Date last visited should be set on insert.");
mAsserter.ok(t2Db <= insertFinish, "DATE_LAST_VISITED",
"Date last visited should be set on insert.");
mAsserter.ok(t2Db > t1Db, "DATE_LAST_VISITED",
"Date last visited should be updated on key increment.");
}
}
/**
* Verify that sending a delete command empties the database.
*/
private class TestDelete extends TestCase {
@Override
public void test() throws Exception {
String insertedTerm = "Courtside Seats";
ContentValues cv = new ContentValues();
cv.put(SearchHistory.QUERY, insertedTerm);
mProvider.insert(SearchHistory.CONTENT_URI, cv);
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
mAsserter.is(c.getCount(), 1, "Should have one value");
mProvider.delete(SearchHistory.CONTENT_URI, null, null);
c.close();
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
mAsserter.is(c.getCount(), 0, "Should be empty");
mProvider.insert(SearchHistory.CONTENT_URI, cv);
c.close();
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
mAsserter.is(c.getCount(), 1, "Should have one value");
c.close();
}
}
/**
* Ensure that we only increment when the case matches.
*/
private class TestIncrement extends TestCase {
@Override
public void test() throws Exception {
ContentValues cv = new ContentValues();
cv.put(SearchHistory.QUERY, "omaha");
mProvider.insert(SearchHistory.CONTENT_URI, cv);
cv = new ContentValues();
cv.put(SearchHistory.QUERY, "omaha");
mProvider.insert(SearchHistory.CONTENT_URI, cv);
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
c.moveToFirst();
mAsserter.is(c.getCount(), 1, "Should have one result");
mAsserter.is(c.getInt(c.getColumnIndex(SearchHistory.VISITS)), 2,
"Counter should be 2");
c.close();
cv = new ContentValues();
cv.put(SearchHistory.QUERY, "Omaha");
mProvider.insert(SearchHistory.CONTENT_URI, cv);
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
mAsserter.is(c.getCount(), 2, "Should have two results");
c.close();
}
}
}

Просмотреть файл

@ -16,7 +16,7 @@
<Url type="text/html" method="GET" template="https://search.yahoo.com/search">
<Param name="p" value="{searchTerms}" />
<Param name="ei" value="UTF-8" />
<Param name="fr" value="mozilla_mobile_search" />
<Param name="fr" value="mozmob1" />
</Url>
<SearchForm>https://search.yahoo.com/</SearchForm>
</SearchPlugin>

Просмотреть файл

@ -329,6 +329,9 @@ Discovery.prototype = {
let remoteDevice = update.device;
let remoteHost = update.from;
// Record the reply as received so it won't be purged as missing
this._expectingReplies.from.delete(remoteDevice);
// First, loop over the known services
for (let service in this.remoteServices) {
let devicesWithService = this.remoteServices[service];

Просмотреть файл

@ -116,6 +116,9 @@ add_task(function*() {
discovery.addService("penguins", { tux: false });
yield scanForChange("penguins", "updated");
// Scan again, but nothing should be removed
yield scanForNoChange("penguins", "removed");
// Split the scanning side from the service side to simulate the machine with
// the service becoming unreachable
gTestTransports = {};
@ -137,3 +140,17 @@ function scanForChange(service, changeType) {
discovery.scan();
return deferred.promise;
}
function scanForNoChange(service, changeType) {
let deferred = promise.defer();
let timer = setTimeout(() => {
deferred.resolve();
}, discovery.replyTimeout + 500);
discovery.on(service + "-device-" + changeType, function onChange() {
discovery.off(service + "-device-" + changeType, onChange);
clearTimeout(timer);
deferred.reject(new Error("Unexpected change occurred"));
});
discovery.scan();
return deferred.promise;
}

Просмотреть файл

@ -222,7 +222,7 @@ let FunctionCallActor = protocol.ActorClass({
// If this argument matches the method's signature
// and is an enum, change it to its constant name.
if (enumArgs && enumArgs.indexOf(i) !== -1) {
return getEnumsLookupTable(global, caller)[arg] || arg;
return getBitToEnumValue(global, caller, arg);
}
return arg;
});
@ -641,19 +641,48 @@ CallWatcherFront.ENUM_METHODS[CallWatcherFront.CANVAS_WEBGL_CONTEXT] = {
var gEnumRegex = /^[A-Z_]+$/;
var gEnumsLookupTable = {};
function getEnumsLookupTable(type, object) {
let cachedEnum = gEnumsLookupTable[type];
if (cachedEnum) {
return cachedEnum;
}
// These values are returned from errors, or empty values,
// and need to be ignored when checking arguments due to the bitwise math.
var INVALID_ENUMS = [
"INVALID_ENUM", "NO_ERROR", "INVALID_VALUE", "OUT_OF_MEMORY", "NONE"
];
let table = gEnumsLookupTable[type] = {};
function getBitToEnumValue(type, object, arg) {
let table = gEnumsLookupTable[type];
for (let key in object) {
if (key.match(gEnumRegex)) {
table[object[key]] = key;
// If mapping not yet created, do it on the first run.
if (!table) {
table = gEnumsLookupTable[type] = {};
for (let key in object) {
if (key.match(gEnumRegex)) {
// Maps `16384` to `"COLOR_BUFFER_BIT"`, etc.
table[object[key]] = key;
}
}
}
return table;
// If a single bit value, just return it.
if (table[arg]) {
return table[arg];
}
// Otherwise, attempt to reduce it to the original bit flags:
// `16640` -> "COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT"
let flags = [];
for (let flag in table) {
if (INVALID_ENUMS.indexOf(table[flag]) !== -1) {
continue;
}
// Cast to integer as all values are stored as strings
// in `table`
flag = flag | 0;
if (flag && (arg & flag) === flag) {
flags.push(table[flag]);
}
}
// Cache the combined bitmask value
return table[arg] = flags.join(" | ") || arg;
}

Просмотреть файл

@ -901,7 +901,7 @@ const TAB_CHARS = "\t";
* @param string text The CSS source to prettify.
* @return string Prettified CSS source
*/
CssLogic.prettifyCSS = function(text) {
CssLogic.prettifyCSS = function(text, ruleCount) {
if (CssLogic.LINE_SEPARATOR == null) {
let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
CssLogic.LINE_SEPARATOR = (os === "WINNT" ? "\r\n" : "\n");
@ -910,6 +910,12 @@ CssLogic.prettifyCSS = function(text) {
// remove initial and terminating HTML comments and surrounding whitespace
text = text.replace(/(?:^\s*<!--[\r\n]*)|(?:\s*-->\s*$)/g, "");
// don't attempt to prettify if there's more than one line per rule.
let lineCount = text.split("\n").length - 1;
if (ruleCount !== null && lineCount >= ruleCount) {
return text;
}
let parts = []; // indented parts
let partStart = 0; // start offset of currently parsed part
let indent = "";

Просмотреть файл

@ -23,15 +23,19 @@ const TESTS = [ {
pageid: PAGEID_ERROR_PATCHING,
buttonClick: "next"
}, {
pageid: PAGEID_DOWNLOADING
pageid: PAGEID_DOWNLOADING,
extraStartFunction: createContinueFile
}, {
pageid: PAGEID_FINISHED,
buttonClick: "extra1"
buttonClick: "extra1",
extraStartFunction: removeContinueFile
} ];
function runTest() {
debugDump("entering");
removeContinueFile();
// Specify the url to update.sjs with a slowDownloadMar param so the ui can
// load before the download completes.
let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1";

Просмотреть файл

@ -16,6 +16,7 @@
<script type="application/javascript"
src="utils.js"/>
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript">
<![CDATA[
@ -23,15 +24,19 @@ const TESTS = [ {
pageid: PAGEID_ERROR_PATCHING,
buttonClick: "next"
}, {
pageid: PAGEID_DOWNLOADING
pageid: PAGEID_DOWNLOADING,
extraStartFunction: createContinueFile
}, {
pageid: PAGEID_ERRORS,
buttonClick: "finish"
buttonClick: "finish",
extraStartFunction: removeContinueFile
} ];
function runTest() {
debugDump("entering");
removeContinueFile();
// Specify the url to update.sjs with a slowDownloadMar param so the ui can
// load before the download completes.
let slowDownloadURL = URL_HTTP_UPDATE_XML + "?slowDownloadMar=1";

Просмотреть файл

@ -44,23 +44,37 @@ function handleRequest(aRequest, aResponse) {
// mar will be downloaded asynchronously which will allow the ui to load
// before the download completes.
if (params.slowDownloadMar) {
var i;
aResponse.processAsync();
aResponse.setHeader("Content-Type", "binary/octet-stream");
aResponse.setHeader("Content-Length", SIZE_SIMPLE_MAR);
var continueFile = AUS_Cc["@mozilla.org/file/directory_service;1"].
getService(AUS_Ci.nsIProperties).
get("CurWorkD", AUS_Ci.nsILocalFile);
var continuePath = REL_PATH_DATA + "continue";
var continuePathParts = continuePath.split("/");
for (i = 0; i < continuePathParts.length; ++i) {
continueFile.append(continuePathParts[i]);
}
var marFile = AUS_Cc["@mozilla.org/file/directory_service;1"].
getService(AUS_Ci.nsIProperties).
get("CurWorkD", AUS_Ci.nsILocalFile);
var path = REL_PATH_DATA + FILE_SIMPLE_MAR;
var pathParts = path.split("/");
for(var i = 0; i < pathParts.length; ++i)
for (i = 0; i < pathParts.length; ++i) {
marFile.append(pathParts[i]);
}
var contents = readFileBytes(marFile);
gTimer = AUS_Cc["@mozilla.org/timer;1"].
createInstance(AUS_Ci.nsITimer);
gTimer.initWithCallback(function(aTimer) {
aResponse.write(contents);
aResponse.finish();
}, SLOW_MAR_DOWNLOAD_INTERVAL, AUS_Ci.nsITimer.TYPE_ONE_SHOT);
if (continueFile.exists()) {
gTimer.cancel();
aResponse.write(contents);
aResponse.finish();
}
}, SLOW_MAR_DOWNLOAD_INTERVAL, AUS_Ci.nsITimer.TYPE_REPEATING_SLACK);
return;
}

Просмотреть файл

@ -483,7 +483,7 @@ function delayedDefaultCallback() {
if (gTest.buttonClick) {
debugDump("clicking " + gTest.buttonClick + " button");
if(gTest.extraDelayedFinishFunction) {
if (gTest.extraDelayedFinishFunction) {
throw("Tests cannot have a buttonClick and an extraDelayedFinishFunction property");
}
gDocElem.getButton(gTest.buttonClick).click();
@ -495,6 +495,45 @@ function delayedDefaultCallback() {
}
}
/**
* Gets the continue file used to signal the mock http server to continue
* downloading for slow download mar file tests without creating it.
*
* @return nsILocalFile for the continue file.
*/
function getContinueFile() {
let continueFile = AUS_Cc["@mozilla.org/file/directory_service;1"].
getService(AUS_Ci.nsIProperties).
get("CurWorkD", AUS_Ci.nsILocalFile);
let continuePath = REL_PATH_DATA + "/continue";
let continuePathParts = continuePath.split("/");
for (let i = 0; i < continuePathParts.length; ++i) {
continueFile.append(continuePathParts[i]);
}
return continueFile;
}
/**
* Creates the continue file used to signal the mock http server to continue
* downloading for slow download mar file tests.
*/
function createContinueFile() {
debugDump("creating 'continue' file for slow mar downloads");
writeFile(getContinueFile(), "");
}
/**
* Removes the continue file used to signal the mock http server to continue
* downloading for slow download mar file tests.
*/
function removeContinueFile() {
let continueFile = getContinueFile();
if (continueFile.exists()) {
debugDump("removing 'continue' file for slow mar downloads");
continueFile.remove(false);
}
}
/**
* Checks the wizard page buttons' disabled and hidden attributes values are
* correct. If an expected button id is not specified then the expected disabled