Merge mozilla-central and fx-team

This commit is contained in:
Ed Morley 2014-06-11 10:10:34 +01:00
Родитель 3788175029 7ee62fabc4
Коммит cd7094ef21
17 изменённых файлов: 185 добавлений и 73 удалений

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

@ -1797,7 +1797,7 @@ Scope.prototype = {
element.className = aTargetClassName;
let arrow = this._arrow = document.createElement("hbox");
arrow.className = "arrow";
arrow.className = "arrow theme-twisty";
let name = this._name = document.createElement("label");
name.className = "plain name";

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

@ -372,6 +372,7 @@
@BINPATH@/browser/components/devtools-clhandler.js
@BINPATH@/browser/components/Experiments.manifest
@BINPATH@/browser/components/ExperimentsService.js
@BINPATH@/browser/components/translation.manifest
@BINPATH@/components/Downloads.manifest
@BINPATH@/components/DownloadLegacy.js
@BINPATH@/components/BrowserPageThumbs.manifest

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

@ -282,6 +282,10 @@ div.CodeMirror span.eval-text {
background-position: -42px -14px;
}
.theme-twisty[invisible] {
visibility: hidden;
}
.theme-checkbox {
display: inline-block;
border: 0;

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

@ -282,6 +282,10 @@ div.CodeMirror span.eval-text {
background-position: -14px -14px;
}
.theme-twisty[invisible] {
visibility: hidden;
}
/* Use white twisty when next to a selected item in markup view */
.theme-selected ~ .theme-twisty {
background-position: -28px -14px;

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

@ -630,8 +630,12 @@
color: inherit !important;
}
.variable-or-property > .title > .arrow {
-moz-margin-start: 3px;
.variables-view-container .theme-twisty {
margin: 2px;
}
.variable-or-property > .title > .theme-twisty {
-moz-margin-start: 5px;
}
.variable-or-property:not([untitled]) > .variables-view-element-details {
@ -892,22 +896,6 @@
margin: 0;
}
/* Expand/collapse arrow */
.arrow {
-moz-appearance: treetwisty;
width: 20px;
height: 20px;
}
.arrow[open] {
-moz-appearance: treetwistyopen;
}
.arrow[invisible] {
visibility: hidden;
}
/* Canvas graphs */
.graph-widget-canvas {

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

@ -6,14 +6,4 @@
.breadcrumbs-widget-item:-moz-focusring > .button-box {
border-width: 0;
}
.arrow {
-moz-appearance: none;
background: url("chrome://global/skin/tree/twisty-clsd.png") center center no-repeat;
}
.arrow[open] {
-moz-appearance: none;
background-image: url("chrome://global/skin/tree/twisty-open.png");
}
}

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

@ -306,7 +306,7 @@ this.DOMApplicationRegistry = {
},
// Registers all the activities and system messages.
registerAppsHandlers: function(aRunUpdate) {
registerAppsHandlers: Task.async(function*(aRunUpdate) {
this.notifyAppsRegistryStart();
let ids = [];
for (let id in this.webapps) {
@ -318,40 +318,38 @@ this.DOMApplicationRegistry = {
// Read the CSPs and roles. If MOZ_SYS_MSG is defined this is done on
// _processManifestForIds so as to not reading the manifests
// twice
this._readManifests(ids).then((aResults) => {
aResults.forEach((aResult) => {
if (!aResult.manifest) {
// If we can't load the manifest, we probably have a corrupted
// registry. We delete the app since we can't do anything with it.
delete this.webapps[aResult.id];
return;
}
let app = this.webapps[aResult.id];
app.csp = aResult.manifest.csp || "";
app.role = aResult.manifest.role || "";
if (app.appStatus >= Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
app.redirects = this.sanitizeRedirects(aResult.redirects);
}
});
let results = yield this._readManifests(ids);
results.forEach((aResult) => {
if (!aResult.manifest) {
// If we can't load the manifest, we probably have a corrupted
// registry. We delete the app since we can't do anything with it.
delete this.webapps[aResult.id];
return;
}
let app = this.webapps[aResult.id];
app.csp = aResult.manifest.csp || "";
app.role = aResult.manifest.role || "";
if (app.appStatus >= Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
app.redirects = this.sanitizeRedirects(aResult.redirects);
}
});
// Nothing else to do but notifying we're ready.
this.notifyAppsRegistryReady();
}
},
}),
updateDataStoreForApp: function(aId) {
updateDataStoreForApp: Task.async(function*(aId) {
if (!this.webapps[aId]) {
return;
}
// Create or Update the DataStore for this app
this._readManifests([{ id: aId }]).then((aResult) => {
let app = this.webapps[aId];
this.updateDataStore(app.localId, app.origin, app.manifestURL,
aResult[0].manifest, app.appStatus);
});
},
let results = yield this._readManifests([{ id: aId }]);
let app = this.webapps[aId];
this.updateDataStore(app.localId, app.origin, app.manifestURL,
results[0].manifest, app.appStatus);
}),
updatePermissionsForApp: function(aId, aIsPreinstalled) {
if (!this.webapps[aId]) {
@ -609,10 +607,10 @@ this.DOMApplicationRegistry = {
// DataStores must be initialized at startup.
for (let id in this.webapps) {
this.updateDataStoreForApp(id);
yield this.updateDataStoreForApp(id);
}
this.registerAppsHandlers(runUpdate);
yield this.registerAppsHandlers(runUpdate);
}.bind(this)).then(null, Cu.reportError);
},
@ -1101,7 +1099,11 @@ this.DOMApplicationRegistry = {
this.getSelf(msg, mm);
break;
case "Webapps:Uninstall":
#ifdef MOZ_WIDGET_ANDROID
Services.obs.notifyObservers(mm, "webapps-runtime-uninstall", JSON.stringify(msg));
#else
this.doUninstall(msg, mm);
#endif
break;
case "Webapps:Launch":
this.doLaunch(msg, mm);

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

@ -416,6 +416,16 @@ abstract public class BrowserApp extends GeckoApp
return values;
}
void handleReaderRemoved(final String url) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
BrowserDB.removeReadingListItemWithURL(getContentResolver(), url);
showToast(R.string.page_removed, Toast.LENGTH_SHORT);
}
});
}
private void handleReaderFaviconRequest(final String url) {
(new UiAsyncTask<Void, Void, String>(ThreadUtils.getBackgroundHandler()) {
@Override
@ -529,6 +539,7 @@ abstract public class BrowserApp extends GeckoApp
"Menu:Add",
"Menu:Remove",
"Reader:ListStatusRequest",
"Reader:Removed",
"Reader:Share",
"Settings:Show",
"Telemetry:Gather",
@ -886,6 +897,7 @@ abstract public class BrowserApp extends GeckoApp
"Menu:Add",
"Menu:Remove",
"Reader:ListStatusRequest",
"Reader:Removed",
"Reader:Share",
"Settings:Show",
"Telemetry:Gather",
@ -1216,6 +1228,10 @@ abstract public class BrowserApp extends GeckoApp
} else if ("Reader:ListStatusRequest".equals(event)) {
handleReaderListStatusRequest(message.getString("url"));
} else if ("Reader:Removed".equals(event)) {
final String url = message.getString("url");
handleReaderRemoved(url);
} else if ("Reader:Share".equals(event)) {
final String title = message.getString("title");
final String url = message.getString("url");

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

@ -106,7 +106,6 @@ class GlobalHistory {
BrowserDB.updateVisitedHistory(GeckoAppShell.getContext().getContentResolver(), uri);
final long end = SystemClock.uptimeMillis();
final long took = end - start;
Log.d(LOGTAG, "GlobalHistory.add took " + took + "msec.");
Telemetry.HistogramAdd(TELEMETRY_HISTOGRAM_ADD, (int) Math.min(took, Integer.MAX_VALUE));
addToGeckoOnly(uri);
}
@ -117,7 +116,6 @@ class GlobalHistory {
BrowserDB.updateHistoryTitle(GeckoAppShell.getContext().getContentResolver(), uri, title);
final long end = SystemClock.uptimeMillis();
final long took = end - start;
Log.d(LOGTAG, "GlobalHistory.update took " + took + "msec.");
Telemetry.HistogramAdd(TELEMETRY_HISTOGRAM_UPDATE, (int) Math.min(took, Integer.MAX_VALUE));
}

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

@ -5,6 +5,8 @@
package org.mozilla.gecko.home;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.EditBookmarkDialog;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
@ -337,7 +339,16 @@ abstract class HomeFragment extends Fragment {
BrowserDB.removeHistoryEntry(cr, mUrl);
BrowserDB.removeReadingListItemWithURL(cr, mUrl);
GeckoEvent e = GeckoEvent.createBroadcastEvent("Reader:Remove", mUrl);
final JSONObject json = new JSONObject();
try {
json.put("url", mUrl);
json.put("notify", false);
} catch (JSONException e) {
Log.e(LOGTAG, "error building JSON arguments");
}
GeckoEvent e = GeckoEvent.createBroadcastEvent("Reader:Remove", json.toString());
GeckoAppShell.sendEventToGecko(e);
return null;

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

@ -31,6 +31,7 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
public class EventListener implements NativeEventListener {
@ -41,6 +42,7 @@ public class EventListener implements NativeEventListener {
EventDispatcher.getInstance().registerGeckoThreadListener(this,
"Webapps:Preinstall",
"Webapps:InstallApk",
"Webapps:UninstallApk",
"Webapps:Postinstall",
"Webapps:Open",
"Webapps:Uninstall",
@ -51,6 +53,7 @@ public class EventListener implements NativeEventListener {
EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
"Webapps:Preinstall",
"Webapps:InstallApk",
"Webapps:UninstallApk",
"Webapps:Postinstall",
"Webapps:Open",
"Webapps:Uninstall",
@ -62,6 +65,8 @@ public class EventListener implements NativeEventListener {
try {
if (event.equals("Webapps:InstallApk")) {
installApk(GeckoAppShell.getGeckoInterface().getActivity(), message, callback);
} else if (event.equals("Webapps:UninstallApk")) {
uninstallApk(GeckoAppShell.getGeckoInterface().getActivity(), message);
} else if (event.equals("Webapps:Postinstall")) {
postInstallWebapp(message.getString("apkPackageName"), message.getString("origin"));
} else if (event.equals("Webapps:Open")) {
@ -193,6 +198,20 @@ public class EventListener implements NativeEventListener {
});
}
public static void uninstallApk(final Activity context, NativeJSObject message) {
String packageName = message.getString("apkPackageName");
Uri packageUri = Uri.parse("package:" + packageName);
Intent intent;
if (Build.VERSION.SDK_INT < 14) {
intent = new Intent(Intent.ACTION_DELETE, packageUri);
} else {
intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
}
context.startActivity(intent);
}
private static final int DEFAULT_VERSION_CODE = -1;
public static JSONObject getApkVersions(Activity context, String[] packageNames) {

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

@ -47,6 +47,29 @@ function checkForUpdates(aEvent) {
WebappManager.checkForUpdates(true);
}
let ContextMenus = {
target: null,
init: function() {
document.addEventListener("contextmenu", this, false);
document.getElementById("uninstallLabel").addEventListener("click", this.uninstall.bind(this), false);
},
handleEvent: function(event) {
// store the target of context menu events so that we know which app to act on
this.target = event.target;
while (!this.target.hasAttribute("contextmenu")) {
this.target = this.target.parentNode;
}
},
uninstall: function() {
navigator.mozApps.mgmt.uninstall(this.target.app);
this.target = null;
}
};
function onLoad(aEvent) {
let elmts = document.querySelectorAll("[pref]");
for (let i = 0; i < elmts.length; i++) {
@ -59,6 +82,8 @@ function onLoad(aEvent) {
navigator.mozApps.mgmt.onuninstall = onUninstall;
updateList();
ContextMenus.init();
// XXX - Hack to fix bug 985867 for now
document.addEventListener("touchstart", function() { });
}
@ -84,6 +109,7 @@ function addApplication(aApp) {
let container = document.createElement("div");
container.className = "app list-item";
container.setAttribute("contextmenu", "appmenu");
container.setAttribute("id", "app-" + aApp.origin);
container.setAttribute("mozApp", aApp.origin);
container.setAttribute("title", manifest.name);

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

@ -28,6 +28,11 @@
</head>
<body dir="&locale.dir;">
<menu type="context" id="appmenu">
<menuitem id="uninstallLabel" label="&aboutApps.uninstall;"></menuitem>
</menu>
<div class="header">
<div>&aboutApps.header;</div>
<div id="header-button" role="button" aria-label="&aboutApps.browseMarketplace;" pref="app.marketplaceURL"/>

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

@ -196,9 +196,9 @@ AboutReader.prototype = {
}
break;
}
case "Reader:Remove": {
if (aData == this._article.url) {
let args = JSON.parse(aData);
if (args.url == this._article.url) {
if (this._isReadingListItem != 0) {
this._isReadingListItem = 0;
this._updateToggleButton();
@ -316,7 +316,8 @@ AboutReader.prototype = {
// In addition to removing the article from the cache (handled in
// browser.js), sending this message will cause the toggle button to be
// updated (handled in this file).
Services.obs.notifyObservers(null, "Reader:Remove", this._article.url);
let json = JSON.stringify({ url: this._article.url, notify: true });
Services.obs.notifyObservers(null, "Reader:Remove", json);
UITelemetry.addEvent("unsave.1", "button", null, "reader");
}

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

@ -328,7 +328,7 @@ var BrowserApp = {
Services.obs.addObserver(this, "webapps-runtime-install-package", false);
Services.obs.addObserver(this, "webapps-ask-install", false);
Services.obs.addObserver(this, "webapps-launch", false);
Services.obs.addObserver(this, "webapps-uninstall", false);
Services.obs.addObserver(this, "webapps-runtime-uninstall", false);
Services.obs.addObserver(this, "Webapps:AutoInstall", false);
Services.obs.addObserver(this, "Webapps:Load", false);
Services.obs.addObserver(this, "Webapps:AutoUninstall", false);
@ -1631,8 +1631,8 @@ var BrowserApp = {
break;
}
case "webapps-uninstall": {
WebappManager.uninstall(JSON.parse(aData));
case "webapps-runtime-uninstall": {
WebappManager.uninstall(JSON.parse(aData), aSubject);
break;
}
@ -7320,9 +7320,20 @@ let Reader = {
}
case "Reader:Remove": {
let url = aData;
this.removeArticleFromCache(url, function(success) {
this.log("Reader:Remove success=" + success + ", url=" + url);
let args = JSON.parse(aData);
if (!("url" in args)) {
throw new Error("Reader:Remove requires URL as an argument");
}
this.removeArticleFromCache(args.url, function(success) {
this.log("Reader:Remove success=" + success + ", url=" + args.url);
if (success && args.notify) {
sendMessageToJava({
type: "Reader:Removed",
url: args.url
});
}
}.bind(this));
break;
}

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

@ -7,5 +7,4 @@
<!ENTITY aboutApps.browseMarketplace "Browse the Firefox Marketplace">
<!ENTITY aboutApps.uninstall "Uninstall">
<!ENTITY aboutApps.addToHomescreen "Add to Home Screen">
<!ENTITY aboutApps.checkForUpdates "Check for Updates">

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

@ -208,16 +208,53 @@ this.WebappManager = {
});
},
uninstall: function(aData) {
uninstall: Task.async(function*(aData, aMessageManager) {
debug("uninstall: " + aData.manifestURL);
yield DOMApplicationRegistry.registryReady;
if (this._testing) {
// We don't have to do anything, as the registry does all the work.
// Go directly to DOM. Do not uninstall APK, do not collect $200.
DOMApplicationRegistry.doUninstall(aData, aMessageManager);
return;
}
// TODO: uninstall the APK.
},
let app = DOMApplicationRegistry.getAppByManifestURL(aData.manifestURL);
if (!app) {
throw new Error("app not found in registry");
}
// If the APK is installed, then _getAPKVersions will return a version
// for it, so we can use that function to determine its install status.
let apkVersions = yield this._getAPKVersions([ app.apkPackageName ]);
if (app.apkPackageName in apkVersions) {
debug("APK is installed; requesting uninstallation");
sendMessageToJava({
type: "Webapps:UninstallApk",
apkPackageName: app.apkPackageName,
});
// We don't need to call DOMApplicationRegistry.doUninstall at this point,
// because the APK uninstall listener will call autoUninstall once the APK
// is uninstalled; and if the user cancels the APK uninstallation, then we
// shouldn't remove the app from the registry anyway.
// But we should tell the requesting document the result of their request.
// TODO: tell the requesting document if uninstallation succeeds or fails
// by storing weak references to the message/manager pair here and then
// using them in autoUninstall if they're still defined when it's called;
// and make EventListener.uninstallApk return an error when APK uninstall
// fails (which it should be able to detect reliably on Android 4+),
// which we observe here and use to notify the requester of failure.
} else {
// The APK isn't installed, but remove the app from the registry anyway,
// to ensure the user can always remove an app from the registry (and thus
// about:apps) even if it's out of sync with installed APKs.
debug("APK not installed; proceeding directly to removal from registry");
DOMApplicationRegistry.doUninstall(aData, aMessageManager);
}
}),
autoInstall: function(aData) {
debug("autoInstall " + aData.manifestURL);