MozReview-Commit-ID: ET0qKXDqQXD
This commit is contained in:
Wes Kocher 2016-04-13 14:45:41 -07:00
Родитель 01a139d9a0 6248f1e33c
Коммит aa13902dde
35 изменённых файлов: 697 добавлений и 350 удалений

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

@ -35,7 +35,7 @@
////////////////////////////////////////////////////////////////////////////
// Hacky stuffs
// This is the hack needed for searchbar work outside of browser.
// This is the hacks needed to use a searchbar without browser.js.
function getBrowser()
{
return {
@ -43,6 +43,10 @@
};
}
var BrowserSearch = {
updateOpenSearchBadge: function() {}
};
////////////////////////////////////////////////////////////////////////////
// Invokers

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

@ -62,13 +62,16 @@
gQueue.invoke(); // Will call SimpleTest.finish();
}
// This is the hack needed for searchbar work outside of browser.
// This is the hacks needed to use a searchbar without browser.js.
function getBrowser()
{
return {
mCurrentBrowser: { engines: new Array() }
};
}
var BrowserSearch = {
updateOpenSearchBadge: function() {}
};
SimpleTest.waitForExplicitFinish();

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

@ -3409,9 +3409,6 @@ const DOMLinkHandler = {
const BrowserSearch = {
addEngine: function(browser, engine, uri) {
if (!this.searchBar)
return;
// Check to see whether we've already added an engine with this title
if (browser.engines) {
if (browser.engines.some(e => e.title == engine.title))
@ -3449,11 +3446,7 @@ const BrowserSearch = {
*/
updateOpenSearchBadge: function() {
var searchBar = this.searchBar;
// The search bar binding might not be applied even though the element is
// in the document (e.g. when the navigation toolbar is hidden), so check
// for .textbox specifically.
if (!searchBar || !searchBar.textbox)
if (!searchBar)
return;
var engines = gBrowser.selectedBrowser.engines;

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

@ -253,7 +253,7 @@ const CustomizableWidgets = [
let elementCount = tabsFragment.childElementCount;
separator.hidden = !elementCount;
while (--elementCount >= 0) {
tabsFragment.children[elementCount].classList.add("subviewbutton");
tabsFragment.children[elementCount].classList.add("subviewbutton", "cui-withicon");
}
recentlyClosedTabs.appendChild(tabsFragment);
@ -263,7 +263,7 @@ const CustomizableWidgets = [
elementCount = windowsFragment.childElementCount;
separator.hidden = !elementCount;
while (--elementCount >= 0) {
windowsFragment.children[elementCount].classList.add("subviewbutton");
windowsFragment.children[elementCount].classList.add("subviewbutton", "cui-withicon");
}
recentlyClosedWindows.appendChild(windowsFragment);
},

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

@ -81,6 +81,7 @@
if (Components.isSuccessCode(aStatus)) {
// Refresh the display (updating icon, etc)
this.updateDisplay();
BrowserSearch.updateOpenSearchBadge();
} else {
Components.utils.reportError("Cannot initialize search service, bailing out: " + aStatus);
}

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

@ -4,6 +4,10 @@
%include ../../shared/customizableui/panelUIOverlay.inc.css
:root {
--panel-separator-color: hsla(210,4%,10%,.15);
}
.panel-subviews {
background-color: hsla(0,0%,100%,.97);
}
@ -73,4 +77,4 @@ menu.subviewbutton > .menu-right > image {
toolbarpaletteitem[place="palette"] > .toolbarbutton-1 > .toolbarbutton-menubutton-button {
padding: 3px 1px;
}
}

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

@ -21,6 +21,7 @@
%include ../browser.inc
:root {
--panel-separator-color: ThreeDShadow;
--panel-ui-exit-subview-gutter-width: 38px;
}
@ -1153,7 +1154,8 @@ menuitem.panel-subview-footer@menuStateActive@,
.cui-widget-panelview menuseparator {
-moz-appearance: none;
min-height: 0;
border-top: 1px solid hsla(210,4%,10%,.15);
border-top: 1px solid var(--panel-separator-color);
border-bottom: none;
margin: 6px 0;
padding: 0;
}
@ -1346,7 +1348,7 @@ toolbarpaletteitem[haswideitem][place="panel"] + toolbarpaletteitem[haswideitem]
margin: .5em 0;
width: 1px;
height: auto;
background: hsla(210,4%,10%,.15);
background: var(--panel-separator-color);
transition-property: margin;
transition-duration: 10ms;
transition-timing-function: ease;

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

@ -301,13 +301,14 @@ StyleEditorUI.prototype = {
let sources = yield styleSheet.getOriginalSources();
if (sources && sources.length) {
let parentEditorName = editor.friendlyName;
this._removeStyleSheetEditor(editor);
for (let source of sources) {
// set so the first sheet will be selected, even if it's a source
source.styleSheetIndex = styleSheet.styleSheetIndex;
source.relatedStyleSheet = styleSheet;
source.relatedEditorName = parentEditorName;
yield this._addStyleSheetEditor(source);
}
}
@ -803,7 +804,7 @@ StyleEditorUI.prototype = {
}
let ruleCount = editor.styleSheet.ruleCount;
if (editor.styleSheet.relatedStyleSheet && editor.linkedCSSFile) {
if (editor.styleSheet.relatedStyleSheet) {
ruleCount = editor.styleSheet.relatedStyleSheet.ruleCount;
}
if (ruleCount === undefined) {
@ -828,11 +829,13 @@ StyleEditorUI.prototype = {
label.setAttribute("tooltiptext", editor.styleSheet.href);
}
let linkedCSSFile = "";
let linkedCSSSource = "";
if (editor.linkedCSSFile) {
linkedCSSFile = OS.Path.basename(editor.linkedCSSFile);
linkedCSSSource = OS.Path.basename(editor.linkedCSSFile);
} else if (editor.styleSheet.relatedEditorName) {
linkedCSSSource = editor.styleSheet.relatedEditorName;
}
text(summary, ".stylesheet-linked-file", linkedCSSFile);
text(summary, ".stylesheet-linked-file", linkedCSSSource);
text(summary, ".stylesheet-title", editor.styleSheet.title || "");
text(summary, ".stylesheet-rule-count",
PluralForm.get(ruleCount,

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

@ -222,6 +222,9 @@ StyleSheetEditor.prototype = {
}
let relatedSheet = this.styleSheet.relatedStyleSheet;
if (!relatedSheet || !relatedSheet.href) {
return;
}
let path;
let href = removeQuery(relatedSheet.href);

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

@ -40,6 +40,7 @@ support-files =
sourcemap-sass/media-rules.scss
sourcemap-styl/test-stylus.styl
sourcemaps.html
sourcemaps-inline.html
sourcemaps-large.html
sourcemaps-watching.html
test_private.css
@ -84,6 +85,7 @@ skip-if = e10s && debug # Bug 1252201 - Docshell leak on debug e10s
[browser_styleeditor_sv_resize.js]
[browser_styleeditor_selectstylesheet.js]
[browser_styleeditor_sourcemaps.js]
[browser_styleeditor_sourcemaps_inline.js]
[browser_styleeditor_sourcemap_large.js]
[browser_styleeditor_sourcemap_watching.js]
[browser_styleeditor_sync.js]

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

@ -0,0 +1,85 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// https rather than chrome to improve coverage
const TESTCASE_URI = TEST_BASE_HTTPS + "sourcemaps-inline.html";
const PREF = "devtools.styleeditor.source-maps-enabled";
const sassContent = `body {
background-color: black;
& > h1 {
color: white;
}
}
`;
const cssContent = `body {
background-color: black;
}
body > h1 {
color: white;
}
` +
"/*# sourceMappingURL=data:application/json;base64,ewoidmVyc2lvbiI6IDMsCiJtY" +
"XBwaW5ncyI6ICJBQUFBLElBQUs7RUFDSCxnQkFBZ0IsRUFBRSxLQUFLO0VBQ3ZCLFNBQU87SUFD" +
"TCxLQUFLLEVBQUUsS0FBSyIsCiJzb3VyY2VzIjogWyJ0ZXN0LnNjc3MiXSwKInNvdXJjZXNDb25" +
"0ZW50IjogWyJib2R5IHtcbiAgYmFja2dyb3VuZC1jb2xvcjogYmxhY2s7XG4gICYgPiBoMSB7XG" +
"4gICAgY29sb3I6IHdoaXRlO1xuICB9XG59XG4iXSwKIm5hbWVzIjogW10sCiJmaWxlIjogInRlc" +
"3QuY3NzIgp9Cg== */";
add_task(function* () {
let {ui} = yield openStyleEditorForURL(TESTCASE_URI);
is(ui.editors.length, 1,
"correct number of editors with source maps enabled");
yield testEditor(ui.editors[0], "test.scss", sassContent);
// Test disabling original sources
yield togglePref(ui);
is(ui.editors.length, 1, "correct number of editors after pref toggled");
// Test CSS editors
yield testEditor(ui.editors[0], "<inline style sheet #1>", cssContent);
Services.prefs.clearUserPref(PREF);
});
function* testEditor(editor, expectedName, expectedText) {
let name = getStylesheetNameFor(editor);
is(expectedName, name, name + " editor name is correct");
yield openEditor(editor);
let text = editor.sourceEditor.getText();
is(text, expectedText, name + " editor contains expected text");
}
/* Helpers */
function togglePref(UI) {
let editorsPromise = UI.once("stylesheets-reset");
let selectedPromise = UI.once("editor-selected");
Services.prefs.setBoolPref(PREF, false);
return promise.all([editorsPromise, selectedPromise]);
}
function openEditor(editor) {
getLinkFor(editor).click();
return editor.getSourceEditor();
}
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}
function getStylesheetNameFor(editor) {
return editor.summary.querySelector(".stylesheet-name > label")
.getAttribute("value");
}

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

@ -0,0 +1,17 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>testcase for testing CSS source maps in inline style</title>
<style type="text/css">body {
background-color: black;
}
body > h1 {
color: white;
}
/*# sourceMappingURL=data:application/json;base64,ewoidmVyc2lvbiI6IDMsCiJtYXBwaW5ncyI6ICJBQUFBLElBQUs7RUFDSCxnQkFBZ0IsRUFBRSxLQUFLO0VBQ3ZCLFNBQU87SUFDTCxLQUFLLEVBQUUsS0FBSyIsCiJzb3VyY2VzIjogWyJ0ZXN0LnNjc3MiXSwKInNvdXJjZXNDb250ZW50IjogWyJib2R5IHtcbiAgYmFja2dyb3VuZC1jb2xvcjogYmxhY2s7XG4gICYgPiBoMSB7XG4gICAgY29sb3I6IHdoaXRlO1xuICB9XG59XG4iXSwKIm5hbWVzIjogW10sCiJmaWxlIjogInRlc3QuY3NzIgp9Cg== */</style>
</head>
<body>
<h1>Source maps testcase</div>
</body>
</html>

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

@ -7,7 +7,7 @@
// Check that, even though the AnimationPlayerActor only sends the bits of its
// state that change, the front reconstructs the whole state everytime.
add_task(function*() {
add_task(function* () {
let {client, walker, animations} =
yield initAnimationsFrontForUrl(MAIN_DOMAIN + "animation.html");
@ -29,9 +29,9 @@ function* playerHasCompleteStateAtAllTimes(walker, animations) {
// contains all keys.
// Normally, only the currentTime will have changed in between 2 calls.
for (let i = 0; i < 10; i++) {
let state = yield player.getCurrentState();
yield player.refreshState();
keys.forEach(key => {
ok(typeof state[key] !== "undefined",
ok(typeof player.state[key] !== "undefined",
"The state retrieved has key " + key);
});
}

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

@ -69,8 +69,6 @@ public class AppConstants {
public static final boolean preJBMR1 = MAX_SDK_VERSION < 17 || (MIN_SDK_VERSION < 17 && Build.VERSION.SDK_INT < 17);
public static final boolean preJB = MAX_SDK_VERSION < 16 || (MIN_SDK_VERSION < 16 && Build.VERSION.SDK_INT < 16);
public static final boolean preICS = MAX_SDK_VERSION < 14 || (MIN_SDK_VERSION < 14 && Build.VERSION.SDK_INT < 14);
public static final boolean preHCMR2 = MAX_SDK_VERSION < 13 || (MIN_SDK_VERSION < 13 && Build.VERSION.SDK_INT < 13);
public static final boolean preHCMR1 = MAX_SDK_VERSION < 12 || (MIN_SDK_VERSION < 12 && Build.VERSION.SDK_INT < 12);
}
/**

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

@ -1,199 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
/* 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.animation;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
import org.mozilla.gecko.AppConstants.Versions;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
class AnimatorProxy {
private static final WeakHashMap<View, AnimatorProxy> PROXIES =
new WeakHashMap<View, AnimatorProxy>();
private static interface AnimatorProxyImpl {
public float getAlpha();
public void setAlpha(float alpha);
public float getTranslationX();
public void setTranslationX(float translationX);
public float getTranslationY();
public void setTranslationY(float translationY);
public View getView();
}
private final AnimatorProxyImpl mImpl;
private AnimatorProxy(AnimatorProxyImpl impl) {
mImpl = impl;
}
public static AnimatorProxy create(View view) {
AnimatorProxy proxy = PROXIES.get(view);
// If the view's animation proxy has been overridden from somewhere else, we need to
// create a new AnimatorProxy for the view.
if (proxy == null) {
AnimatorProxyImpl impl = (new AnimatorProxyPostHC(view));
proxy = new AnimatorProxy(impl);
PROXIES.put(view, proxy);
}
return proxy;
}
public int getWidth() {
View view = mImpl.getView();
if (view != null)
return view.getWidth();
return 0;
}
public void setWidth(int width) {
View view = mImpl.getView();
if (view != null) {
ViewGroup.LayoutParams lp = view.getLayoutParams();
lp.width = width;
view.setLayoutParams(lp);
}
}
public int getHeight() {
View view = mImpl.getView();
if (view != null)
return view.getHeight();
return 0;
}
public void setHeight(int height) {
View view = mImpl.getView();
if (view != null) {
ViewGroup.LayoutParams lp = view.getLayoutParams();
lp.height = height;
view.setLayoutParams(lp);
}
}
public int getScrollX() {
View view = mImpl.getView();
if (view != null)
return view.getScrollX();
return 0;
}
public int getScrollY() {
View view = mImpl.getView();
if (view != null)
return view.getScrollY();
return 0;
}
public void scrollTo(int scrollX, int scrollY) {
View view = mImpl.getView();
if (view != null)
view.scrollTo(scrollX, scrollY);
}
public float getAlpha() {
return mImpl.getAlpha();
}
public void setAlpha(float alpha) {
mImpl.setAlpha(alpha);
}
public float getTranslationX() {
return mImpl.getTranslationX();
}
public void setTranslationX(float translationX) {
mImpl.setTranslationX(translationX);
}
public float getTranslationY() {
return mImpl.getTranslationY();
}
public void setTranslationY(float translationY) {
mImpl.setTranslationY(translationY);
}
private static class AnimatorProxyPostHC implements AnimatorProxyImpl {
private final WeakReference<View> mViewRef;
public AnimatorProxyPostHC(View view) {
mViewRef = new WeakReference<View>(view);
}
@Override
public float getAlpha() {
View view = mViewRef.get();
if (view != null)
return view.getAlpha();
return 1;
}
@Override
public void setAlpha(float alpha) {
View view = mViewRef.get();
if (view != null)
view.setAlpha(alpha);
}
@Override
public float getTranslationX() {
View view = mViewRef.get();
if (view != null)
return view.getTranslationX();
return 0;
}
@Override
public void setTranslationX(float translationX) {
View view = mViewRef.get();
if (view != null)
view.setTranslationX(translationX);
}
@Override
public float getTranslationY() {
View view = mViewRef.get();
if (view != null)
return view.getTranslationY();
return 0;
}
@Override
public void setTranslationY(float translationY) {
View view = mViewRef.get();
if (view != null)
view.setTranslationY(translationY);
}
@Override
public View getView() {
return mViewRef.get();
}
}
}

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

@ -35,7 +35,6 @@ public class PropertyAnimator implements Runnable {
private class ElementHolder {
View view;
AnimatorProxy proxy;
Property property;
float from;
float to;
@ -76,7 +75,6 @@ public class PropertyAnimator implements Runnable {
ElementHolder element = new ElementHolder();
element.view = view;
element.proxy = AnimatorProxy.create(view);
element.property = property;
element.to = to;
@ -128,19 +126,19 @@ public class PropertyAnimator implements Runnable {
// Fix the from value based on current position and property
for (ElementHolder element : mElementsList) {
if (element.property == Property.ALPHA)
element.from = element.proxy.getAlpha();
element.from = ViewHelper.getAlpha(element.view);
else if (element.property == Property.TRANSLATION_Y)
element.from = element.proxy.getTranslationY();
element.from = ViewHelper.getTranslationY(element.view);
else if (element.property == Property.TRANSLATION_X)
element.from = element.proxy.getTranslationX();
element.from = ViewHelper.getTranslationX(element.view);
else if (element.property == Property.SCROLL_Y)
element.from = element.proxy.getScrollY();
element.from = ViewHelper.getScrollY(element.view);
else if (element.property == Property.SCROLL_X)
element.from = element.proxy.getScrollX();
element.from = ViewHelper.getScrollX(element.view);
else if (element.property == Property.WIDTH)
element.from = element.proxy.getWidth();
element.from = ViewHelper.getWidth(element.view);
else if (element.property == Property.HEIGHT)
element.from = element.proxy.getHeight();
element.from = ViewHelper.getHeight(element.view);
ViewCompat.setHasTransientState(element.view, true);
@ -254,19 +252,19 @@ public class PropertyAnimator implements Runnable {
return;
if (element.property == Property.ALPHA)
element.proxy.setAlpha(delta);
ViewHelper.setAlpha(element.view, delta);
else if (element.property == Property.TRANSLATION_Y)
element.proxy.setTranslationY(delta);
ViewHelper.setTranslationY(element.view, delta);
else if (element.property == Property.TRANSLATION_X)
element.proxy.setTranslationX(delta);
ViewHelper.setTranslationX(element.view, delta);
else if (element.property == Property.SCROLL_Y)
element.proxy.scrollTo(element.proxy.getScrollX(), (int) delta);
ViewHelper.scrollTo(element.view, ViewHelper.getScrollX(element.view), (int) delta);
else if (element.property == Property.SCROLL_X)
element.proxy.scrollTo((int) delta, element.proxy.getScrollY());
ViewHelper.scrollTo(element.view, (int) delta, ViewHelper.getScrollY(element.view));
else if (element.property == Property.WIDTH)
element.proxy.setWidth((int) delta);
ViewHelper.setWidth(element.view, (int) delta);
else if (element.property == Property.HEIGHT)
element.proxy.setHeight((int) delta);
ViewHelper.setHeight(element.view, (int) delta);
}
private static abstract class FramePoster {

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

@ -5,58 +5,105 @@
package org.mozilla.gecko.animation;
import android.view.View;
import android.view.ViewGroup;
public final class ViewHelper {
private ViewHelper() {
}
public static float getTranslationX(View view) {
AnimatorProxy proxy = AnimatorProxy.create(view);
return proxy.getTranslationX();
if (view != null) {
return view.getTranslationX();
}
return 0;
}
public static void setTranslationX(View view, float translationX) {
final AnimatorProxy proxy = AnimatorProxy.create(view);
proxy.setTranslationX(translationX);
if (view != null) {
view.setTranslationX(translationX);
}
}
public static float getTranslationY(View view) {
final AnimatorProxy proxy = AnimatorProxy.create(view);
return proxy.getTranslationY();
if (view != null) {
return view.getTranslationY();
}
return 0;
}
public static void setTranslationY(View view, float translationY) {
final AnimatorProxy proxy = AnimatorProxy.create(view);
proxy.setTranslationY(translationY);
if (view != null) {
view.setTranslationY(translationY);
}
}
public static float getAlpha(View view) {
final AnimatorProxy proxy = AnimatorProxy.create(view);
return proxy.getAlpha();
if (view != null) {
return view.getAlpha();
}
return 1;
}
public static void setAlpha(View view, float alpha) {
final AnimatorProxy proxy = AnimatorProxy.create(view);
proxy.setAlpha(alpha);
if (view != null) {
view.setAlpha(alpha);
}
}
public static int getWidth(View view) {
final AnimatorProxy proxy = AnimatorProxy.create(view);
return proxy.getWidth();
if (view != null) {
return view.getWidth();
}
return 0;
}
public static void setWidth(View view, int width) {
final AnimatorProxy proxy = AnimatorProxy.create(view);
proxy.setWidth(width);
if (view != null) {
ViewGroup.LayoutParams lp = view.getLayoutParams();
lp.width = width;
view.setLayoutParams(lp);
}
}
public static int getHeight(View view) {
final AnimatorProxy proxy = AnimatorProxy.create(view);
return proxy.getHeight();
if (view != null) {
return view.getHeight();
}
return 0;
}
public static void setHeight(View view, int height) {
final AnimatorProxy proxy = AnimatorProxy.create(view);
proxy.setHeight(height);
if (view != null) {
ViewGroup.LayoutParams lp = view.getLayoutParams();
lp.height = height;
view.setLayoutParams(lp);
}
}
public static int getScrollX(View view) {
if (view != null) {
return view.getScrollX();
}
return 0;
}
public static int getScrollY(View view) {
if (view != null) {
return view.getScrollY();
}
return 0;
}
public static void scrollTo(View view, int scrollX, int scrollY) {
if (view != null) {
view.scrollTo(scrollX, scrollY);
}
}
}

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

@ -897,7 +897,10 @@ public class Distribution {
}
}
return new String[] { baseDirectory };
return new String[] {
baseDirectory + "/default",
baseDirectory
};
}
/**

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

@ -6,7 +6,6 @@
package org.mozilla.gecko.gfx;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
@ -305,10 +304,6 @@ class JavaPanZoomController
/** This function MUST be called on the UI thread */
@Override
public boolean onKeyEvent(KeyEvent event) {
if (Versions.preHCMR1) {
return false;
}
if ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD
&& event.getAction() == KeyEvent.ACTION_DOWN) {
@ -328,10 +323,6 @@ class JavaPanZoomController
/** This function MUST be called on the UI thread */
@Override
public boolean onMotionEvent(MotionEvent event) {
if (Versions.preHCMR1) {
return false;
}
switch (event.getSource() & InputDevice.SOURCE_CLASS_MASK) {
case InputDevice.SOURCE_CLASS_POINTER:
switch (event.getAction() & MotionEvent.ACTION_MASK) {

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

@ -461,6 +461,17 @@ public class GeckoMenu extends ListView
return false;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Close the menu if it is open and the hardware menu key is pressed.
if (keyCode == KeyEvent.KEYCODE_MENU && isShown()) {
close();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean isShortcutKey(int keyCode, KeyEvent event) {
return true;

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

@ -18,14 +18,6 @@ import android.view.ViewConfiguration;
public final class HardwareUtils {
private static final String LOGTAG = "GeckoHardwareUtils";
// Minimum memory threshold for a device to be considered
// a low memory platform (see isLowMemoryPlatform). This value
// has be in sync with Gecko's equivalent threshold (defined in
// xpcom/base/nsMemoryImpl.cpp) and should only be used in cases
// where we can't depend on Gecko to be up and running e.g. show/hide
// reading list capabilities in HomePager.
private static final int LOW_MEMORY_THRESHOLD_MB = 384;
private static final boolean IS_AMAZON_DEVICE = Build.MANUFACTURER.equalsIgnoreCase("Amazon");
public static final boolean IS_KINDLE_DEVICE = IS_AMAZON_DEVICE &&
(Build.MODEL.equals("Kindle Fire") ||
@ -86,19 +78,6 @@ public final class HardwareUtils {
return SysInfo.getMemSize();
}
public static boolean isLowMemoryPlatform() {
final int memSize = getMemSize();
// Fallback to false if we fail to read meminfo
// for some reason.
if (memSize == 0) {
Log.w(LOGTAG, "Could not compute system memory. Falling back to isLowMemoryPlatform = false.");
return false;
}
return memSize < LOW_MEMORY_THRESHOLD_MB;
}
/**
* @return false if the current system is not supported (e.g. APK/system ABI mismatch).
*/

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

@ -219,13 +219,17 @@
<!ENTITY pref_cookies_not_accept_foreign "Enabled, excluding 3rd party">
<!ENTITY pref_cookies_disabled "Disabled">
<!ENTITY pref_category_data_saver "Data saver">
<!ENTITY pref_category_media "Media">
<!ENTITY pref_category_developer_tools "Developer tools">
<!ENTITY pref_tap_to_load_images_title2 "Show images">
<!ENTITY pref_tap_to_load_images_enabled "Always">
<!ENTITY pref_tap_to_load_images_data "Only over Wi-Fi">
<!ENTITY pref_tap_to_load_images_disabled2 "Blocked">
<!ENTITY pref_show_web_fonts "Show Web fonts">
<!ENTITY pref_show_web_fonts_summary "Hide to use default fonts and reduce website load times">
<!ENTITY pref_show_web_fonts "Show web fonts">
<!ENTITY pref_show_web_fonts_summary2 "Download remote fonts when loading a page">
<!ENTITY pref_tracking_protection_title2 "Tracking Protection">
<!ENTITY pref_tracking_protection_summary3 "Enabled in Private Browsing">

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

@ -196,7 +196,6 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
'AlarmReceiver.java',
'AndroidGamepadManager.java',
'animation/AnimationUtils.java',
'animation/AnimatorProxy.java',
'animation/HeightChangeAnimation.java',
'animation/PropertyAnimator.java',
'animation/Rotate3DAnimation.java',

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

@ -32,42 +32,52 @@
android:entryValues="@array/pref_restore_values"
android:persistent="true" />
<ListPreference android:key="browser.image_blocking"
android:title="@string/pref_tap_to_load_images_title2"
android:entries="@array/pref_browser_image_blocking_entries"
android:entryValues="@array/pref_browser_image_blocking_values"
android:persistent="false" />
<CheckBoxPreference android:key="browser.display.use_document_fonts"
android:title="@string/pref_show_web_fonts"
android:summary="@string/pref_show_web_fonts_summary"/>
<ListPreference android:key="plugin.enable"
android:title="@string/pref_plugins"
android:entries="@array/pref_plugins_entries"
android:entryValues="@array/pref_plugins_values"
android:persistent="false" />
<SwitchPreference android:key="media.autoplay.enabled"
android:title="@string/pref_media_autoplay_enabled"
android:summary="@string/pref_media_autoplay_enabled_summary" />
<ListPreference android:key="browser.menu.showCharacterEncoding"
android:title="@string/pref_char_encoding"
android:entries="@array/pref_char_encoding_entries"
android:entryValues="@array/pref_char_encoding_values"
android:persistent="false" />
<SwitchPreference android:key="devtools.remote.usb.enabled"
android:title="@string/pref_developer_remotedebugging_usb" />
<PreferenceCategory android:title="@string/pref_category_data_saver">
<ListPreference android:key="browser.image_blocking"
android:title="@string/pref_tap_to_load_images_title2"
android:entries="@array/pref_browser_image_blocking_entries"
android:entryValues="@array/pref_browser_image_blocking_values"
android:persistent="false" />
<SwitchPreference android:key="devtools.remote.wifi.enabled"
android:title="@string/pref_developer_remotedebugging_wifi" />
<SwitchPreference android:key="browser.display.use_document_fonts"
android:title="@string/pref_show_web_fonts"
android:summary="@string/pref_show_web_fonts_summary"/>
<org.mozilla.gecko.preferences.AlignRightLinkPreference android:key="android.not_a_preference.remote_debugging.link"
android:title="@string/pref_learn_more"
android:persistent="false"
url="https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_Firefox_for_Android_with_WebIDE" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/pref_category_media">
<ListPreference android:key="plugin.enable"
android:title="@string/pref_plugins"
android:entries="@array/pref_plugins_entries"
android:entryValues="@array/pref_plugins_values"
android:persistent="false" />
<SwitchPreference android:key="media.autoplay.enabled"
android:title="@string/pref_media_autoplay_enabled"
android:summary="@string/pref_media_autoplay_enabled_summary" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/pref_category_developer_tools">
<SwitchPreference android:key="devtools.remote.usb.enabled"
android:title="@string/pref_developer_remotedebugging_usb" />
<SwitchPreference android:key="devtools.remote.wifi.enabled"
android:title="@string/pref_developer_remotedebugging_wifi" />
<org.mozilla.gecko.preferences.AlignRightLinkPreference android:key="android.not_a_preference.remote_debugging.link"
android:title="@string/pref_learn_more"
android:persistent="false"
url="https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_Firefox_for_Android_with_WebIDE" />
</PreferenceCategory>
</PreferenceScreen>

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

@ -203,13 +203,17 @@
<string name="pref_cookies_not_accept_foreign">&pref_cookies_not_accept_foreign;</string>
<string name="pref_cookies_disabled">&pref_cookies_disabled;</string>
<string name="pref_category_data_saver">&pref_category_data_saver;</string>
<string name="pref_category_media">&pref_category_media;</string>
<string name="pref_category_developer_tools">&pref_category_developer_tools;</string>
<string name="pref_tap_to_load_images_title2">&pref_tap_to_load_images_title2;</string>
<string name="pref_tap_to_load_images_enabled">&pref_tap_to_load_images_enabled;</string>
<string name="pref_tap_to_load_images_data">&pref_tap_to_load_images_data;</string>
<string name="pref_tap_to_load_images_disabled2">&pref_tap_to_load_images_disabled2;</string>
<string name="pref_show_web_fonts">&pref_show_web_fonts;</string>
<string name="pref_show_web_fonts_summary">&pref_show_web_fonts_summary;</string>
<string name="pref_show_web_fonts_summary">&pref_show_web_fonts_summary2;</string>
<string name="pref_tracking_protection_title">&pref_tracking_protection_title2;</string>
<string name="pref_tracking_protection_summary">&pref_tracking_protection_summary3;</string>

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

@ -622,8 +622,8 @@ var ActionBarHandler = {
toStringWithFormat("text/plain", flags, 0);
}
// Selection text gets trimmed up.
return selection.toString().trim();
// Return explicitly selected text.
return selection.toString();
},
/**

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

@ -1351,7 +1351,13 @@ LoginManagerPrompter.prototype = {
// Now that we know which login to use, modify its password.
var selectedLogin = logins[selectedIndex.value];
this.log("Updating password for user " + selectedLogin.username);
this._updateLogin(selectedLogin, aNewLogin);
var newLoginWithUsername = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
newLoginWithUsername.init(aNewLogin.hostname,
aNewLogin.formSubmitURL, aNewLogin.httpRealm,
selectedLogin.username, aNewLogin.password,
selectedLogin.userNameField, aNewLogin.passwordField);
this._updateLogin(selectedLogin, newLoginWithUsername);
}
},

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

@ -12,6 +12,7 @@ support-files =
../subtst_notifications_8.html
../subtst_notifications_9.html
../subtst_notifications_10.html
../subtst_notifications_change_p.html
authenticate.sjs
form_basic.html
head.js
@ -21,6 +22,8 @@ support-files =
streamConverter_content.sjs
[browser_capture_doorhanger.js]
[browser_username_select_dialog.js]
skip-if = e10s # bug 1263760
[browser_DOMFormHasPassword.js]
[browser_DOMInputPasswordAdded.js]
[browser_filldoorhanger.js]

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

@ -51,6 +51,8 @@ add_task(function* test_clickNever() {
clickDoorhangerButton(notif, NEVER_BUTTON);
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
info("Make sure Never took effect");
yield testSubmittingLoginForm("subtst_notifications_1.html", function*(fieldValues) {
is(fieldValues.username, "notifyu1", "Checking submitted username");
@ -61,6 +63,8 @@ add_task(function* test_clickNever() {
"Checking for login saving disabled");
Services.logins.setLoginSavingEnabled("http://mochi.test:8888", true);
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
add_task(function* test_clickRemember() {
@ -74,6 +78,13 @@ add_task(function* test_clickRemember() {
clickDoorhangerButton(notif, REMEMBER_BUTTON);
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username used on the new entry");
is(login.password, "notifyp1", "Check the password used on the new entry");
is(login.timesUsed, 1, "Check times used on new entry");
info("Make sure Remember took effect and we don't prompt for an existing login");
yield testSubmittingLoginForm("subtst_notifications_1.html", function*(fieldValues) {
is(fieldValues.username, "notifyu1", "Checking submitted username");
@ -82,6 +93,13 @@ add_task(function* test_clickRemember() {
ok(!notif, "checking for no notification popup");
});
logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username used");
is(login.password, "notifyp1", "Check the password used");
is(login.timesUsed, 2, "Check times used incremented");
checkOnlyLoginWasUsedTwice({ justChanged: false });
// remove that login
@ -100,6 +118,8 @@ add_task(function* test_rememberSignonsFalse() {
let notif = getCaptureDoorhanger("password-save");
ok(!notif, "checking for no notification popup");
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
add_task(function* test_rememberSignonsTrue() {
@ -113,6 +133,8 @@ add_task(function* test_rememberSignonsTrue() {
ok(notif, "got notification popup");
notif.remove();
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
/* autocomplete=off tests... */
@ -127,6 +149,8 @@ add_task(function* test_autocompleteOffUsername() {
ok(notif, "checking for notification popup");
notif.remove();
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
add_task(function* test_autocompleteOffPassword() {
@ -139,6 +163,8 @@ add_task(function* test_autocompleteOffPassword() {
ok(notif, "checking for notification popup");
notif.remove();
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
add_task(function* test_autocompleteOffForm() {
@ -151,6 +177,8 @@ add_task(function* test_autocompleteOffForm() {
ok(notif, "checking for notification popup");
notif.remove();
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
@ -163,6 +191,8 @@ add_task(function* test_noPasswordField() {
let notif = getCaptureDoorhanger("password-save");
ok(!notif, "checking for no notification popup");
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
add_task(function* test_pwOnlyLoginMatchesForm() {
@ -177,6 +207,13 @@ add_task(function* test_pwOnlyLoginMatchesForm() {
notif.remove();
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "", "Check the username");
is(login.password, "notifyp1", "Check the password");
is(login.timesUsed, 1, "Check times used");
Services.logins.removeLogin(login2);
});
@ -191,6 +228,13 @@ add_task(function* test_pwOnlyFormMatchesLogin() {
ok(!notif, "checking for no notification popup");
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username");
is(login.password, "notifyp1", "Check the password");
is(login.timesUsed, 2, "Check times used");
Services.logins.removeLogin(login1);
});
@ -206,6 +250,13 @@ add_task(function* test_pwOnlyFormDoesntMatchExisting() {
notif.remove();
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1B", "Check the username unchanged");
is(login.password, "notifyp1B", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
Services.logins.removeLogin(login1B);
});
@ -221,6 +272,13 @@ add_task(function* test_changeUPLoginOnUPForm_dont() {
clickDoorhangerButton(notif, DONT_CHANGE_BUTTON);
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username unchanged");
is(login.password, "notifyp1", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
Services.logins.removeLogin(login1);
});
@ -237,6 +295,13 @@ add_task(function* test_changeUPLoginOnUPForm_change() {
ok(!getCaptureDoorhanger("password-change"), "popup should be gone");
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username unchanged");
is(login.password, "pass2", "Check the password changed");
is(login.timesUsed, 2, "Check times used");
checkOnlyLoginWasUsedTwice({ justChanged: true });
// cleanup
@ -257,6 +322,15 @@ add_task(function* test_changePLoginOnUPForm() {
clickDoorhangerButton(notif, CHANGE_BUTTON);
ok(!getCaptureDoorhanger("password-change"), "popup should be gone");
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "", "Check the username unchanged");
is(login.password, "pass2", "Check the password changed");
is(login.timesUsed, 2, "Check times used");
// no cleanup -- saved password to be used in the next test.
});
add_task(function* test_changePLoginOnPForm() {
@ -270,6 +344,14 @@ add_task(function* test_changePLoginOnPForm() {
clickDoorhangerButton(notif, CHANGE_BUTTON);
ok(!getCaptureDoorhanger("password-change"), "popup should be gone");
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "", "Check the username unchanged");
is(login.password, "notifyp1", "Check the password changed");
is(login.timesUsed, 3, "Check times used");
Services.logins.removeLogin(login2);
});
@ -287,6 +369,8 @@ add_task(function* test_checkUPSaveText() {
is(expectedText, notificationText, "Checking text: " + notificationText);
notif.remove();
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
add_task(function* test_checkPSaveText() {
@ -303,6 +387,8 @@ add_task(function* test_checkPSaveText() {
is(expectedText, notificationText, "Checking text: " + notificationText);
notif.remove();
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
add_task(function* test_capture2pw0un() {
@ -316,6 +402,8 @@ add_task(function* test_capture2pw0un() {
ok(notif, "got notification popup");
notif.remove();
});
is(Services.logins.getAllLogins().length, 0, "Should not have any logins yet");
});
add_task(function* test_change2pw0unExistingDifferentUP() {
@ -332,6 +420,13 @@ add_task(function* test_change2pw0unExistingDifferentUP() {
notif.remove();
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1B", "Check the username unchanged");
is(login.password, "notifyp1B", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
Services.logins.removeLogin(login1B);
});
@ -349,6 +444,13 @@ add_task(function* test_change2pw0unExistingDifferentP() {
notif.remove();
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "", "Check the username unchanged");
is(login.password, "notifyp1B", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
Services.logins.removeLogin(login2B);
});
@ -365,11 +467,46 @@ add_task(function* test_change2pw0unExistingWithSameP() {
ok(!notif, "checking for no notification popup");
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "", "Check the username unchanged");
is(login.password, "notifyp1", "Check the password unchanged");
is(login.timesUsed, 2, "Check times used incremented");
checkOnlyLoginWasUsedTwice({ justChanged: false });
Services.logins.removeLogin(login2);
});
add_task(function* test_changeUPLoginOnPUpdateForm() {
info("Check for change-password popup, u+p login on password update form.");
Services.logins.addLogin(login1);
yield testSubmittingLoginForm("subtst_notifications_change_p.html", function*(fieldValues) {
is(fieldValues.username, "null", "Checking submitted username");
is(fieldValues.password, "pass2", "Checking submitted password");
let notif = getCaptureDoorhanger("password-change");
ok(notif, "got notification popup");
clickDoorhangerButton(notif, CHANGE_BUTTON);
ok(!getCaptureDoorhanger("password-change"), "popup should be gone");
});
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username unchanged");
is(login.password, "pass2", "Check the password changed");
is(login.timesUsed, 2, "Check times used");
checkOnlyLoginWasUsedTwice({ justChanged: true });
// cleanup
login1.password = "pass2";
Services.logins.removeLogin(login1);
login1.password = "notifyp1";
});
add_task(function* test_recipeCaptureFields_NewLogin() {
info("Check that we capture the proper fields when a field recipe is in use.");
@ -385,6 +522,13 @@ add_task(function* test_recipeCaptureFields_NewLogin() {
clickDoorhangerButton(notif, REMEMBER_BUTTON);
}, "http://example.org"); // The recipe is for example.org
let logins = Services.logins.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username unchanged");
is(login.password, "notifyp1", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
});
add_task(function* test_recipeCaptureFields_ExistingLogin() {
@ -400,8 +544,11 @@ add_task(function* test_recipeCaptureFields_ExistingLogin() {
checkOnlyLoginWasUsedTwice({ justChanged: false });
let logins = Services.logins.getAllLogins();
is(logins[0].username, "notifyu1", "check .username for existing login submission");
is(logins[0].password, "notifyp1", "check .password for existing login submission");
is(logins.length, 1, "Should only have 1 login");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username unchanged");
is(login.password, "notifyp1", "Check the password unchanged");
is(login.timesUsed, 2, "Check times used incremented");
Services.logins.removeAllLogins();
});

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

@ -0,0 +1,144 @@
/*
* Test username selection dialog, on password update from a p-only form,
* when there are multiple saved logins on the domain.
*/
// Copied from prompt_common.js. TODO: share the code.
function getSelectDialogDoc() {
// Trudge through all the open windows, until we find the one
// that has selectDialog.xul loaded.
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
//var enumerator = wm.getEnumerator("navigator:browser");
var enumerator = wm.getXULWindowEnumerator(null);
while (enumerator.hasMoreElements()) {
var win = enumerator.getNext();
var windowDocShell = win.QueryInterface(Ci.nsIXULWindow).docShell;
var containedDocShells = windowDocShell.getDocShellEnumerator(
Ci.nsIDocShellTreeItem.typeChrome,
Ci.nsIDocShell.ENUMERATE_FORWARDS);
while (containedDocShells.hasMoreElements()) {
// Get the corresponding document for this docshell
var childDocShell = containedDocShells.getNext();
// We don't want it if it's not done loading.
if (childDocShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE)
continue;
var childDoc = childDocShell.QueryInterface(Ci.nsIDocShell)
.contentViewer
.DOMDocument;
if (childDoc.location.href == "chrome://global/content/selectDialog.xul")
return childDoc;
}
}
return null;
}
let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
Ci.nsILoginInfo, "init");
let login1 = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
"notifyu1", "notifyp1", "user", "pass");
let login1B = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
"notifyu1B", "notifyp1B", "user", "pass");
add_task(function* test_changeUPLoginOnPUpdateForm_accept() {
info("Select an u+p login from multiple logins, on password update form, and accept.");
Services.logins.addLogin(login1);
Services.logins.addLogin(login1B);
yield testSubmittingLoginForm("subtst_notifications_change_p.html", function*(fieldValues) {
is(fieldValues.username, "null", "Checking submitted username");
is(fieldValues.password, "pass2", "Checking submitted password");
yield ContentTaskUtils.waitForCondition(() => {
return getSelectDialogDoc();
}, "Wait for selection dialog to be accessible.");
let doc = getSelectDialogDoc();
let dialog = doc.getElementsByTagName("dialog")[0];
let listbox = doc.getElementById("list");
is(listbox.selectedIndex, 0, "Checking selected index");
is(listbox.itemCount, 2, "Checking selected length");
['notifyu1', 'notifyu1B'].forEach((username, i) => {
is(listbox.getItemAtIndex(i).label, username, "Check username selection on dialog");
});
dialog.acceptDialog();
yield ContentTaskUtils.waitForCondition(() => {
return !getSelectDialogDoc();
}, "Wait for selection dialog to disappear.");
});
let logins = Services.logins.getAllLogins();
is(logins.length, 2, "Should have 2 logins");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username unchanged");
is(login.password, "pass2", "Check the password changed");
is(login.timesUsed, 2, "Check times used");
login = SpecialPowers.wrap(logins[1]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1B", "Check the username unchanged");
is(login.password, "notifyp1B", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
// cleanup
login1.password = "pass2";
Services.logins.removeLogin(login1);
login1.password = "notifyp1";
Services.logins.removeLogin(login1B);
});
add_task(function* test_changeUPLoginOnPUpdateForm_cancel() {
info("Select an u+p login from multiple logins, on password update form, and cancel.");
Services.logins.addLogin(login1);
Services.logins.addLogin(login1B);
yield testSubmittingLoginForm("subtst_notifications_change_p.html", function*(fieldValues) {
is(fieldValues.username, "null", "Checking submitted username");
is(fieldValues.password, "pass2", "Checking submitted password");
yield ContentTaskUtils.waitForCondition(() => {
return getSelectDialogDoc();
}, "Wait for selection dialog to be accessible.");
let doc = getSelectDialogDoc();
let dialog = doc.getElementsByTagName("dialog")[0];
let listbox = doc.getElementById("list");
is(listbox.selectedIndex, 0, "Checking selected index");
is(listbox.itemCount, 2, "Checking selected length");
['notifyu1', 'notifyu1B'].forEach((username, i) => {
is(listbox.getItemAtIndex(i).label, username, "Check username selection on dialog");
});
dialog.cancelDialog();
yield ContentTaskUtils.waitForCondition(() => {
return !getSelectDialogDoc();
}, "Wait for selection dialog to disappear.");
});
let logins = Services.logins.getAllLogins();
is(logins.length, 2, "Should have 2 logins");
let login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username unchanged");
is(login.password, "notifyp1", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
login = SpecialPowers.wrap(logins[1]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1B", "Check the username unchanged");
is(login.password, "notifyp1B", "Check the password unchanged");
is(login.timesUsed, 1, "Check times used");
// cleanup
Services.logins.removeLogin(login1);
Services.logins.removeLogin(login1B);
});

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

@ -1,6 +1,7 @@
const DIRECTORY_PATH = "/browser/toolkit/components/passwordmgr/test/browser/";
Cu.import("resource://testing-common/LoginTestUtils.jsm", this);
Cu.import("resource://testing-common/ContentTaskUtils.jsm", this);
registerCleanupFunction(function* cleanup_removeAllLoginsAndResetRecipes() {
Services.logins.removeAllLogins();

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

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Subtest for Login Manager notifications</title>
</head>
<body>
<h2>Change password</h2>
<form id="form" action="formsubmit.sjs">
<input id="pass_current" name="pass_current" type="password" value="notifyp1">
<input id="pass" name="pass" type="password">
<input id="pass_confirm" name="pass_confirm" type="password">
<button type='submit'>Submit</button>
</form>
<script>
function submitForm() {
passField.value = "pass2";
passConfirmField.value = "pass2";
form.submit();
}
window.onload = submitForm;
var form = document.getElementById("form");
var userField = document.getElementById("user");
var passField = document.getElementById("pass");
var passConfirmField = document.getElementById("pass_confirm");
</script>
</body>
</html>

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

@ -81,7 +81,9 @@ function checkTest() {
logins = pwmgr.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
ok(login.timesUsed, 1, "Check times used on new entry");
is(login.username, "notifyu1", "Check the username used on the new entry");
is(login.password, "notifyp1", "Check the password used on the new entry");
is(login.timesUsed, 1, "Check times used on new entry");
// password-change with chrome hidden
popup = getPopup(popupNotifications, "password-change");
@ -95,6 +97,7 @@ function checkTest() {
logins = pwmgr.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu1", "Check the username");
is(login.password, "pass2", "Check password changed");
is(login.timesUsed, 2, "check .timesUsed incremented on change");
ok(login.timeCreated < login.timeLastUsed, "timeLastUsed bumped");
@ -120,7 +123,9 @@ function checkTest() {
logins = pwmgr.getAllLogins();
is(logins.length, 1, "Should only have 1 login now");
login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
ok(login.timesUsed, 1, "Check times used on new entry");
is(login.username, "notifyu2", "Check the username used on the new entry");
is(login.password, "notifyp2", "Check the password used on the new entry");
is(login.timesUsed, 1, "Check times used on new entry");
// password-change with chrome visible
popupWin = iframe.contentWindow.popupWin;
@ -139,6 +144,7 @@ function checkTest() {
logins = pwmgr.getAllLogins();
is(logins.length, 1, "Should have 1 login");
login = SpecialPowers.wrap(logins[0]).QueryInterface(Ci.nsILoginMetaInfo);
is(login.username, "notifyu2", "Check the username");
is(login.password, "pass2", "Check password changed");
is(login.timesUsed, 2, "check .timesUsed incremented on change");
ok(login.timeCreated < login.timeLastUsed, "timeLastUsed bumped");

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

@ -5103,6 +5103,34 @@
"kind": "flag",
"description": "Set if Telemetry failed to save the session data to disk."
},
"TELEMETRY_ASSEMBLE_PAYLOAD_EXCEPTION": {
"alert_emails": ["telemetry-client-dev@mozilla.com"],
"bug_numbers": [1250640],
"expires_in_version": "53",
"kind": "count",
"description": "Count of exceptions in TelemetrySession.getSessionPayload()."
},
"TELEMETRY_SCHEDULER_TICK_EXCEPTION": {
"alert_emails": ["telemetry-client-dev@mozilla.com"],
"bug_numbers": [1250640],
"expires_in_version": "53",
"kind": "count",
"description": "Count of exceptions during executing the TelemetrySession scheduler tick logic."
},
"TELEMETRY_SCHEDULER_WAKEUP": {
"alert_emails": ["telemetry-client-dev@mozilla.com"],
"bug_numbers": [1250640],
"expires_in_version": "53",
"kind": "count",
"description": "Count of TelemetrySession scheduler ticks that were delayed long enough to suspect sleep."
},
"TELEMETRY_SCHEDULER_SEND_DAILY": {
"alert_emails": ["telemetry-client-dev@mozilla.com"],
"bug_numbers": [1250640],
"expires_in_version": "53",
"kind": "count",
"description": "Count of TelemetrySession triggering a daily ping."
},
"TELEMETRY_TEST_FLAG": {
"expires_in_version": "never",
"kind": "flag",

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

@ -320,6 +320,12 @@ var TelemetryScheduler = {
idleService.addIdleObserver(this, IDLE_TIMEOUT_SECONDS);
},
_clearTimeout: function() {
if (this._schedulerTimer) {
Policy.clearSchedulerTickTimeout(this._schedulerTimer);
}
},
/**
* Reschedules the tick timer.
*/
@ -330,9 +336,7 @@ var TelemetryScheduler = {
return;
}
if (this._schedulerTimer) {
Policy.clearSchedulerTickTimeout(this._schedulerTimer);
}
this._clearTimeout();
const now = Policy.now();
let timeout = SCHEDULER_TICK_INTERVAL_MS;
@ -421,6 +425,10 @@ var TelemetryScheduler = {
* operation completes.
*/
_onSchedulerTick: function() {
// This call might not be triggered from a timeout. In that case we don't want to
// leave any previously scheduled timeouts pending.
this._clearTimeout();
if (this._shuttingDown) {
this._log.warn("_onSchedulerTick - already shutdown.");
return Promise.reject(new Error("Already shutdown."));
@ -430,6 +438,7 @@ var TelemetryScheduler = {
try {
promise = this._schedulerTickLogic();
} catch (e) {
Telemetry.getHistogramById("TELEMETRY_SCHEDULER_TICK_EXCEPTION").add(1);
this._log.error("_onSchedulerTick - There was an exception", e);
} finally {
this._rescheduleTimeout();
@ -449,8 +458,10 @@ var TelemetryScheduler = {
let nowDate = Policy.now();
let now = nowDate.getTime();
if (now - this._lastTickTime > 1.1 * SCHEDULER_TICK_INTERVAL_MS) {
this._log.trace("_schedulerTickLogic - First scheduler tick after sleep or startup.");
if ((now - this._lastTickTime) > (1.1 * SCHEDULER_TICK_INTERVAL_MS) &&
(this._lastTickTime != 0)) {
Telemetry.getHistogramById("TELEMETRY_SCHEDULER_WAKEUP").add(1);
this._log.trace("_schedulerTickLogic - First scheduler tick after sleep.");
}
this._lastTickTime = now;
@ -458,6 +469,7 @@ var TelemetryScheduler = {
const shouldSendDaily = this._isDailyPingDue(nowDate);
if (shouldSendDaily) {
Telemetry.getHistogramById("TELEMETRY_SCHEDULER_SEND_DAILY").add(1);
this._log.trace("_schedulerTickLogic - Daily ping due.");
this._lastDailyPingTime = now;
return Impl._sendDailyPing();
@ -1299,23 +1311,29 @@ var Impl = {
getSessionPayload: function getSessionPayload(reason, clearSubsession) {
this._log.trace("getSessionPayload - reason: " + reason + ", clearSubsession: " + clearSubsession);
const isMobile = ["gonk", "android"].includes(AppConstants.platform);
const isSubsession = isMobile ? false : !this._isClassicReason(reason);
let payload;
try {
const isMobile = ["gonk", "android"].includes(AppConstants.platform);
const isSubsession = isMobile ? false : !this._isClassicReason(reason);
if (isMobile) {
clearSubsession = false;
}
if (isMobile) {
clearSubsession = false;
}
let measurements =
this.getSimpleMeasurements(reason == REASON_SAVED_SESSION, isSubsession, clearSubsession);
let info = !Utils.isContentProcess ? this.getMetadata(reason) : null;
let payload = this.assemblePayloadWithMeasurements(measurements, info, reason, clearSubsession);
if (!Utils.isContentProcess && clearSubsession) {
this.startNewSubsession();
// Persist session data to disk (don't wait until it completes).
let sessionData = this._getSessionDataObject();
TelemetryStorage.saveSessionData(sessionData);
let measurements =
this.getSimpleMeasurements(reason == REASON_SAVED_SESSION, isSubsession, clearSubsession);
let info = !Utils.isContentProcess ? this.getMetadata(reason) : null;
payload = this.assemblePayloadWithMeasurements(measurements, info, reason, clearSubsession);
} catch (ex) {
Telemetry.getHistogramById("TELEMETRY_ASSEMBLE_PAYLOAD_EXCEPTION").add(1);
throw ex;
} finally {
if (!Utils.isContentProcess && clearSubsession) {
this.startNewSubsession();
// Persist session data to disk (don't wait until it completes).
let sessionData = this._getSessionDataObject();
TelemetryStorage.saveSessionData(sessionData);
}
}
return payload;