Bug 957070 - move webapp event listeners/handlers from GeckoAppShell to webapp/ class; r=wesj

--HG--
rename : mobile/android/base/webapp/WebAppAllocator.java => mobile/android/base/webapp/Allocator.java
rename : mobile/android/base/webapp/WebAppDispatcher.java => mobile/android/base/webapp/Dispatcher.java
extra : rebase_source : a7e66abdf7738d1ae96a167bf6df7a58c208efa1
This commit is contained in:
Martyn Haigh 2014-01-24 21:57:13 -08:00
parent 9caeb09454
commit 14abcba732
13 changed files with 262 additions and 174 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please # changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more. # don't change CLOBBER for WebIDL changes any more.
Bug 948583, first part, apparently requires a clobber. (Ideas for fixing this involve removing jsopcode.tbl, which is a bit too big to do while holding up this patch.) Bug 957070 requires a clobber to resolve a reference to a program class member.

View File

@ -159,7 +159,7 @@
</activity> </activity>
#ifdef MOZ_ANDROID_SYNTHAPKS #ifdef MOZ_ANDROID_SYNTHAPKS
<activity android:name="org.mozilla.gecko.webapp.WebAppDispatcher" <activity android:name="org.mozilla.gecko.webapp.Dispatcher"
android:noHistory="true" > android:noHistory="true" >
<intent-filter> <intent-filter>
<!-- catch links from synthetic apks --> <!-- catch links from synthetic apks -->

View File

