merge fx-team to mozilla-central
@ -34,8 +34,12 @@ var FeedHandler = {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (container.firstChild)
|
||||
container.removeChild(container.firstChild);
|
||||
for (let i = container.childNodes.length - 1; i >= 0; --i) {
|
||||
let node = container.childNodes[i];
|
||||
if (isSubview && node.localName == "label")
|
||||
continue;
|
||||
container.removeChild(node);
|
||||
}
|
||||
|
||||
if (!feeds || feeds.length <= 1)
|
||||
return false;
|
||||
|
@ -283,7 +283,13 @@ let gSyncUI = {
|
||||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
if (xps.fxAccountsEnabled) {
|
||||
switchToTabHavingURI("about:accounts", true);
|
||||
fxAccounts.getSignedInUser().then(userData => {
|
||||
if (userData) {
|
||||
this.openPrefs();
|
||||
} else {
|
||||
switchToTabHavingURI("about:accounts", true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
|
||||
if (win)
|
||||
|
@ -123,7 +123,9 @@
|
||||
|
||||
<panelview id="PanelUI-socialapi" flex="1"/>
|
||||
|
||||
<panelview id="PanelUI-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);"></panelview>
|
||||
<panelview id="PanelUI-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);">
|
||||
<label value="&feedsMenu.label;" class="panel-subview-header"/>
|
||||
</panelview>
|
||||
|
||||
<panelview id="PanelUI-helpView" flex="1">
|
||||
<label value="&helpMenu.label;" class="panel-subview-header"/>
|
||||
|
@ -84,11 +84,11 @@
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
os.addObserver(this, "browser-search-engine-modified", false);
|
||||
|
||||
this._addedObserver = true;
|
||||
this._initialized = true;
|
||||
|
||||
this.searchService.init((function search_init_cb(aStatus) {
|
||||
// Bail out if the binding's been destroyed
|
||||
if (this._destroyed)
|
||||
if (!this._initialized)
|
||||
return;
|
||||
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
@ -101,13 +101,12 @@
|
||||
]]></constructor>
|
||||
|
||||
<destructor><![CDATA[
|
||||
this._destroyed = true;
|
||||
if (this._initialized) {
|
||||
this._initialized = false;
|
||||
|
||||
if (this._addedObserver) {
|
||||
var os = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
os.removeObserver(this, "browser-search-engine-modified");
|
||||
this._addedObserver = false;
|
||||
}
|
||||
|
||||
// Make sure to break the cycle from _textbox to us. Otherwise we leak
|
||||
|
@ -11,9 +11,9 @@ const {Cc, Ci, Cu} = require("chrome");
|
||||
let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
|
||||
let Heritage = require("sdk/core/heritage");
|
||||
|
||||
loader.lazyGetter(this, "promise", () => require("sdk/core/promise"));
|
||||
loader.lazyGetter(this, "Telemetry", () => require("devtools/shared/telemetry"));
|
||||
loader.lazyGetter(this, "WebConsoleFrame", () => require("devtools/webconsole/webconsole").WebConsoleFrame);
|
||||
loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
|
||||
loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
|
||||
loader.lazyImporter(this, "devtools", "resource://gre/modules/devtools/Loader.jsm");
|
||||
loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
|
||||
@ -110,7 +110,6 @@ HUD_SERVICE.prototype =
|
||||
function HS_openBrowserConsole(aTarget, aIframeWindow, aChromeWindow)
|
||||
{
|
||||
let hud = new BrowserConsole(aTarget, aIframeWindow, aChromeWindow);
|
||||
this._browserConsoleID = hud.hudId;
|
||||
this.consoles.set(hud.hudId, hud);
|
||||
return hud.init();
|
||||
},
|
||||
@ -242,6 +241,7 @@ HUD_SERVICE.prototype =
|
||||
connect().then(getTarget).then(openWindow).then((aWindow) => {
|
||||
this.openBrowserConsole(target, aWindow, aWindow)
|
||||
.then((aBrowserConsole) => {
|
||||
this._browserConsoleID = aBrowserConsole.hudId;
|
||||
this._browserConsoleDefer.resolve(aBrowserConsole);
|
||||
this._browserConsoleDefer = null;
|
||||
})
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
const {Cc, Ci, Cu} = require("chrome");
|
||||
|
||||
loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
|
||||
loader.lazyGetter(this, "promise", () => require("sdk/core/promise"));
|
||||
loader.lazyGetter(this, "HUDService", () => require("devtools/webconsole/hudservice"));
|
||||
loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
|
||||
|
||||
|
@ -49,10 +49,7 @@ function test()
|
||||
EventUtils.synthesizeKey(c, {}, hud.iframeWindow);
|
||||
}
|
||||
|
||||
hud.jsterm.execute(null, () => {
|
||||
// executeSoon() is needed to get out of the execute() event loop.
|
||||
executeSoon(onReadProperty.bind(null, msg));
|
||||
});
|
||||
hud.jsterm.execute(null, onReadProperty.bind(null, msg));
|
||||
}
|
||||
|
||||
function onReadProperty(deadObjectMessage)
|
||||
@ -72,7 +69,6 @@ function test()
|
||||
|
||||
function onFetched()
|
||||
{
|
||||
ok(true, "variables view fetched");
|
||||
hud.jsterm.execute("delete window.foobarzTezt; 2013-26", onCalcResult);
|
||||
}
|
||||
|
||||
|
@ -95,24 +95,37 @@ function testGen() {
|
||||
testNext();
|
||||
};
|
||||
EventUtils.synthesizeKey("VK_END", {});
|
||||
yield undefined;
|
||||
yield;
|
||||
|
||||
let oldScrollTop = scrollBox.scrollTop;
|
||||
|
||||
content.console.log("test message 151");
|
||||
|
||||
scrollBox.onscroll = () => {
|
||||
if (scrollBox.scrollTop == oldScrollTop) {
|
||||
// Wait for scroll to change.
|
||||
return;
|
||||
}
|
||||
scrollBox.onscroll = null;
|
||||
isnot(scrollBox.scrollTop, oldScrollTop, "scroll location updated (moved to bottom again)");
|
||||
hud = testDriver = null;
|
||||
finishTest();
|
||||
};
|
||||
waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
text: "test message 151",
|
||||
category: CATEGORY_WEBDEV,
|
||||
severity: SEVERITY_LOG,
|
||||
}],
|
||||
}).then(() => {
|
||||
scrollBox.onscroll = () => {
|
||||
if (scrollBox.scrollTop == oldScrollTop) {
|
||||
// Wait for scroll to change.
|
||||
return;
|
||||
}
|
||||
scrollBox.onscroll = null;
|
||||
isnot(scrollBox.scrollTop, oldScrollTop, "scroll location updated (moved to bottom again)");
|
||||
testNext();
|
||||
};
|
||||
});
|
||||
|
||||
yield undefined;
|
||||
|
||||
hud = testDriver = null;
|
||||
finishTest();
|
||||
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
@ -6,7 +6,7 @@
|
||||
let WebConsoleUtils, TargetFactory, require;
|
||||
let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
||||
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
|
||||
let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
|
||||
(() => {
|
||||
|
@ -14,7 +14,7 @@ loader.lazyServiceGetter(this, "clipboardHelper",
|
||||
"@mozilla.org/widget/clipboardhelper;1",
|
||||
"nsIClipboardHelper");
|
||||
loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
|
||||
loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
|
||||
loader.lazyGetter(this, "promise", () => require("sdk/core/promise"));
|
||||
loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
|
||||
loader.lazyGetter(this, "AutocompletePopup",
|
||||
() => require("devtools/shared/autocomplete-popup").AutocompletePopup);
|
||||
|
@ -129,6 +129,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
||||
<!ENTITY shareSelectCmd.accesskey "s">
|
||||
<!ENTITY shareVideoCmd.label "Share This Video">
|
||||
<!ENTITY shareVideoCmd.accesskey "s">
|
||||
<!ENTITY feedsMenu.label "Subscribe">
|
||||
<!ENTITY subscribeToPageMenupopup.label "Subscribe to This Page">
|
||||
<!ENTITY subscribeToPageMenuitem.label "Subscribe to This Page…">
|
||||
<!ENTITY addCurPagesCmd.label "Bookmark All Tabs…">
|
||||
|
@ -161,11 +161,6 @@ var BrowserUI = {
|
||||
Util.dumpLn("Exception in delay load module:", ex.message);
|
||||
}
|
||||
|
||||
if (WindowsPrefSync) {
|
||||
// Pulls in Desktop controlled prefs and pushes out Metro controlled prefs
|
||||
WindowsPrefSync.init();
|
||||
}
|
||||
|
||||
// check for left over crash reports and submit them if found.
|
||||
BrowserUI.startupCrashCheck();
|
||||
|
||||
|
@ -185,8 +185,7 @@ var Browser = {
|
||||
// Should we restore the previous session (crash or some other event)
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"]
|
||||
.getService(Ci.nsISessionStore);
|
||||
let shouldRestore = ss.shouldRestore()
|
||||
|| (3 == Services.prefs.getIntPref("browser.startup.page"));
|
||||
let shouldRestore = ss.shouldRestore();
|
||||
if (shouldRestore) {
|
||||
let bringFront = false;
|
||||
// First open any commandline URLs, except the homepage
|
||||
|
@ -9,6 +9,7 @@ const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/WindowsPrefSync.jsm");
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
|
||||
@ -199,6 +200,10 @@ SessionStore.prototype = {
|
||||
break;
|
||||
case "final-ui-startup":
|
||||
observerService.removeObserver(this, "final-ui-startup");
|
||||
if (WindowsPrefSync) {
|
||||
// Pulls in Desktop controlled prefs and pushes out Metro controlled prefs
|
||||
WindowsPrefSync.init();
|
||||
}
|
||||
this.init();
|
||||
break;
|
||||
case "domwindowopened":
|
||||
@ -340,9 +345,12 @@ SessionStore.prototype = {
|
||||
this._lastSaveTime = Date.now();
|
||||
|
||||
// Nothing to restore, notify observers things are complete
|
||||
if (!this._shouldRestore) {
|
||||
if (!this.shouldRestore()) {
|
||||
this._clearCache();
|
||||
Services.obs.notifyObservers(null, "sessionstore-windows-restored", "");
|
||||
|
||||
// If nothing is being restored, we only have our single Metro window.
|
||||
this._orderedWindows.push(aWindow.__SSID);
|
||||
}
|
||||
}
|
||||
|
||||
@ -726,7 +734,7 @@ SessionStore.prototype = {
|
||||
},
|
||||
|
||||
shouldRestore: function ss_shouldRestore() {
|
||||
return this._shouldRestore;
|
||||
return this._shouldRestore || (3 == Services.prefs.getIntPref("browser.startup.page"));
|
||||
},
|
||||
|
||||
restoreLastSession: function ss_restoreLastSession(aBringToFront) {
|
||||
|
@ -818,7 +818,7 @@ pref("browser.snippets.geoUrl", "https://geo.mozilla.org/country.json");
|
||||
pref("browser.snippets.statsUrl", "https://snippets-stats.mozilla.org/mobile");
|
||||
|
||||
// These prefs require a restart to take effect.
|
||||
pref("browser.snippets.enabled", false);
|
||||
pref("browser.snippets.enabled", true);
|
||||
pref("browser.snippets.syncPromo.enabled", false);
|
||||
|
||||
#ifdef MOZ_ANDROID_SYNTHAPKS
|
||||
|
@ -716,6 +716,8 @@ public abstract class GeckoApp
|
||||
message.optString("className"), message.optString("action"), message.optString("title"));
|
||||
} else if (event.equals("Locale:Set")) {
|
||||
setLocale(message.getString("locale"));
|
||||
} else if (event.equals("SystemUI:Visibility")) {
|
||||
setSystemUiVisible(message.getBoolean("visible"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
|
||||
@ -1580,6 +1582,7 @@ public abstract class GeckoApp
|
||||
registerEventListener("Intent:Open");
|
||||
registerEventListener("Intent:GetHandlers");
|
||||
registerEventListener("Locale:Set");
|
||||
registerEventListener("SystemUI:Visibility");
|
||||
|
||||
if (SmsManager.getInstance() != null) {
|
||||
SmsManager.getInstance().start();
|
||||
@ -2109,6 +2112,7 @@ public abstract class GeckoApp
|
||||
unregisterEventListener("Intent:Open");
|
||||
unregisterEventListener("Intent:GetHandlers");
|
||||
unregisterEventListener("Locale:Set");
|
||||
unregisterEventListener("SystemUI:Visibility");
|
||||
|
||||
deleteTempFiles();
|
||||
|
||||
@ -2815,4 +2819,17 @@ public abstract class GeckoApp
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setSystemUiVisible(final boolean visible) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (visible) {
|
||||
mMainLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
|
||||
} else {
|
||||
mMainLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -168,8 +168,11 @@ public final class HomeConfig {
|
||||
mLayoutType = panelConfig.mLayoutType;
|
||||
|
||||
mViews = new ArrayList<ViewConfig>();
|
||||
for (ViewConfig viewConfig : panelConfig.mViews) {
|
||||
mViews.add(new ViewConfig(viewConfig));
|
||||
List<ViewConfig> viewConfigs = panelConfig.mViews;
|
||||
if (viewConfigs != null) {
|
||||
for (ViewConfig viewConfig : viewConfigs) {
|
||||
mViews.add(new ViewConfig(viewConfig));
|
||||
}
|
||||
}
|
||||
mFlags = panelConfig.mFlags.clone();
|
||||
|
||||
|
@ -80,8 +80,12 @@ public abstract class CustomListPreference extends Preference implements View.On
|
||||
protected abstract int getPreferenceLayoutResource();
|
||||
|
||||
/**
|
||||
* Set whether this object's UI should display this as the default item. To ensure proper ordering,
|
||||
* this method should only be called after this Preference is added to the PreferenceCategory.
|
||||
* Set whether this object's UI should display this as the default item.
|
||||
* Note: This must be called from the UI thread because it touches the view hierarchy.
|
||||
*
|
||||
* To ensure proper ordering, this method should only be called after this Preference
|
||||
* is added to the PreferenceCategory.
|
||||
*
|
||||
* @param isDefault Flag indicating if this represents the default list item.
|
||||
*/
|
||||
public void setIsDefault(boolean isDefault) {
|
||||
|
@ -16,6 +16,7 @@ import org.json.JSONObject;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoEvent;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
public class SearchPreferenceCategory extends CustomListCategory implements GeckoEventListener {
|
||||
public static final String LOGTAG = "SearchPrefCategory";
|
||||
@ -81,7 +82,7 @@ public class SearchPreferenceCategory extends CustomListCategory implements Geck
|
||||
JSONObject engineJSON = engines.getJSONObject(i);
|
||||
final String engineName = engineJSON.getString("name");
|
||||
|
||||
SearchEnginePreference enginePreference = new SearchEnginePreference(getContext(), this);
|
||||
final SearchEnginePreference enginePreference = new SearchEnginePreference(getContext(), this);
|
||||
enginePreference.setSearchEngineFromJSON(engineJSON);
|
||||
enginePreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||
@Override
|
||||
@ -100,7 +101,12 @@ public class SearchPreferenceCategory extends CustomListCategory implements Geck
|
||||
// We set this here, not in setSearchEngineFromJSON, because it allows us to
|
||||
// keep a reference to the default engine to use when the AlertDialog
|
||||
// callbacks are used.
|
||||
enginePreference.setIsDefault(true);
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
enginePreference.setIsDefault(true);
|
||||
}
|
||||
});
|
||||
mDefaultReference = enginePreference;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
|
After Width: | Height: | Size: 797 B |
BIN
mobile/android/base/resources/drawable-hdpi/ab_copy.png
Normal file
After Width: | Height: | Size: 193 B |
BIN
mobile/android/base/resources/drawable-hdpi/ab_cut.png
Normal file
After Width: | Height: | Size: 664 B |
Before Width: | Height: | Size: 737 B After Width: | Height: | Size: 574 B |
BIN
mobile/android/base/resources/drawable-hdpi/ab_paste.png
Normal file
After Width: | Height: | Size: 324 B |
BIN
mobile/android/base/resources/drawable-hdpi/ab_search.png
Normal file
After Width: | Height: | Size: 846 B |
BIN
mobile/android/base/resources/drawable-hdpi/ab_select_all.png
Normal file
After Width: | Height: | Size: 199 B |
Before Width: | Height: | Size: 199 B |
Before Width: | Height: | Size: 564 B |
Before Width: | Height: | Size: 148 B After Width: | Height: | Size: 144 B |
Before Width: | Height: | Size: 337 B |
Before Width: | Height: | Size: 216 B |
After Width: | Height: | Size: 569 B |
BIN
mobile/android/base/resources/drawable-mdpi/ab_copy.png
Normal file
After Width: | Height: | Size: 166 B |
BIN
mobile/android/base/resources/drawable-mdpi/ab_cut.png
Normal file
After Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 552 B After Width: | Height: | Size: 442 B |
BIN
mobile/android/base/resources/drawable-mdpi/ab_paste.png
Normal file
After Width: | Height: | Size: 249 B |
BIN
mobile/android/base/resources/drawable-mdpi/ab_search.png
Normal file
After Width: | Height: | Size: 587 B |
BIN
mobile/android/base/resources/drawable-mdpi/ab_select_all.png
Normal file
After Width: | Height: | Size: 157 B |
Before Width: | Height: | Size: 161 B |
Before Width: | Height: | Size: 357 B |
Before Width: | Height: | Size: 131 B After Width: | Height: | Size: 128 B |
Before Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 166 B |
After Width: | Height: | Size: 1.0 KiB |
BIN
mobile/android/base/resources/drawable-xhdpi/ab_copy.png
Normal file
After Width: | Height: | Size: 251 B |
BIN
mobile/android/base/resources/drawable-xhdpi/ab_cut.png
Normal file
After Width: | Height: | Size: 890 B |
Before Width: | Height: | Size: 915 B After Width: | Height: | Size: 804 B |
BIN
mobile/android/base/resources/drawable-xhdpi/ab_paste.png
Normal file
After Width: | Height: | Size: 427 B |
BIN
mobile/android/base/resources/drawable-xhdpi/ab_search.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
mobile/android/base/resources/drawable-xhdpi/ab_select_all.png
Normal file
After Width: | Height: | Size: 233 B |
Before Width: | Height: | Size: 252 B |
Before Width: | Height: | Size: 996 B |
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 179 B |
Before Width: | Height: | Size: 442 B |
@ -81,19 +81,23 @@
|
||||
</style>
|
||||
|
||||
<style name="GeckoActionBar.Title" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Title">
|
||||
<item name="android:drawableLeft">?android:attr/actionModeCloseDrawable</item>
|
||||
<item name="android:drawableLeft">@drawable/ab_done</item>
|
||||
<item name="android:background">@android:color/transparent</item>
|
||||
<item name="android:paddingLeft">15dp</item>
|
||||
<item name="android:paddingRight">15dp</item>
|
||||
</style>
|
||||
|
||||
<style name="GeckoActionBar.Button" parent="android:style/Widget.Holo.Light.ActionButton">
|
||||
<item name="android:padding">12dp</item>
|
||||
<item name="android:padding">8dip</item>
|
||||
<!-- The default implementation doesn't do any image scaling. Our custom menus mean we can't just use the same image
|
||||
in both menus and the actionbar without doing some scaling though. -->
|
||||
<item name="android:scaleType">centerInside</item>
|
||||
</style>
|
||||
|
||||
<style name="GeckoActionBar.Button.MenuButton" parent="android:style/Widget.Holo.Light.ActionButton.Overflow">
|
||||
<item name="android:scaleType">center</item>
|
||||
<item name="android:background">@android:color/transparent</item>
|
||||
<item name="android:src">@drawable/menu_light</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
@ -53,10 +53,10 @@
|
||||
<item name="menuItemActionModeStyle">@style/GeckoActionBar.Button</item>
|
||||
<item name="android:actionModeStyle">@style/GeckoActionBar</item>
|
||||
<item name="android:actionButtonStyle">@style/GeckoActionBar.Button</item>
|
||||
<item name="android:actionModeCutDrawable">@drawable/cut</item>
|
||||
<item name="android:actionModeCopyDrawable">@drawable/copy</item>
|
||||
<item name="android:actionModePasteDrawable">@drawable/paste</item>
|
||||
<item name="android:actionModeSelectAllDrawable">@drawable/select_all</item>
|
||||
<item name="android:actionModeCutDrawable">@drawable/ab_cut</item>
|
||||
<item name="android:actionModeCopyDrawable">@drawable/ab_copy</item>
|
||||
<item name="android:actionModePasteDrawable">@drawable/ab_paste</item>
|
||||
<item name="android:actionModeSelectAllDrawable">@drawable/ab_select_all</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
@ -30,6 +30,11 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
|
||||
/**
|
||||
* Mozilla: Extra imports.
|
||||
*/
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
/**
|
||||
* Mozilla: Unused import.
|
||||
*/
|
||||
@ -257,6 +262,11 @@ public class ActivityChooserModel extends DataSetObservable {
|
||||
*/
|
||||
//private final PackageMonitor mPackageMonitor = new DataModelPackageMonitor();
|
||||
|
||||
/**
|
||||
* Mozilla: Count to monitor added and removed packages.
|
||||
*/
|
||||
private int mApplicationsCount;
|
||||
|
||||
/**
|
||||
* Context for accessing resources.
|
||||
*/
|
||||
@ -732,6 +742,15 @@ public class ActivityChooserModel extends DataSetObservable {
|
||||
* @return Whether loading was performed.
|
||||
*/
|
||||
private boolean loadActivitiesIfNeeded() {
|
||||
/**
|
||||
* Mozilla: Hack to find change in the installed/uninstalled applications.
|
||||
*/
|
||||
List<ApplicationInfo> applications = mContext.getPackageManager().getInstalledApplications(0);
|
||||
if (applications != null && applications.size() != mApplicationsCount) {
|
||||
mApplicationsCount = applications.size();
|
||||
mReloadActivities = true;
|
||||
}
|
||||
|
||||
if (mReloadActivities && mIntent != null) {
|
||||
mReloadActivities = false;
|
||||
mActivities.clear();
|
||||
|
@ -405,18 +405,18 @@ var SelectionHandler = {
|
||||
SELECT_ALL: {
|
||||
label: Strings.browser.GetStringFromName("contextmenu.selectAll"),
|
||||
id: "selectall_action",
|
||||
icon: "drawable://select_all",
|
||||
icon: "drawable://ab_select_all",
|
||||
action: function(aElement) {
|
||||
SelectionHandler.selectAll(aElement);
|
||||
},
|
||||
selector: ClipboardHelper.selectAllContext,
|
||||
order: 1,
|
||||
order: 5,
|
||||
},
|
||||
|
||||
CUT: {
|
||||
label: Strings.browser.GetStringFromName("contextmenu.cut"),
|
||||
id: "cut_action",
|
||||
icon: "drawable://cut",
|
||||
icon: "drawable://ab_cut",
|
||||
action: function(aElement) {
|
||||
let start = aElement.selectionStart;
|
||||
let end = aElement.selectionEnd;
|
||||
@ -427,31 +427,31 @@ var SelectionHandler = {
|
||||
// copySelection closes the selection. Show a caret where we just cut the text.
|
||||
SelectionHandler.attachCaret(aElement);
|
||||
},
|
||||
order: 1,
|
||||
order: 4,
|
||||
selector: ClipboardHelper.cutContext,
|
||||
},
|
||||
|
||||
COPY: {
|
||||
label: Strings.browser.GetStringFromName("contextmenu.copy"),
|
||||
id: "copy_action",
|
||||
icon: "drawable://copy",
|
||||
icon: "drawable://ab_copy",
|
||||
action: function() {
|
||||
SelectionHandler.copySelection();
|
||||
},
|
||||
order: 1,
|
||||
order: 3,
|
||||
selector: ClipboardHelper.getCopyContext(false)
|
||||
},
|
||||
|
||||
PASTE: {
|
||||
label: Strings.browser.GetStringFromName("contextmenu.paste"),
|
||||
id: "paste_action",
|
||||
icon: "drawable://paste",
|
||||
icon: "drawable://ab_paste",
|
||||
action: function(aElement) {
|
||||
ClipboardHelper.paste(aElement);
|
||||
SelectionHandler._positionHandles();
|
||||
SelectionHandler._updateMenu();
|
||||
},
|
||||
order: 1,
|
||||
order: 2,
|
||||
selector: ClipboardHelper.pasteContext,
|
||||
},
|
||||
|
||||
@ -470,11 +470,12 @@ var SelectionHandler = {
|
||||
return Strings.browser.formatStringFromName("contextmenu.search", [Services.search.defaultEngine.name], 1);
|
||||
},
|
||||
id: "search_action",
|
||||
icon: "drawable://ic_url_bar_search",
|
||||
icon: "drawable://ab_search",
|
||||
action: function() {
|
||||
SelectionHandler.searchSelection();
|
||||
SelectionHandler._closeSelection();
|
||||
},
|
||||
order: 1,
|
||||
selector: ClipboardHelper.searchWithContext,
|
||||
},
|
||||
|
||||
|
@ -266,8 +266,9 @@ AboutReader.prototype = {
|
||||
break;
|
||||
case "scroll":
|
||||
if (!this._scrolled) {
|
||||
this._scrolled = true;
|
||||
this._setToolbarVisibility(false);
|
||||
let isScrollingUp = this._scrollOffset > aEvent.pageY;
|
||||
this._setToolbarVisibility(isScrollingUp);
|
||||
this._scrollOffset = aEvent.pageY;
|
||||
}
|
||||
break;
|
||||
case "popstate":
|
||||
@ -501,6 +502,7 @@ AboutReader.prototype = {
|
||||
return;
|
||||
|
||||
this._toolbarElement.classList.toggle("toolbar-hidden");
|
||||
this._setSystemUIVisibility(visible);
|
||||
|
||||
if (!visible && !this._hasUsedToolbar) {
|
||||
this._hasUsedToolbar = Services.prefs.getBoolPref("reader.has_used_toolbar");
|
||||
@ -517,6 +519,13 @@ AboutReader.prototype = {
|
||||
this._setToolbarVisibility(!this._getToolbarVisibility());
|
||||
},
|
||||
|
||||
_setSystemUIVisibility: function Reader_setSystemUIVisibility(visible) {
|
||||
gChromeWin.sendMessageToJava({
|
||||
type: "SystemUI:Visibility",
|
||||
visible: visible
|
||||
});
|
||||
},
|
||||
|
||||
_loadFromURL: function Reader_loadFromURL(url) {
|
||||
this._showProgressDelayed();
|
||||
|
||||
|
@ -6793,7 +6793,7 @@ var SearchEngines = {
|
||||
SelectionHandler.addAction({
|
||||
id: "search_add_action",
|
||||
label: Strings.browser.GetStringFromName("contextmenu.addSearchEngine"),
|
||||
icon: "drawable://ic_url_bar_search",
|
||||
icon: "drawable://ab_add_search_engine",
|
||||
selector: filter,
|
||||
action: function(aElement) {
|
||||
SearchEngines.addEngine(aElement);
|
||||
|
@ -39,6 +39,10 @@ li:not(:last-of-type),
|
||||
#errorLongDesc,
|
||||
#errorLongContent {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
/* Push the #ignoreWarningButton to the bottom on the blocked site page */
|
||||
.blockedsite > #errorPageContainer > #errorLongContent {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
@ -339,13 +339,24 @@ InternalMethods.prototype = {
|
||||
return Promise.resolve(data);
|
||||
}
|
||||
if (!this.whenVerifiedPromise) {
|
||||
this.whenVerifiedPromise = Promise.defer();
|
||||
log.debug("whenVerified promise starts polling for verified email");
|
||||
this.pollEmailStatus(data.sessionToken, "start");
|
||||
}
|
||||
return this.whenVerifiedPromise.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Resend the verification email to the logged-in user.
|
||||
*
|
||||
* @return Promise
|
||||
* fulfilled: json data returned from xhr call
|
||||
* rejected: error
|
||||
*/
|
||||
resendVerificationEmail: function(data) {
|
||||
this.pollEmailStatus(data.sessionToken, "start");
|
||||
return this.fxAccountsClient.resendVerificationEmail(data.sessionToken);
|
||||
},
|
||||
|
||||
notifyObservers: function(topic) {
|
||||
log.debug("Notifying observers of " + topic);
|
||||
Services.obs.notifyObservers(null, topic, null);
|
||||
@ -364,12 +375,13 @@ InternalMethods.prototype = {
|
||||
let myGenerationCount = this.generationCount;
|
||||
log.debug("entering pollEmailStatus: " + why + " " + myGenerationCount);
|
||||
if (why == "start") {
|
||||
if (this.currentTimer) {
|
||||
// safety check - this case should have been caught on
|
||||
// entry with setSignedInUser
|
||||
throw new Error("Already polling for email status");
|
||||
}
|
||||
// If we were already polling, stop and start again. This could happen
|
||||
// if the user requested the verification email to be resent while we
|
||||
// were already polling for receipt of an earlier email.
|
||||
this.pollTimeRemaining = this.POLL_SESSION;
|
||||
if (!this.whenVerifiedPromise) {
|
||||
this.whenVerifiedPromise = Promise.defer();
|
||||
}
|
||||
}
|
||||
|
||||
this.checkEmailStatus(sessionToken)
|
||||
@ -487,7 +499,7 @@ this.FxAccounts.prototype = Object.freeze({
|
||||
log.debug("setSignedInUser - aborting any existing flows");
|
||||
internal.abortExistingFlow();
|
||||
|
||||
let record = {version: this.version, accountData: credentials };
|
||||
let record = {version: this.version, accountData: credentials};
|
||||
// Cache a clone of the credentials object.
|
||||
internal.signedInUser = JSON.parse(JSON.stringify(record));
|
||||
|
||||
@ -533,6 +545,22 @@ this.FxAccounts.prototype = Object.freeze({
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Resend the verification email fot the currently signed-in user.
|
||||
*
|
||||
*/
|
||||
resendVerificationEmail: function resendVerificationEmail() {
|
||||
return this.getSignedInUser().then((data) => {
|
||||
// If the caller is asking for verification to be re-sent, and there is
|
||||
// no signed-in user to begin with, this is probably best regarded as an
|
||||
// error.
|
||||
if (data) {
|
||||
return internal.resendVerificationEmail(data);
|
||||
}
|
||||
throw new Error("Cannot resend verification email; no signed-in user");
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* returns a promise that fires with the assertion. If there is no verified
|
||||
* signed-in user, fires with null.
|
||||
|
@ -101,7 +101,7 @@ this.FxAccountsClient.prototype = {
|
||||
* Destroy the current session with the Firefox Account API server
|
||||
*
|
||||
* @param sessionTokenHex
|
||||
* The session token endcoded in hex
|
||||
* The session token encoded in hex
|
||||
* @return Promise
|
||||
*/
|
||||
signOut: function (sessionTokenHex) {
|
||||
@ -113,7 +113,7 @@ this.FxAccountsClient.prototype = {
|
||||
* Check the verification status of the user's FxA email address
|
||||
*
|
||||
* @param sessionTokenHex
|
||||
* The current session token endcoded in hex
|
||||
* The current session token encoded in hex
|
||||
* @return Promise
|
||||
*/
|
||||
recoveryEmailStatus: function (sessionTokenHex) {
|
||||
@ -121,6 +121,18 @@ this.FxAccountsClient.prototype = {
|
||||
this._deriveHawkCredentials(sessionTokenHex, "sessionToken"));
|
||||
},
|
||||
|
||||
/**
|
||||
* Resend the verification email for the user
|
||||
*
|
||||
* @param sessionTokenHex
|
||||
* The current token encoded in hex
|
||||
* @return Promise
|
||||
*/
|
||||
resendVerificationEmail: function(sessionTokenHex) {
|
||||
return this._request("/recovery_email/resend_code", "POST",
|
||||
this._deriveHawkCredentials(sessionTokenHex, "sessionToken"));
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve encryption keys
|
||||
*
|
||||
@ -170,7 +182,7 @@ this.FxAccountsClient.prototype = {
|
||||
* Sends a public key to the FxA API server and returns a signed certificate
|
||||
*
|
||||
* @param sessionTokenHex
|
||||
* The current session token endcoded in hex
|
||||
* The current session token encoded in hex
|
||||
* @param serializedPublicKey
|
||||
* A public key (usually generated by jwcrypto)
|
||||
* @param lifetime
|
||||
@ -223,7 +235,7 @@ this.FxAccountsClient.prototype = {
|
||||
* (e.g. sessionToken vs. keyFetchToken).
|
||||
*
|
||||
* @param tokenHex
|
||||
* The current session token endcoded in hex
|
||||
* The current session token encoded in hex
|
||||
* @param context
|
||||
* A context for the credentials
|
||||
* @param size
|
||||
|
@ -64,6 +64,11 @@ function MockFxAccountsClient() {
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
this.resendVerificationEmail = function(sessionToken) {
|
||||
// Return the session token to show that we received it in the first place
|
||||
return Promise.resolve(sessionToken);
|
||||
};
|
||||
|
||||
this.signCertificate = function() { throw "no" };
|
||||
|
||||
FxAccountsClient.apply(this);
|
||||
@ -168,9 +173,7 @@ add_task(function test_get_signed_in_user_initially_unset() {
|
||||
do_check_eq(result, null);
|
||||
});
|
||||
|
||||
/*
|
||||
* Sanity-check that our mocked client is working correctly
|
||||
*/
|
||||
// Sanity-check that our mocked client is working correctly
|
||||
add_test(function test_client_mock() {
|
||||
do_test_pending();
|
||||
|
||||
@ -188,12 +191,10 @@ add_test(function test_client_mock() {
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* Sign in a user, and after a little while, verify the user's email.
|
||||
* Right after signing in the user, we should get the 'onlogin' notification.
|
||||
* Polling should detect that the email is verified, and eventually
|
||||
* 'onverified' should be observed
|
||||
*/
|
||||
// Sign in a user, and after a little while, verify the user's email.
|
||||
// Right after signing in the user, we should get the 'onlogin' notification.
|
||||
// Polling should detect that the email is verified, and eventually
|
||||
// 'onverified' should be observed
|
||||
add_test(function test_verification_poll() {
|
||||
do_test_pending();
|
||||
|
||||
@ -224,7 +225,7 @@ add_test(function test_verification_poll() {
|
||||
// The user is signing in, but email has not been verified yet
|
||||
do_check_eq(user.verified, false);
|
||||
do_timeout(200, function() {
|
||||
// Mock email verification ...
|
||||
log.debug("Mocking verification of francine's email");
|
||||
fxa.internal.fxAccountsClient._email = test_user.email;
|
||||
fxa.internal.fxAccountsClient._verified = true;
|
||||
});
|
||||
@ -232,11 +233,9 @@ add_test(function test_verification_poll() {
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* Sign in the user, but never verify the email. The check-email
|
||||
* poll should time out. No verifiedlogin event should be observed, and the
|
||||
* internal whenVerified promise should be rejected
|
||||
*/
|
||||
// Sign in the user, but never verify the email. The check-email
|
||||
// poll should time out. No verifiedlogin event should be observed, and the
|
||||
// internal whenVerified promise should be rejected
|
||||
add_test(function test_polling_timeout() {
|
||||
do_test_pending();
|
||||
|
||||
@ -303,9 +302,7 @@ add_test(function test_getKeys() {
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* getKeys with no keyFetchToken should trigger signOut
|
||||
*/
|
||||
// getKeys with no keyFetchToken should trigger signOut
|
||||
add_test(function test_getKeys_no_token() {
|
||||
do_test_pending();
|
||||
|
||||
@ -326,11 +323,9 @@ add_test(function test_getKeys_no_token() {
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* Alice (User A) signs up but never verifies her email. Then Bob (User B)
|
||||
* signs in with a verified email. Ensure that no sign-in events are triggered
|
||||
* on Alice's behalf. In the end, Bob should be the signed-in user.
|
||||
*/
|
||||
// Alice (User A) signs up but never verifies her email. Then Bob (User B)
|
||||
// signs in with a verified email. Ensure that no sign-in events are triggered
|
||||
// on Alice's behalf. In the end, Bob should be the signed-in user.
|
||||
add_test(function test_overlapping_signins() {
|
||||
do_test_pending();
|
||||
|
||||
@ -457,6 +452,64 @@ add_task(function test_getAssertion() {
|
||||
_("----- DONE ----\n");
|
||||
});
|
||||
|
||||
add_task(function test_resend_email_not_signed_in() {
|
||||
let fxa = new MockFxAccounts();
|
||||
|
||||
try {
|
||||
yield fxa.resendVerificationEmail();
|
||||
} catch(err) {
|
||||
do_check_eq(err.message,
|
||||
"Cannot resend verification email; no signed-in user");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
return;
|
||||
}
|
||||
do_throw("Should not be able to resend email when nobody is signed in");
|
||||
});
|
||||
|
||||
add_task(function test_resend_email() {
|
||||
do_test_pending();
|
||||
|
||||
let fxa = new MockFxAccounts();
|
||||
let alice = getTestUser("alice");
|
||||
|
||||
do_check_eq(fxa.internal.generationCount, 0);
|
||||
|
||||
// Alice is the user signing in; her email is unverified.
|
||||
fxa.setSignedInUser(alice).then(() => {
|
||||
log.debug("Alice signing in");
|
||||
|
||||
// We're polling for the first email
|
||||
do_check_eq(fxa.internal.generationCount, 1);
|
||||
|
||||
// The polling timer is ticking
|
||||
do_check_true(fxa.internal.currentTimer > 0);
|
||||
|
||||
fxa.internal.getUserAccountData().then(user => {
|
||||
do_check_eq(user.email, alice.email);
|
||||
do_check_eq(user.verified, false);
|
||||
log.debug("Alice wants verification email resent");
|
||||
|
||||
fxa.resendVerificationEmail().then((result) => {
|
||||
// Mock server response; ensures that the session token actually was
|
||||
// passed to the client to make the hawk call
|
||||
do_check_eq(result, "alice's session token");
|
||||
|
||||
// Timer was not restarted
|
||||
do_check_eq(fxa.internal.generationCount, 1);
|
||||
|
||||
// Timer is still ticking
|
||||
do_check_true(fxa.internal.currentTimer > 0);
|
||||
|
||||
// Ok abort polling before we go on to the next test
|
||||
fxa.internal.abortExistingFlow();
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* End of tests.
|
||||
* Utility functions follow.
|
||||
|
@ -21,6 +21,10 @@ menulist:-moz-focusring:not([open="true"]):not(.menulist-compact) > .menulist-la
|
||||
-moz-margin-start: 0 !important;
|
||||
}
|
||||
|
||||
.menulist-description {
|
||||
-moz-margin-start: 1ex !important;
|
||||
}
|
||||
|
||||
menulist:not([editable="true"]) > .menulist-dropmarker {
|
||||
margin-top: -2px;
|
||||
-moz-margin-start: 3px;
|
||||
|