mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 22:05:44 +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.
|
// Registers all the activities and system messages.
|
||||||
registerAppsHandlers: function(aRunUpdate) {
|
registerAppsHandlers: Task.async(function*(aRunUpdate) {
|
||||||
this.notifyAppsRegistryStart();
|
this.notifyAppsRegistryStart();
|
||||||
let ids = [];
|
let ids = [];
|
||||||
for (let id in this.webapps) {
|
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
|
// Read the CSPs and roles. If MOZ_SYS_MSG is defined this is done on
|
||||||
// _processManifestForIds so as to not reading the manifests
|
// _processManifestForIds so as to not reading the manifests
|
||||||
// twice
|
// twice
|
||||||
this._readManifests(ids).then((aResults) => {
|
let results = yield this._readManifests(ids);
|
||||||
aResults.forEach((aResult) => {
|
results.forEach((aResult) => {
|
||||||
if (!aResult.manifest) {
|
if (!aResult.manifest) {
|
||||||
// If we can't load the manifest, we probably have a corrupted
|
// 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.
|
// registry. We delete the app since we can't do anything with it.
|
||||||
delete this.webapps[aResult.id];
|
delete this.webapps[aResult.id];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let app = this.webapps[aResult.id];
|
let app = this.webapps[aResult.id];
|
||||||
app.csp = aResult.manifest.csp || "";
|
app.csp = aResult.manifest.csp || "";
|
||||||
app.role = aResult.manifest.role || "";
|
app.role = aResult.manifest.role || "";
|
||||||
if (app.appStatus >= Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
|
if (app.appStatus >= Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
|
||||||
app.redirects = this.sanitizeRedirects(aResult.redirects);
|
app.redirects = this.sanitizeRedirects(aResult.redirects);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Nothing else to do but notifying we're ready.
|
// Nothing else to do but notifying we're ready.
|
||||||
this.notifyAppsRegistryReady();
|
this.notifyAppsRegistryReady();
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
|
|
||||||
updateDataStoreForApp: function(aId) {
|
updateDataStoreForApp: Task.async(function*(aId) {
|
||||||
if (!this.webapps[aId]) {
|
if (!this.webapps[aId]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create or Update the DataStore for this app
|
// Create or Update the DataStore for this app
|
||||||
this._readManifests([{ id: aId }]).then((aResult) => {
|
let results = yield this._readManifests([{ id: aId }]);
|
||||||
let app = this.webapps[aId];
|
let app = this.webapps[aId];
|
||||||
this.updateDataStore(app.localId, app.origin, app.manifestURL,
|
this.updateDataStore(app.localId, app.origin, app.manifestURL,
|
||||||
aResult[0].manifest, app.appStatus);
|
results[0].manifest, app.appStatus);
|
||||||
});
|
}),
|
||||||
},
|
|
||||||
|
|
||||||
updatePermissionsForApp: function(aId, aIsPreinstalled) {
|
updatePermissionsForApp: function(aId, aIsPreinstalled) {
|
||||||
if (!this.webapps[aId]) {
|
if (!this.webapps[aId]) {
|
||||||
@ -609,10 +607,10 @@ this.DOMApplicationRegistry = {
|
|||||||
|
|
||||||
// DataStores must be initialized at startup.
|
// DataStores must be initialized at startup.
|
||||||
for (let id in this.webapps) {
|
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);
|
}.bind(this)).then(null, Cu.reportError);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1101,7 +1099,11 @@ this.DOMApplicationRegistry = {
|
|||||||
this.getSelf(msg, mm);
|
this.getSelf(msg, mm);
|
||||||
break;
|
break;
|
||||||
case "Webapps:Uninstall":
|
case "Webapps:Uninstall":
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
Services.obs.notifyObservers(mm, "webapps-runtime-uninstall", JSON.stringify(msg));
|
||||||
|
#else
|
||||||
this.doUninstall(msg, mm);
|
this.doUninstall(msg, mm);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case "Webapps:Launch":
|
case "Webapps:Launch":
|
||||||
this.doLaunch(msg, mm);
|
this.doLaunch(msg, mm);
|
||||||
|
@ -31,6 +31,7 @@ import android.content.IntentFilter;
|
|||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class EventListener implements NativeEventListener {
|
public class EventListener implements NativeEventListener {
|
||||||
@ -41,6 +42,7 @@ public class EventListener implements NativeEventListener {
|
|||||||
EventDispatcher.getInstance().registerGeckoThreadListener(this,
|
EventDispatcher.getInstance().registerGeckoThreadListener(this,
|
||||||
"Webapps:Preinstall",
|
"Webapps:Preinstall",
|
||||||
"Webapps:InstallApk",
|
"Webapps:InstallApk",
|
||||||
|
"Webapps:UninstallApk",
|
||||||
"Webapps:Postinstall",
|
"Webapps:Postinstall",
|
||||||
"Webapps:Open",
|
"Webapps:Open",
|
||||||
"Webapps:Uninstall",
|
"Webapps:Uninstall",
|
||||||
@ -51,6 +53,7 @@ public class EventListener implements NativeEventListener {
|
|||||||
EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
|
EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
|
||||||
"Webapps:Preinstall",
|
"Webapps:Preinstall",
|
||||||
"Webapps:InstallApk",
|
"Webapps:InstallApk",
|
||||||
|
"Webapps:UninstallApk",
|
||||||
"Webapps:Postinstall",
|
"Webapps:Postinstall",
|
||||||
"Webapps:Open",
|
"Webapps:Open",
|
||||||
"Webapps:Uninstall",
|
"Webapps:Uninstall",
|
||||||
@ -62,6 +65,8 @@ public class EventListener implements NativeEventListener {
|
|||||||
try {
|
try {
|
||||||
if (event.equals("Webapps:InstallApk")) {
|
if (event.equals("Webapps:InstallApk")) {
|
||||||
installApk(GeckoAppShell.getGeckoInterface().getActivity(), message, callback);
|
installApk(GeckoAppShell.getGeckoInterface().getActivity(), message, callback);
|
||||||
|
} else if (event.equals("Webapps:UninstallApk")) {
|
||||||
|
uninstallApk(GeckoAppShell.getGeckoInterface().getActivity(), message);
|
||||||
} else if (event.equals("Webapps:Postinstall")) {
|
} else if (event.equals("Webapps:Postinstall")) {
|
||||||
postInstallWebapp(message.getString("apkPackageName"), message.getString("origin"));
|
postInstallWebapp(message.getString("apkPackageName"), message.getString("origin"));
|
||||||
} else if (event.equals("Webapps:Open")) {
|
} 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;
|
private static final int DEFAULT_VERSION_CODE = -1;
|
||||||
|
|
||||||
public static JSONObject getApkVersions(Activity context, String[] packageNames) {
|
public static JSONObject getApkVersions(Activity context, String[] packageNames) {
|
||||||
|
@ -47,6 +47,29 @@ function checkForUpdates(aEvent) {
|
|||||||
WebappManager.checkForUpdates(true);
|
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) {
|
function onLoad(aEvent) {
|
||||||
let elmts = document.querySelectorAll("[pref]");
|
let elmts = document.querySelectorAll("[pref]");
|
||||||
for (let i = 0; i < elmts.length; i++) {
|
for (let i = 0; i < elmts.length; i++) {
|
||||||
@ -59,6 +82,8 @@ function onLoad(aEvent) {
|
|||||||
navigator.mozApps.mgmt.onuninstall = onUninstall;
|
navigator.mozApps.mgmt.onuninstall = onUninstall;
|
||||||
updateList();
|
updateList();
|
||||||
|
|
||||||
|
ContextMenus.init();
|
||||||
|
|
||||||
// XXX - Hack to fix bug 985867 for now
|
// XXX - Hack to fix bug 985867 for now
|
||||||
document.addEventListener("touchstart", function() { });
|
document.addEventListener("touchstart", function() { });
|
||||||
}
|
}
|
||||||
@ -84,6 +109,7 @@ function addApplication(aApp) {
|
|||||||
|
|
||||||
let container = document.createElement("div");
|
let container = document.createElement("div");
|
||||||
container.className = "app list-item";
|
container.className = "app list-item";
|
||||||
|
container.setAttribute("contextmenu", "appmenu");
|
||||||
container.setAttribute("id", "app-" + aApp.origin);
|
container.setAttribute("id", "app-" + aApp.origin);
|
||||||
container.setAttribute("mozApp", aApp.origin);
|
container.setAttribute("mozApp", aApp.origin);
|
||||||
container.setAttribute("title", manifest.name);
|
container.setAttribute("title", manifest.name);
|
||||||
|
@ -28,6 +28,11 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body dir="&locale.dir;">
|
<body dir="&locale.dir;">
|
||||||
|
|
||||||
|
<menu type="context" id="appmenu">
|
||||||
|
<menuitem id="uninstallLabel" label="&aboutApps.uninstall;"></menuitem>
|
||||||
|
</menu>
|
||||||
|
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div>&aboutApps.header;</div>
|
<div>&aboutApps.header;</div>
|
||||||
<div id="header-button" role="button" aria-label="&aboutApps.browseMarketplace;" pref="app.marketplaceURL"/>
|
<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-runtime-install-package", false);
|
||||||
Services.obs.addObserver(this, "webapps-ask-install", false);
|
Services.obs.addObserver(this, "webapps-ask-install", false);
|
||||||
Services.obs.addObserver(this, "webapps-launch", 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:AutoInstall", false);
|
||||||
Services.obs.addObserver(this, "Webapps:Load", false);
|
Services.obs.addObserver(this, "Webapps:Load", false);
|
||||||
Services.obs.addObserver(this, "Webapps:AutoUninstall", false);
|
Services.obs.addObserver(this, "Webapps:AutoUninstall", false);
|
||||||
@ -1631,8 +1631,8 @@ var BrowserApp = {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "webapps-uninstall": {
|
case "webapps-runtime-uninstall": {
|
||||||
WebappManager.uninstall(JSON.parse(aData));
|
WebappManager.uninstall(JSON.parse(aData), aSubject);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,5 +7,4 @@
|
|||||||
|
|
||||||
<!ENTITY aboutApps.browseMarketplace "Browse the Firefox Marketplace">
|
<!ENTITY aboutApps.browseMarketplace "Browse the Firefox Marketplace">
|
||||||
<!ENTITY aboutApps.uninstall "Uninstall">
|
<!ENTITY aboutApps.uninstall "Uninstall">
|
||||||
<!ENTITY aboutApps.addToHomescreen "Add to Home Screen">
|
|
||||||
<!ENTITY aboutApps.checkForUpdates "Check for Updates">
|
<!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);
|
debug("uninstall: " + aData.manifestURL);
|
||||||
|
|
||||||
|
yield DOMApplicationRegistry.registryReady;
|
||||||
|
|
||||||
if (this._testing) {
|
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;
|
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) {
|
autoInstall: function(aData) {
|
||||||
debug("autoInstall " + aData.manifestURL);
|
debug("autoInstall " + aData.manifestURL);
|
||||||
|
Loading…
Reference in New Issue
Block a user