@ -29,6 +29,7 @@ import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask; import org.mozilla.gecko.util.UiAsyncTask;
import org.mozilla.gecko.webapp.UninstallListener; import org.mozilla.gecko.webapp.UninstallListener;
import org.mozilla.gecko.webapp.EventListener;
import org.mozilla.gecko.widget.ButtonToast; import org.mozilla.gecko.widget.ButtonToast;
import org.json.JSONArray; import org.json.JSONArray;
@ -633,34 +634,13 @@ public abstract class GeckoApp
final String title = message.getString("title"); final String title = message.getString("title");
final String type = message.getString("shortcutType"); final String type = message.getString("shortcutType");
GeckoAppShell.removeShortcut(title, url, origin, type); GeckoAppShell.removeShortcut(title, url, origin, type);
} else if (AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("WebApps:InstallApk")) {
GeckoAppShell.installApk(this, message.getString("filePath"), message.getString("data"));
} else if (!AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("WebApps:PreInstall")) { } else if (!AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("WebApps:PreInstall")) {
String name = message.getString("name"); String name = message.getString("name");
String manifestURL = message.getString("manifestURL"); String manifestURL = message.getString("manifestURL");
String origin = message.getString("origin"); String origin = message.getString("origin");
// preInstallWebapp will return a File object pointing to the profile directory of the webapp // preInstallWebapp will return a File object pointing to the profile directory of the webapp
mCurrentResponse = GeckoAppShell.preInstallWebApp(name, manifestURL, origin).toString(); mCurrentResponse = EventListener.preInstallWebApp(name, manifestURL, origin).toString();
} else if (event.equals("WebApps:PostInstall")) {
if (AppConstants.MOZ_ANDROID_SYNTHAPKS) {
GeckoAppShell.postInstallWebApp(message.getString("apkPackageName"), message.getString("origin"));
} else {
String name = message.getString("name");
String manifestURL = message.getString("manifestURL");
String iconURL = message.getString("iconURL");
String originalOrigin = message.getString("originalOrigin");
String origin = message.getString("origin");
GeckoAppShell.postInstallWebApp(name, manifestURL, origin, iconURL, originalOrigin);
}
} else if (event.equals("WebApps:Open")) {
String manifestURL = message.getString("manifestURL");
String origin = message.getString("origin");
Intent intent = GeckoAppShell.getWebAppIntent(manifestURL, origin, "", null);
if (intent == null)
return;
startActivity(intent);
} else if (!AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("WebApps:Uninstall")) {
GeckoAppShell.uninstallWebApp(message.getString("origin"));
} else if (event.equals("Share:Text")) { } else if (event.equals("Share:Text")) {
String text = message.getString("text"); String text = message.getString("text");
GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, ""); GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, "");
@ -1564,12 +1544,6 @@ public abstract class GeckoApp
registerEventListener("Accessibility:Event"); registerEventListener("Accessibility:Event");
registerEventListener("Accessibility:Ready"); registerEventListener("Accessibility:Ready");
registerEventListener("Shortcut:Remove"); registerEventListener("Shortcut:Remove");
// TODO Consider moving webapp install-related things into InstallHelper.
registerEventListener("WebApps:InstallApk");
registerEventListener("WebApps:PreInstall");
registerEventListener("WebApps:PostInstall");
registerEventListener("WebApps:Open");
registerEventListener("WebApps:Uninstall");
registerEventListener("Share:Text"); registerEventListener("Share:Text");
registerEventListener("Share:Image"); registerEventListener("Share:Image");
registerEventListener("Image:SetAs"); registerEventListener("Image:SetAs");
@ -1583,6 +1557,9 @@ public abstract class GeckoApp
registerEventListener("Intent:GetHandlers"); registerEventListener("Intent:GetHandlers");
registerEventListener("Locale:Set"); registerEventListener("Locale:Set");
registerEventListener("SystemUI:Visibility"); registerEventListener("SystemUI:Visibility");
registerEventListener("WebApps:PreInstall");
EventListener.registerEvents();
if (SmsManager.getInstance() != null) { if (SmsManager.getInstance() != null) {
SmsManager.getInstance().start(); SmsManager.getInstance().start();
@ -2095,11 +2072,6 @@ public abstract class GeckoApp
unregisterEventListener("Accessibility:Event"); unregisterEventListener("Accessibility:Event");
unregisterEventListener("Accessibility:Ready"); unregisterEventListener("Accessibility:Ready");
unregisterEventListener("Shortcut:Remove"); unregisterEventListener("Shortcut:Remove");
unregisterEventListener("WebApps:InstallApk");
unregisterEventListener("WebApps:PreInstall");
unregisterEventListener("WebApps:PostInstall");
unregisterEventListener("WebApps:Open");
unregisterEventListener("WebApps:Uninstall");
unregisterEventListener("Share:Text"); unregisterEventListener("Share:Text");
unregisterEventListener("Share:Image"); unregisterEventListener("Share:Image");
unregisterEventListener("Image:SetAs"); unregisterEventListener("Image:SetAs");
@ -2113,6 +2085,9 @@ public abstract class GeckoApp
unregisterEventListener("Intent:GetHandlers"); unregisterEventListener("Intent:GetHandlers");
unregisterEventListener("Locale:Set"); unregisterEventListener("Locale:Set");
unregisterEventListener("SystemUI:Visibility"); unregisterEventListener("SystemUI:Visibility");
unregisterEventListener("WebApps:PreInstall");
EventListener.unregisterEvents();
deleteTempFiles(); deleteTempFiles();

View File

@ -10,18 +10,19 @@ import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.gfx.GeckoLayerClient; import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PanZoomController; import org.mozilla.gecko.gfx.PanZoomController;
import org.mozilla.gecko.mozglue.JNITarget; import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter; import org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter;
import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI; import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
import org.mozilla.gecko.prompts.PromptService; import org.mozilla.gecko.mozglue.JNITarget;
import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.mozglue.RobocopTarget; import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.prompts.PromptService;
import org.mozilla.gecko.util.ActivityResultHandler; import org.mozilla.gecko.util.ActivityResultHandler;
import org.mozilla.gecko.util.EventDispatcher; import org.mozilla.gecko.util.EventDispatcher;
import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.HardwareUtils; import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.ProxySelector; import org.mozilla.gecko.util.ProxySelector;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.webapp.Allocator;
import org.mozilla.gecko.webapp.InstallListener; import org.mozilla.gecko.webapp.InstallListener;
import org.json.JSONException; import org.json.JSONException;
@ -718,34 +719,11 @@ public class GeckoAppShell
gRestartScheduled = true; gRestartScheduled = true;
} }
// The old implementation of preInstallWebApp. Not used by MOZ_ANDROID_SYNTHAPKS.
public static File preInstallWebApp(String aTitle, String aURI, String aOrigin) {
int index = WebAppAllocator.getInstance(getContext()).findAndAllocateIndex(aOrigin, aTitle, (String) null);
GeckoProfile profile = GeckoProfile.get(getContext(), "webapp" + index);
return profile.getDir();
}
// The old implementation of postInstallWebApp. Not used by MOZ_ANDROID_SYNTHAPKS.
public static void postInstallWebApp(String aTitle, String aURI, String aOrigin, String aIconURL, String aOriginalOrigin) {
WebAppAllocator allocator = WebAppAllocator.getInstance(getContext());
int index = allocator.getIndexForApp(aOriginalOrigin);
assert index != -1 && aIconURL != null;
allocator.updateAppAllocation(aOrigin, index, BitmapUtils.getBitmapFromDataURI(aIconURL));
createShortcut(aTitle, aURI, aOrigin, aIconURL, "webapp");
}
// The new implementation of postInstallWebApp. Used by MOZ_ANDROID_SYNTHAPKS.
public static void postInstallWebApp(String aPackageName, String aOrigin) {
org.mozilla.gecko.webapp.WebAppAllocator allocator = org.mozilla.gecko.webapp.WebAppAllocator.getInstance(getContext());
int index = allocator.findOrAllocatePackage(aPackageName);
allocator.putOrigin(index, aOrigin);
}
public static Intent getWebAppIntent(String aURI, String aOrigin, String aTitle, Bitmap aIcon) { public static Intent getWebAppIntent(String aURI, String aOrigin, String aTitle, Bitmap aIcon) {
Intent intent; Intent intent;
if (AppConstants.MOZ_ANDROID_SYNTHAPKS) { if (AppConstants.MOZ_ANDROID_SYNTHAPKS) {
org.mozilla.gecko.webapp.WebAppAllocator slots = org.mozilla.gecko.webapp.WebAppAllocator.getInstance(getContext()); Allocator slots = Allocator.getInstance(getContext());
int index = slots.getIndexForOrigin(aOrigin); int index = slots.getIndexForOrigin(aOrigin);
if (index == -1) { if (index == -1) {
@ -873,45 +851,6 @@ public class GeckoAppShell
}); });
} }
public static void uninstallWebApp(final String uniqueURI) {
// On uninstall, we need to do a couple of things:
// 1. nuke the running app process.
// 2. nuke the profile that was assigned to that webapp
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
int index;
if (AppConstants.MOZ_ANDROID_SYNTHAPKS) {
index = org.mozilla.gecko.webapp.WebAppAllocator.getInstance(getContext()).releaseIndexForApp(uniqueURI);
} else {
index = WebAppAllocator.getInstance(getContext()).releaseIndexForApp(uniqueURI);
}
// if -1, nothing to do; we didn't think it was installed anyway
if (index == -1)
return;
// kill the app if it's running
String targetProcessName = getContext().getPackageName();
targetProcessName = targetProcessName + ":" + targetProcessName + ".WebApp" + index;
ActivityManager am = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> procs = am.getRunningAppProcesses();
if (procs != null) {
for (ActivityManager.RunningAppProcessInfo proc : procs) {
if (proc.processName.equals(targetProcessName)) {
android.os.Process.killProcess(proc.pid);
break;
}
}
}
// then nuke the profile
GeckoProfile.removeProfile(getContext(), "webapp" + index);
}
});
}
@JNITarget @JNITarget
static public int getPreferredIconSize() { static public int getPreferredIconSize() {
if (android.os.Build.VERSION.SDK_INT >= 11) { if (android.os.Build.VERSION.SDK_INT >= 11) {
@ -2739,54 +2678,4 @@ public class GeckoAppShell
return "DIRECT"; return "DIRECT";
} }
public static void installApk(final Activity context, String filePath, String data) {
// This is the data that mozApps.install sent to Webapps.jsm.
JSONObject argsObj = null;
// We get the manifest url out of javascript here so we can use it as a checksum
// in a minute, when a package has been installed.
String manifestUrl = null;
try {
argsObj = new JSONObject(data);
manifestUrl = argsObj.getJSONObject("app").getString("manifestURL");
} catch (JSONException e) {
Log.e(LOGTAG, "can't get manifest URL from JSON data", e);
// TODO: propagate the error back to the mozApps.install caller.
return;
}
// We will check the manifestUrl from the one in the APK.
// Thus, we can have a one-to-one mapping of apk to receiver.
final InstallListener receiver = new InstallListener(manifestUrl, argsObj);
// Listen for packages being installed.
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
context.registerReceiver(receiver, filter);
// Now call the package installer.
File file = new File(filePath);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
sActivityHelper.startIntentForActivity(context, intent, new ActivityResultHandler() {
@Override
public void onActivityResult(int resultCode, Intent data) {
// The InstallListener will catch the case where the user pressed install.
// Now deal with if the user pressed cancel.
if (resultCode == Activity.RESULT_CANCELED) {
try {
context.unregisterReceiver(receiver);
receiver.cleanup();
} catch (java.lang.IllegalArgumentException e) {
// IllegalArgumentException happens because resultCode is RESULT_CANCELED
// when the user presses the Done button in the install confirmation dialog,
// even though the install has been successful (and InstallListener already
// unregistered the receiver).
Log.e(LOGTAG, "error unregistering install receiver: ", e);
}
}
}
});
}
} }

