зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central and fx-team
This commit is contained in:
Коммит
cd7094ef21
|
@ -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 {
|
||||
|
|
|
@ -7,13 +7,3 @@
|
|||
.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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче