mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-19 15:51:33 +00:00
Bug 1019054 - re-add uninstallation from about:apps context menu; r=mfinkle,marco
This commit is contained in:
parent
d0bb84f99d
commit
78814e0a21
@ -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);
|
||||
|
@ -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"/>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user