View File

@ -331,12 +331,13 @@ gbjar.sources += [
'updater/UpdateService.java', 'updater/UpdateService.java',
'updater/UpdateServiceHelper.java', 'updater/UpdateServiceHelper.java',
'VideoPlayer.java', 'VideoPlayer.java',
'webapp/Allocator.java',
'webapp/ApkResources.java', 'webapp/ApkResources.java',
'webapp/Dispatcher.java',
'webapp/EventListener.java',
'webapp/InstallHelper.java', 'webapp/InstallHelper.java',
'webapp/InstallListener.java', 'webapp/InstallListener.java',
'webapp/UninstallListener.java', 'webapp/UninstallListener.java',
'webapp/WebAppAllocator.java',
'webapp/WebAppDispatcher.java',
'webapp/WebAppImpl.java', 'webapp/WebAppImpl.java',
'WebAppAllocator.java', 'WebAppAllocator.java',
'WebAppImpl.java', 'WebAppImpl.java',

View File

@ -16,7 +16,7 @@ import java.util.ArrayList;
import android.util.Log; import android.util.Log;
public class WebAppAllocator { public class Allocator {
private final String LOGTAG = "GeckoWebAppAllocator"; private final String LOGTAG = "GeckoWebAppAllocator";
@ -26,14 +26,14 @@ public class WebAppAllocator {
// The number of WebApp# and WEBAPP# activites/apps/intents // The number of WebApp# and WEBAPP# activites/apps/intents
private final static int MAX_WEB_APPS = 100; private final static int MAX_WEB_APPS = 100;
protected static WebAppAllocator sInstance = null; protected static Allocator sInstance = null;
public static WebAppAllocator getInstance() { public static Allocator getInstance() {
return getInstance(GeckoAppShell.getContext()); return getInstance(GeckoAppShell.getContext());
} }
public static synchronized WebAppAllocator getInstance(Context cx) { public static synchronized Allocator getInstance(Context cx) {
if (sInstance == null) { if (sInstance == null) {
sInstance = new WebAppAllocator(cx); sInstance = new Allocator(cx);
} }
return sInstance; return sInstance;
@ -41,7 +41,7 @@ public class WebAppAllocator {
SharedPreferences mPrefs; SharedPreferences mPrefs;
protected WebAppAllocator(Context context) { protected Allocator(Context context) {
mPrefs = context.getSharedPreferences("webapps", Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS); mPrefs = context.getSharedPreferences("webapps", Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
} }

View File

@ -21,7 +21,7 @@ import android.os.Environment;
import android.util.Log; import android.util.Log;
public class ApkResources { public class ApkResources {
private static final String LOGTAG = "GeckoApkResources"; private static final String LOGTAG = "GeckoWebAppApkResources";
private final String mPackageName; private final String mPackageName;
private final ApplicationInfo mInfo; private final ApplicationInfo mInfo;
private final Context mContext; private final Context mContext;

View File

@ -8,20 +8,25 @@ package org.mozilla.gecko.webapp;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
public class WebAppDispatcher extends Activity { public class Dispatcher extends Activity {
private static final String LOGTAG = "GeckoWebAppDispatcher"; private static final String LOGTAG = "GeckoWebAppDispatcher";
@Override @Override
protected void onCreate(Bundle bundle) { protected void onCreate(Bundle bundle) {
super.onCreate(bundle); super.onCreate(bundle);
WebAppAllocator allocator = WebAppAllocator.getInstance(getApplicationContext()); Allocator allocator = Allocator.getInstance(getApplicationContext());
if (bundle == null) { if (bundle == null) {
bundle = getIntent().getExtras(); bundle = getIntent().getExtras();
} }
if (bundle == null) {
Log.e(LOGTAG, "Passed intent data missing.");
}
String packageName = bundle.getString("packageName"); String packageName = bundle.getString("packageName");
int index = allocator.getIndexForApp(packageName); int index = allocator.getIndexForApp(packageName);

View File

@ -0,0 +1,217 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.webapp;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.ActivityResultHandler;
import org.mozilla.gecko.util.EventDispatcher;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.WebAppAllocator;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;
import java.io.File;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class EventListener implements GeckoEventListener {
private static final String LOGTAG = "GeckoWebAppEventListener";
private EventListener() { }
private static EventListener mEventListener;
private static EventListener getEventListener() {
if (mEventListener == null) {
mEventListener = new EventListener();
}
return mEventListener;
}
private static void registerEventListener(String event) {
GeckoAppShell.getEventDispatcher().registerEventListener(event, EventListener.getEventListener());
}
private static void unregisterEventListener(String event) {
GeckoAppShell.getEventDispatcher().unregisterEventListener(event, EventListener.getEventListener());
}
public static void registerEvents() {
registerEventListener("WebApps:PreInstall");
registerEventListener("WebApps:InstallApk");
registerEventListener("WebApps:PostInstall");
registerEventListener("WebApps:Open");
registerEventListener("WebApps:Uninstall");
}
public static void unregisterEvents() {
unregisterEventListener("WebApps:PreInstall");
unregisterEventListener("WebApps:InstallApk");
unregisterEventListener("WebApps:PostInstall");
unregisterEventListener("WebApps:Open");
unregisterEventListener("WebApps:Uninstall");
}
@Override
public void handleMessage(String event, JSONObject message) {
try {
if (AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("WebApps:InstallApk")) {
installApk(GeckoAppShell.getGeckoInterface().getActivity(), message.getString("filePath"), message.getString("data"));
} else if (event.equals("WebApps:PostInstall")) {
if (AppConstants.MOZ_ANDROID_SYNTHAPKS) {
postInstallWebApp(message.getString("apkPackageName"), message.getString("origin"));
} else {
postInstallWebApp(message.getString("name"),
message.getString("manifestURL"),
message.getString("origin"),
message.getString("iconURL"),
message.getString("originalOrigin"));
}
} else if (event.equals("WebApps:Open")) {
Intent intent = GeckoAppShell.getWebAppIntent(message.getString("manifestURL"),
message.getString("origin"),
"", null);
if (intent == null) {
return;
}
GeckoAppShell.getGeckoInterface().getActivity().startActivity(intent);
} else if (!AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("WebApps:Uninstall")) {
uninstallWebApp(message.getString("origin"));
}
} catch (Exception e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
}
}
// Not used by MOZ_ANDROID_SYNTHAPKS.
public static File preInstallWebApp(String aTitle, String aURI, String aOrigin) {
int index = WebAppAllocator.getInstance(GeckoAppShell.getContext()).findAndAllocateIndex(aOrigin, aTitle, (String) null);
GeckoProfile profile = GeckoProfile.get(GeckoAppShell.getContext(), "webapp" + index);
return profile.getDir();
}
// Not used by MOZ_ANDROID_SYNTHAPKS.
public static void postInstallWebApp(String aTitle, String aURI, String aOrigin, String aIconURL, String aOriginalOrigin) {
WebAppAllocator allocator = WebAppAllocator.getInstance(GeckoAppShell.getContext());
int index = allocator.getIndexForApp(aOriginalOrigin);
assert aIconURL != null;
Bitmap icon = BitmapUtils.getBitmapFromDataURI(aIconURL);
assert aOrigin != null && index != -1;
allocator.updateAppAllocation(aOrigin, index, icon);
GeckoAppShell.createShortcut(aTitle, aURI, aOrigin, icon, "webapp");
}
// Used by MOZ_ANDROID_SYNTHAPKS.
public static void postInstallWebApp(String aPackageName, String aOrigin) {
Allocator allocator = Allocator.getInstance(GeckoAppShell.getContext());
int index = allocator.findOrAllocatePackage(aPackageName);
allocator.putOrigin(index, aOrigin);
}
public static void uninstallWebApp(final String uniqueURI) {
// On uninstall, we need to do a couple of things:
// 1. nuke the running app process.
// 2. nuke the profile that was assigned to that webapp
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
int index;
index = Allocator.getInstance(GeckoAppShell.getContext()).releaseIndexForApp(uniqueURI);
// if -1, nothing to do; we didn't think it was installed anyway
if (index == -1)
return;
// kill the app if it's running
String targetProcessName = GeckoAppShell.getContext().getPackageName();
targetProcessName = targetProcessName + ":" + targetProcessName + ".WebApp" + index;
ActivityManager am = (ActivityManager) GeckoAppShell.getContext().getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> procs = am.getRunningAppProcesses();
if (procs != null) {
for (ActivityManager.RunningAppProcessInfo proc : procs) {
if (proc.processName.equals(targetProcessName)) {
android.os.Process.killProcess(proc.pid);
break;
}
}
}
// then nuke the profile
GeckoProfile.removeProfile(GeckoAppShell.getContext(), "webapp" + index);
}
});
}
public static void installApk(final Activity context, String filePath, String data) {
// This is the data that mozApps.install sent to Webapps.jsm.
JSONObject argsObj = null;
// We get the manifest url out of javascript here so we can use it as a checksum
// in a minute, when a package has been installed.
String manifestUrl = null;
try {
argsObj = new JSONObject(data);
manifestUrl = argsObj.getJSONObject("app").getString("manifestURL");
} catch (JSONException e) {
Log.e(LOGTAG, "can't get manifest URL from JSON data", e);
// TODO: propagate the error back to the mozApps.install caller.
return;
}
// We will check the manifestUrl from the one in the APK.
// Thus, we can have a one-to-one mapping of apk to receiver.
final InstallListener receiver = new InstallListener(manifestUrl, argsObj);
// Listen for packages being installed.
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
context.registerReceiver(receiver, filter);
// Now call the package installer.
File file = new File(filePath);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
GeckoAppShell.sActivityHelper.startIntentForActivity(context, intent, new ActivityResultHandler() {
@Override
public void onActivityResult(int resultCode, Intent data) {
// The InstallListener will catch the case where the user pressed install.
// Now deal with if the user pressed cancel.
if (resultCode == Activity.RESULT_CANCELED) {
try {
context.unregisterReceiver(receiver);
receiver.cleanup();
} catch (java.lang.IllegalArgumentException e) {
// IllegalArgumentException happens because resultCode is RESULT_CANCELED
// when the user presses the Done button in the install confirmation dialog,
// even though the install has been successful (and InstallListener already
// unregistered the receiver).
Log.e(LOGTAG, "error unregistering install receiver: ", e);
}
}
}
});
}
}

View File

@ -27,7 +27,7 @@ import android.net.Uri;
import android.util.Log; import android.util.Log;
public class InstallHelper implements GeckoEventListener { public class InstallHelper implements GeckoEventListener {
private static final String LOGTAG = "GeckoInstallHelper"; private static final String LOGTAG = "GeckoWebAppInstallHelper";
private static final String[] INSTALL_EVENT_NAMES = new String[] {"WebApps:PostInstall"}; private static final String[] INSTALL_EVENT_NAMES = new String[] {"WebApps:PostInstall"};
private final Context mContext; private final Context mContext;
private final InstallCallback mCallback; private final InstallCallback mCallback;
@ -156,7 +156,7 @@ public class InstallHelper implements GeckoEventListener {
private void calculateColor() { private void calculateColor() {
ThreadUtils.assertOnBackgroundThread(); ThreadUtils.assertOnBackgroundThread();
WebAppAllocator slots = WebAppAllocator.getInstance(mContext); Allocator slots = Allocator.getInstance(mContext);
int index = slots.getIndexForApp(mApkResources.getPackageName()); int index = slots.getIndexForApp(mApkResources.getPackageName());
Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(mApkResources.getAppIcon()); Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(mApkResources.getAppIcon());
slots.updateColor(index, BitmapUtils.getDominantColor(bitmap)); slots.updateColor(index, BitmapUtils.getDominantColor(bitmap));

View File

@ -24,7 +24,7 @@ import android.util.Log;
public class InstallListener extends BroadcastReceiver { public class InstallListener extends BroadcastReceiver {
private static String LOGTAG = "GeckoInstallListener"; private static String LOGTAG = "GeckoWebAppInstallListener";
private JSONObject mData = null; private JSONObject mData = null;
private String mManifestUrl; private String mManifestUrl;
@ -63,9 +63,10 @@ public class InstallListener extends BroadcastReceiver {
if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) { if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
InstallHelper installHelper = new InstallHelper(context, apkResources, null); InstallHelper installHelper = new InstallHelper(context, apkResources, null);
try { try {
JSONObject dataObject = mData; JSONObject dataObject = new JSONObject();
dataObject = new JSONObject().put("request", dataObject); dataObject.put("request", mData);
WebAppAllocator slots = WebAppAllocator.getInstance(context);
Allocator slots = Allocator.getInstance(context);
int i = slots.findOrAllocatePackage(packageName); int i = slots.findOrAllocatePackage(packageName);
installHelper.startInstall("webapp" + i, dataObject); installHelper.startInstall("webapp" + i, dataObject);
} catch (JSONException e) { } catch (JSONException e) {

View File

@ -28,7 +28,7 @@ import java.util.ArrayList;
public class UninstallListener extends BroadcastReceiver { public class UninstallListener extends BroadcastReceiver {
private static String LOGTAG = "GeckoUninstallListener"; private static String LOGTAG = "GeckoWebAppUninstallListener";
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -39,7 +39,7 @@ public class UninstallListener extends BroadcastReceiver {
return; return;
} }
WebAppAllocator allocator = WebAppAllocator.getInstance(context); Allocator allocator = Allocator.getInstance(context);
ArrayList<String> installedPackages = allocator.getInstalledPackageNames(); ArrayList<String> installedPackages = allocator.getInstalledPackageNames();
if (installedPackages.contains(packageName)) { if (installedPackages.contains(packageName)) {
@ -57,7 +57,7 @@ public class UninstallListener extends BroadcastReceiver {
public static void initUninstallPackageScan(Context context) { public static void initUninstallPackageScan(Context context) {
// get list of packages we think are installed // get list of packages we think are installed
WebAppAllocator allocator = WebAppAllocator.getInstance(context); Allocator allocator = Allocator.getInstance(context);
ArrayList<String> fennecPackages = allocator.getInstalledPackageNames(); ArrayList<String> fennecPackages = allocator.getInstalledPackageNames();
ArrayList<String> uninstalledPackages = new ArrayList<String>(); ArrayList<String> uninstalledPackages = new ArrayList<String>();

View File

@ -100,7 +100,7 @@ public class WebAppImpl extends GeckoApp implements InstallCallback {
mTitlebar = findViewById(R.id.webapp_titlebar); mTitlebar = findViewById(R.id.webapp_titlebar);
mSplashscreen = findViewById(R.id.splashscreen); mSplashscreen = findViewById(R.id.splashscreen);
String origin = WebAppAllocator.getInstance(this).getOrigin(getIndex()); String origin = Allocator.getInstance(this).getOrigin(getIndex());
boolean isInstallCompleting = (origin == null); boolean isInstallCompleting = (origin == null);
if (!GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning) || !isInstalled || isInstallCompleting) { if (!GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning) || !isInstalled || isInstallCompleting) {
@ -154,7 +154,7 @@ public class WebAppImpl extends GeckoApp implements InstallCallback {
private void showSplash(boolean isApk) { private void showSplash(boolean isApk) {
// get the favicon dominant color, stored when the app was installed // get the favicon dominant color, stored when the app was installed
int dominantColor = WebAppAllocator.getInstance().getColor(getIndex()); int dominantColor = Allocator.getInstance().getColor(getIndex());
setBackgroundGradient(dominantColor); setBackgroundGradient(dominantColor);