Bug 1021342 - Eliminate non-synthetic web app code. r=myk,mfinkle

This commit is contained in:
Richard Newman 2014-06-10 10:37:38 -07:00
Родитель 607b2c646c
Коммит aa3662b743
24 изменённых файлов: 38 добавлений и 860 удалений

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

@ -3941,7 +3941,6 @@ MOZ_USE_NATIVE_POPUP_WINDOWS=
MOZ_ANDROID_HISTORY=
MOZ_WEBSMS_BACKEND=
MOZ_ANDROID_BEAM=
MOZ_ANDROID_SYNTHAPKS=
MOZ_LOCALE_SWITCHER=
ACCESSIBILITY=1
MOZ_TIME_MANAGER=
@ -4966,18 +4965,6 @@ if test -n "$MOZ_ANDROID_BEAM"; then
AC_DEFINE(MOZ_ANDROID_BEAM)
fi
dnl ========================================================
dnl = Synthesized Webapp APKs on Android
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(android-synthapks,
[ --enable-android-synthapks Enable synthesized APKs],
MOZ_ANDROID_SYNTHAPKS=1,
MOZ_ANDROID_SYNTHAPKS=)
if test -n "$MOZ_ANDROID_SYNTHAPKS"; then
AC_DEFINE(MOZ_ANDROID_SYNTHAPKS)
fi
dnl ========================================================
dnl = JS Debugger XPCOM component (js/jsd)
dnl ========================================================
@ -8574,7 +8561,6 @@ AC_SUBST(MOZ_METRO)
AC_SUBST(MOZ_ANDROID_HISTORY)
AC_SUBST(MOZ_WEBSMS_BACKEND)
AC_SUBST(MOZ_ANDROID_BEAM)
AC_SUBST(MOZ_ANDROID_SYNTHAPKS)
AC_SUBST(MOZ_LOCALE_SWITCHER)
AC_SUBST(MOZ_DISABLE_GECKOVIEW)
AC_SUBST(ENABLE_STRIP)

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

@ -71,7 +71,7 @@ function _setAppProperties(aObj, aApp) {
aObj.csp = aApp.csp;
aObj.installOrigin = aApp.installOrigin;
aObj.origin = aApp.origin;
#ifdef MOZ_ANDROID_SYNTHAPKS
#ifdef MOZ_WIDGET_ANDROID
aObj.apkPackageName = aApp.apkPackageName;
#endif
aObj.receipts = aApp.receipts ? JSON.parse(JSON.stringify(aApp.receipts)) : null;

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

@ -1090,7 +1090,7 @@ this.DOMApplicationRegistry = {
switch (aMessage.name) {
case "Webapps:Install": {
#ifdef MOZ_ANDROID_SYNTHAPKS
#ifdef MOZ_WIDGET_ANDROID
Services.obs.notifyObservers(mm, "webapps-runtime-install", JSON.stringify(msg));
#else
this.doInstall(msg, mm);
@ -1119,7 +1119,7 @@ this.DOMApplicationRegistry = {
this.doGetAll(msg, mm);
break;
case "Webapps:InstallPackage": {
#ifdef MOZ_ANDROID_SYNTHAPKS
#ifdef MOZ_WIDGET_ANDROID
Services.obs.notifyObservers(mm, "webapps-runtime-install-package", JSON.stringify(msg));
#else
this.doInstallPackage(msg, mm);
@ -2510,15 +2510,15 @@ this.DOMApplicationRegistry = {
} else if (manifest.package_path) {
// If it is a local app then it must been installed from a local file
// instead of web.
#ifdef MOZ_ANDROID_SYNTHAPKS
// In that case, we would already have the manifest, not just the update
// manifest.
#ifdef MOZ_WIDGET_ANDROID
dontNeedNetwork = !!aData.app.manifest;
#else
if (aData.app.localInstallPath) {
dontNeedNetwork = true;
jsonManifest.package_path = "file://" + aData.app.localInstallPath;
}
}
#endif
// origin for install apps is meaningless here, since it's app:// and this

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

@ -825,7 +825,6 @@ pref("browser.snippets.statsUrl", "https://snippets-stats.mozilla.org/mobile");
pref("browser.snippets.enabled", true);
pref("browser.snippets.syncPromo.enabled", true);
#ifdef MOZ_ANDROID_SYNTHAPKS
// The URL of the APK factory from which we obtain APKs for webapps.
pref("browser.webapps.apkFactoryUrl", "https://controller.apk.firefox.com/application.apk");
@ -850,8 +849,6 @@ pref("browser.webapps.checkForUpdates", 1);
// which is a test server that always reports all apps as having updates.
pref("browser.webapps.updateCheckUrl", "https://controller.apk.firefox.com/app_updates");
#endif
// The mode of home provider syncing.
// 0: Sync always
// 1: Sync only when on wifi

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

@ -188,7 +188,6 @@
</intent-filter>
</activity>
#ifdef MOZ_ANDROID_SYNTHAPKS
<activity android:name="org.mozilla.gecko.webapp.Dispatcher"
android:noHistory="true" >
<intent-filter>
@ -212,7 +211,6 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
#endif
<activity android:name=".Webapp"
android:label="@string/webapp_generic_name"

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

@ -149,13 +149,6 @@ public class AppConstants {
false;
#endif
public static final boolean MOZ_ANDROID_SYNTHAPKS =
#ifdef MOZ_ANDROID_SYNTHAPKS
true;
#else
false;
#endif
// See this wiki page for more details about channel specific build defines:
// https://wiki.mozilla.org/Platform/Channel-specific_build_defines
public static final boolean RELEASE_BUILD =

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

@ -793,41 +793,19 @@ public class GeckoAppShell
public static Intent getWebappIntent(String aURI, String aOrigin, String aTitle, Bitmap aIcon) {
Intent intent;
if (AppConstants.MOZ_ANDROID_SYNTHAPKS) {
Allocator slots = Allocator.getInstance(getContext());
int index = slots.getIndexForOrigin(aOrigin);
Allocator slots = Allocator.getInstance(getContext());
int index = slots.getIndexForOrigin(aOrigin);
if (index == -1) {
return null;
}
String packageName = slots.getAppForIndex(index);
intent = getContext().getPackageManager().getLaunchIntentForPackage(packageName);
if (aURI != null) {
intent.setData(Uri.parse(aURI));
}
} else {
int index;
if (aIcon != null && !TextUtils.isEmpty(aTitle))
index = WebappAllocator.getInstance(getContext()).findAndAllocateIndex(aOrigin, aTitle, aIcon);
else
index = WebappAllocator.getInstance(getContext()).getIndexForApp(aOrigin);
if (index == -1)
return null;
intent = getWebappIntent(index, aURI);
if (index == -1) {
return null;
}
return intent;
}
String packageName = slots.getAppForIndex(index);
intent = getContext().getPackageManager().getLaunchIntentForPackage(packageName);
if (aURI != null) {
intent.setData(Uri.parse(aURI));
}
// The old implementation of getWebappIntent. Not used by MOZ_ANDROID_SYNTHAPKS.
public static Intent getWebappIntent(int aIndex, String aURI) {
Intent intent = new Intent();
intent.setAction(GeckoApp.ACTION_WEBAPP_PREFIX + aIndex);
intent.setData(Uri.parse(aURI));
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
AppConstants.ANDROID_PACKAGE_NAME + ".WebApps$WebApp" + aIndex);
return intent;
}

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

@ -6,11 +6,7 @@
#filter substitution
package @ANDROID_PACKAGE_NAME@;
#ifdef MOZ_ANDROID_SYNTHAPKS
import org.mozilla.gecko.webapp.WebappImpl;
#else
import org.mozilla.gecko.WebappImpl;
#endif
/**
* This class serves only as a namespace wrapper for WebappImpl.

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

@ -1,132 +0,0 @@
/* -*- 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;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.ThreadUtils;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.util.Log;
import java.util.ArrayList;
public class WebappAllocator {
private final String LOGTAG = "GeckoWebappAllocator";
// The number of Webapp# and WEBAPP# activites/apps/intents
private final static int MAX_WEB_APPS = 100;
protected static WebappAllocator sInstance = null;
public static WebappAllocator getInstance() {
return getInstance(GeckoAppShell.getContext());
}
public static synchronized WebappAllocator getInstance(Context cx) {
if (sInstance == null) {
sInstance = new WebappAllocator(cx);
}
return sInstance;
}
SharedPreferences mPrefs;
protected WebappAllocator(Context context) {
mPrefs = context.getSharedPreferences("webapps", Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
}
public static String appKey(int index) {
return "app" + index;
}
static public String iconKey(int index) {
return "icon" + index;
}
public synchronized int findAndAllocateIndex(String app, String name, String aIconData) {
Bitmap icon = (aIconData != null) ? BitmapUtils.getBitmapFromDataURI(aIconData) : null;
return findAndAllocateIndex(app, name, icon);
}
public synchronized int findAndAllocateIndex(final String app, final String name, final Bitmap aIcon) {
int index = getIndexForApp(app);
if (index != -1)
return index;
for (int i = 0; i < MAX_WEB_APPS; ++i) {
if (!mPrefs.contains(appKey(i))) {
// found unused index i
updateAppAllocation(app, i, aIcon);
return i;
}
}
// no more apps!
return -1;
}
public synchronized void updateAppAllocation(final String app,
final int index,
final Bitmap aIcon) {
if (aIcon != null) {
ThreadUtils.getBackgroundHandler().post(new Runnable() {
@Override
public void run() {
int color = 0;
try {
color = BitmapUtils.getDominantColor(aIcon);
} catch (Exception e) {
Log.e(LOGTAG, "Exception during getDominantColor", e);
}
mPrefs.edit()
.putString(appKey(index), app)
.putInt(iconKey(index), color).commit();
}
});
} else {
mPrefs.edit()
.putString(appKey(index), app)
.putInt(iconKey(index), 0).commit();
}
}
public synchronized int getIndexForApp(String app) {
for (int i = 0; i < MAX_WEB_APPS; ++i) {
if (mPrefs.getString(appKey(i), "").equals(app)) {
return i;
}
}
return -1;
}
public synchronized String getAppForIndex(int index) {
return mPrefs.getString(appKey(index), null);
}
public synchronized int releaseIndexForApp(String app) {
int index = getIndexForApp(app);
if (index == -1)
return -1;
releaseIndex(index);
return index;
}
public synchronized void releaseIndex(final int index) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
mPrefs.edit()
.remove(appKey(index))
.remove(iconKey(index))
.commit();
}
});
}
}

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

@ -1,221 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.RelativeLayout;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.view.animation.AnimationUtils;
import android.view.animation.Animation;
import android.widget.ImageView;
import android.view.Display;
import java.io.File;
import java.net.URI;
public class WebappImpl extends GeckoApp {
private static final String LOGTAG = "GeckoWebappImpl";
private URI mOrigin;
private TextView mTitlebarText = null;
private View mTitlebar = null;
private View mSplashscreen;
protected int getIndex() { return 0; }
@Override
public int getLayout() { return R.layout.web_app; }
@Override
public boolean hasTabsSideBar() { return false; }
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mSplashscreen = (RelativeLayout) findViewById(R.id.splashscreen);
if (!GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
overridePendingTransition(R.anim.grow_fade_in_center, android.R.anim.fade_out);
showSplash();
}
String action = getIntent().getAction();
Bundle extras = getIntent().getExtras();
String title = extras != null ? extras.getString(Intent.EXTRA_SHORTCUT_NAME) : null;
setTitle(title != null ? title : "Web App");
mTitlebarText = (TextView)findViewById(R.id.webapp_title);
mTitlebar = findViewById(R.id.webapp_titlebar);
if (!action.startsWith(ACTION_WEBAPP_PREFIX)) {
Log.e(LOGTAG, "Webapp launch, but intent action is " + action + "!");
return;
}
// Try to use the origin stored in the WebappAllocator first
String origin = WebappAllocator.getInstance(this).getAppForIndex(getIndex());
try {
mOrigin = new URI(origin);
} catch (java.net.URISyntaxException ex) {
// If we can't parse the this is an app protocol, just settle for not having an origin
if (!origin.startsWith("app://")) {
return;
}
// If that failed fall back to the origin stored in the shortcut
Log.i(LOGTAG, "Webapp is not registered with allocator");
try {
mOrigin = new URI(getIntent().getData().toString());
} catch (java.net.URISyntaxException ex2) {
Log.e(LOGTAG, "Unable to parse intent url: ", ex);
}
}
}
@Override
protected void loadStartupTab(String uri) {
String action = getIntent().getAction();
if (GeckoApp.ACTION_WEBAPP_PREFIX.equals(action)) {
// This action assumes the uri is not an installed Webapp. We will
// use the WebappAllocator to register the uri with an Android
// process so it can run chromeless.
int index = WebappAllocator.getInstance(this).findAndAllocateIndex(uri, "App", (Bitmap) null);
Intent appIntent = GeckoAppShell.getWebappIntent(index, uri);
startActivity(appIntent);
finish();
}
}
private void showSplash() {
SharedPreferences prefs = getSharedPreferences("webapps", Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
// get the favicon dominant color, stored when the app was installed
int[] colors = new int[2];
int dominantColor = prefs.getInt(WebappAllocator.iconKey(getIndex()), -1);
// now lighten it, to ensure that the icon stands out in the center
float[] f = new float[3];
Color.colorToHSV(dominantColor, f);
f[2] = Math.min(f[2]*2, 1.0f);
colors[0] = Color.HSVToColor(255, f);
// now generate a second, slightly darker version of the same color
f[2] *= 0.75;
colors[1] = Color.HSVToColor(255, f);
// Draw the background gradient
GradientDrawable gd = new GradientDrawable(GradientDrawable.Orientation.TL_BR, colors);
gd.setGradientType(GradientDrawable.RADIAL_GRADIENT);
Display display = getWindowManager().getDefaultDisplay();
gd.setGradientCenter(0.5f, 0.5f);
gd.setGradientRadius(Math.max(display.getWidth()/2, display.getHeight()/2));
mSplashscreen.setBackgroundDrawable((Drawable)gd);
// look for a logo.png in the profile dir and show it. If we can't find a logo show nothing
File profile = getProfile().getDir();
File logoFile = new File(profile, "logo.png");
if (logoFile.exists()) {
ImageView image = (ImageView)findViewById(R.id.splashscreen_icon);
Drawable d = Drawable.createFromPath(logoFile.getPath());
image.setImageDrawable(d);
Animation fadein = AnimationUtils.loadAnimation(this, R.anim.grow_fade_in_center);
fadein.setStartOffset(500);
fadein.setDuration(1000);
image.startAnimation(fadein);
}
}
@Override
protected String getDefaultProfileName() {
String action = getIntent().getAction();
if (!action.startsWith(ACTION_WEBAPP_PREFIX)) {
Log.e(LOGTAG, "Webapp launch, but intent action is " + action + "!");
return null;
}
return "webapp" + action.substring(ACTION_WEBAPP_PREFIX.length());
}
@Override
protected boolean getSessionRestoreState(Bundle savedInstanceState) {
// for now webapps never restore your session
return false;
}
@Override
public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
switch(msg) {
case SELECTED:
case LOCATION_CHANGE:
if (Tabs.getInstance().isSelectedTab(tab)) {
final String urlString = tab.getURL();
final URI uri;
try {
uri = new URI(urlString);
} catch (java.net.URISyntaxException ex) {
mTitlebarText.setText(urlString);
// If we can't parse the url, and its an app protocol hide
// the titlebar and return, otherwise show the titlebar
// and the full url
if (!urlString.startsWith("app://")) {
mTitlebar.setVisibility(View.VISIBLE);
} else {
mTitlebar.setVisibility(View.GONE);
}
return;
}
if (mOrigin != null && mOrigin.getHost().equals(uri.getHost())) {
mTitlebar.setVisibility(View.GONE);
} else {
mTitlebarText.setText(uri.getScheme() + "://" + uri.getHost());
mTitlebar.setVisibility(View.VISIBLE);
}
}
break;
case LOADED:
if (mSplashscreen != null && mSplashscreen.getVisibility() == View.VISIBLE) {
Animation fadeout = AnimationUtils.loadAnimation(this, android.R.anim.fade_out);
fadeout.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
mSplashscreen.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation animation) { }
@Override
public void onAnimationStart(Animation animation) { }
});
mSplashscreen.startAnimation(fadeout);
}
break;
case START:
if (mSplashscreen != null && mSplashscreen.getVisibility() == View.VISIBLE) {
View area = findViewById(R.id.splashscreen_progress);
area.setVisibility(View.VISIBLE);
Animation fadein = AnimationUtils.loadAnimation(this, android.R.anim.fade_in);
fadein.setDuration(1000);
area.startAnimation(fadein);
}
break;
}
super.onTabChanged(tab, msg, data);
}
};

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

@ -4,19 +4,6 @@
android:windowSoftInputMode="stateUnspecified|adjustResize"
android:process=":@ANDROID_PACKAGE_NAME@.Webapp@APPNUM@"
android:theme="@style/Gecko.App"
#ifdef MOZ_ANDROID_SYNTHAPKS
android:launchMode="singleTop"
android:exported="true"
/>
#else
android:launchMode="singleTask"
android:taskAffinity="org.mozilla.gecko.WEBAPP@APPNUM@"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="org.mozilla.gecko.WEBAPP@APPNUM@" />
</intent-filter>
<intent-filter>
<action android:name="org.mozilla.gecko.ACTION_ALERT_CALLBACK" />
</intent-filter>
</activity>
#endif

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

@ -404,8 +404,6 @@ gbjar.sources += [
'webapp/TaskKiller.java',
'webapp/UninstallListener.java',
'webapp/WebappImpl.java',
'WebappAllocator.java',
'WebappImpl.java',
'widget/ActivityChooserModel.java',
'widget/AllCapsTextView.java',
'widget/AnimatedHeightLayout.java',

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

@ -5,33 +5,6 @@
package org.mozilla.gecko.webapp;
import org.mozilla.gecko.ActivityHandlerHelper;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.ActivityResultHandler;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
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.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
@ -40,6 +13,25 @@ import java.util.Set;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.ActivityHandlerHelper;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.util.ActivityResultHandler;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
import org.mozilla.gecko.util.ThreadUtils;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.util.Log;
public class EventListener implements NativeEventListener {
@ -68,18 +60,10 @@ public class EventListener implements NativeEventListener {
@Override
public void handleMessage(String event, NativeJSObject message, EventCallback callback) {
try {
if (AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("Webapps:InstallApk")) {
if (event.equals("Webapps:InstallApk")) {
installApk(GeckoAppShell.getGeckoInterface().getActivity(), message, callback);
} 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"));
}
postInstallWebapp(message.getString("apkPackageName"), message.getString("origin"));
} else if (event.equals("Webapps:Open")) {
Intent intent = GeckoAppShell.getWebappIntent(message.getString("manifestURL"),
message.getString("origin"),
@ -88,16 +72,6 @@ public class EventListener implements NativeEventListener {
return;
}
GeckoAppShell.getGeckoInterface().getActivity().startActivity(intent);
} else if (!AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("Webapps:Uninstall")) {
uninstallWebapp(message.getString("origin"));
} else if (!AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("Webapps:Preinstall")) {
String name = message.getString("name");
String manifestURL = message.getString("manifestURL");
String origin = message.getString("origin");
JSONObject obj = new JSONObject();
obj.put("profile", preInstallWebapp(name, manifestURL, origin).toString());
callback.sendSuccess(obj);
} else if (event.equals("Webapps:GetApkVersions")) {
JSONObject obj = new JSONObject();
obj.put("versions", getApkVersions(GeckoAppShell.getGeckoInterface().getActivity(),
@ -109,30 +83,6 @@ public class EventListener implements NativeEventListener {
}
}
// 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;
final int preferredSize = GeckoAppShell.getPreferredIconSize();
Bitmap icon = FaviconDecoder.getMostSuitableBitmapFromDataURI(aIconURL, preferredSize);
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);

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

@ -147,9 +147,7 @@ public class UninstallListener extends BroadcastReceiver {
ThreadUtils.assertOnBackgroundThread();
// Perform webapp uninstalls as appropiate.
if (AppConstants.MOZ_ANDROID_SYNTHAPKS) {
UninstallListener.initUninstallPackageScan(mApp.getApplicationContext());
}
UninstallListener.initUninstallPackageScan(mApp.getApplicationContext());
}
}
}

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

@ -11,11 +11,9 @@ Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
Cu.import("resource://gre/modules/PermissionPromptHelper.jsm");
Cu.import("resource://gre/modules/ContactService.jsm");
#ifdef MOZ_ANDROID_SYNTHAPKS
Cu.import("resource://gre/modules/AppsUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Notifications", "resource://gre/modules/Notifications.jsm");
#endif
function pref(name, value) {
return {
@ -70,14 +68,12 @@ let WebappRT = {
});
}
#ifdef MOZ_ANDROID_SYNTHAPKS
// If the app is in debug mode, configure and enable the remote debugger.
sendMessageToJava({ type: "NativeApp:IsDebuggable" }, (response) => {
if (response.isDebuggable) {
this._enableRemoteDebugger(aUrl);
}
});
#endif
this.findManifestUrlFor(aUrl, aCallback);
},
@ -163,7 +159,6 @@ let WebappRT = {
}
},
#ifdef MOZ_ANDROID_SYNTHAPKS
_enableRemoteDebugger: function(aUrl) {
// Skip the connection prompt in favor of notifying the user below.
Services.prefs.setBoolPref("devtools.debugger.prompt-connection", false);
@ -195,7 +190,6 @@ let WebappRT = {
});
});
},
#endif
handleEvent: function(event) {
let target = event.target;

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

@ -12,9 +12,7 @@ Cu.import("resource://gre/modules/Services.jsm")
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
#ifdef MOZ_ANDROID_SYNTHAPKS
XPCOMUtils.defineLazyModuleGetter(this, "WebappManager", "resource://gre/modules/WebappManager.jsm");
#endif
const DEFAULT_ICON = "chrome://browser/skin/images/default-app-icon.png";
@ -45,51 +43,9 @@ function openLink(aEvent) {
} catch (ex) {}
}
#ifdef MOZ_ANDROID_SYNTHAPKS
function checkForUpdates(aEvent) {
WebappManager.checkForUpdates(true);
}
#endif
#ifndef MOZ_ANDROID_SYNTHAPKS
var ContextMenus = {
target: null,
init: function() {
document.addEventListener("contextmenu", this, false);
document.getElementById("addToHomescreenLabel").addEventListener("click", this.addToHomescreen, false);
document.getElementById("uninstallLabel").addEventListener("click", this.uninstall, 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;
}
},
addToHomescreen: function() {
let manifest = this.target.manifest;
gChromeWin.WebappsUI.createShortcut(manifest.name, manifest.fullLaunchPath(), manifest.biggestIconURL || DEFAULT_ICON, "webapp");
this.target = null;
},
uninstall: function() {
navigator.mozApps.mgmt.uninstall(this.target.app);
let manifest = this.target.manifest;
gChromeWin.sendMessageToJava({
type: "Shortcut:Remove",
title: manifest.name,
url: manifest.fullLaunchPath(),
origin: this.target.app.origin,
shortcutType: "webapp"
});
this.target = null;
}
}
#endif
function onLoad(aEvent) {
let elmts = document.querySelectorAll("[pref]");
@ -97,17 +53,11 @@ function onLoad(aEvent) {
elmts[i].addEventListener("click", openLink, false);
}
#ifdef MOZ_ANDROID_SYNTHAPKS
document.getElementById("update-item").addEventListener("click", checkForUpdates, false);
#endif
navigator.mozApps.mgmt.oninstall = onInstall;
navigator.mozApps.mgmt.onuninstall = onUninstall;
updateList();
#ifndef MOZ_ANDROID_SYNTHAPKS
ContextMenus.init();
#endif
}
function updateList() {
@ -131,9 +81,6 @@ function addApplication(aApp) {
let container = document.createElement("div");
container.className = "app list-item";
#ifndef MOZ_ANDROID_SYNTHAPKS
container.setAttribute("contextmenu", "appmenu");
#endif
container.setAttribute("id", "app-" + aApp.origin);
container.setAttribute("mozApp", aApp.origin);
container.setAttribute("title", manifest.name);

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

@ -28,14 +28,6 @@
</head>
<body dir="&locale.dir;">
#ifndef MOZ_ANDROID_SYNTHAPKS
<menu type="context" id="appmenu">
<menuitem id="addToHomescreenLabel" label="&aboutApps.addToHomescreen;"></menuitem>
<menuitem id="uninstallLabel" label="&aboutApps.uninstall;"></menuitem>
</menu>
#endif
<div class="header">
<div>&aboutApps.header;</div>
<div id="header-button" role="button" aria-label="&aboutApps.browseMarketplace;" pref="app.marketplaceURL"/>
@ -55,13 +47,11 @@
<div id="browse-title" class="title">&aboutApps.browseMarketplace;</div>
</div>
</div>
#ifdef MOZ_ANDROID_SYNTHAPKS
<div class="list-item" id="update-item" role="button">
<img class="icon" src="chrome://browser/skin/images/update.png" />
<div class="inner">
<div id="browse-title" class="title">&aboutApps.checkForUpdates;</div>
</div>
</div>
#endif
</body>
</html>

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

@ -77,10 +77,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "ShumwayUtils",
"resource://shumway/ShumwayUtils.jsm");
#endif
#ifdef MOZ_ANDROID_SYNTHAPKS
XPCOMUtils.defineLazyModuleGetter(this, "WebappManager",
"resource://gre/modules/WebappManager.jsm");
#endif
XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
"resource://gre/modules/CharsetMenu.jsm");
@ -326,7 +324,6 @@ var BrowserApp = {
Services.obs.addObserver(this, "FormHistory:Init", false);
Services.obs.addObserver(this, "gather-telemetry", false);
Services.obs.addObserver(this, "keyword-search", false);
#ifdef MOZ_ANDROID_SYNTHAPKS
Services.obs.addObserver(this, "webapps-runtime-install", false);
Services.obs.addObserver(this, "webapps-runtime-install-package", false);
Services.obs.addObserver(this, "webapps-ask-install", false);
@ -335,7 +332,6 @@ var BrowserApp = {
Services.obs.addObserver(this, "Webapps:AutoInstall", false);
Services.obs.addObserver(this, "Webapps:Load", false);
Services.obs.addObserver(this, "Webapps:AutoUninstall", false);
#endif
Services.obs.addObserver(this, "sessionstore-state-purge-complete", false);
function showFullScreenWarning() {
@ -377,13 +373,9 @@ var BrowserApp = {
XPInstallObserver.init();
CharacterEncoding.init();
ActivityObserver.init();
#ifdef MOZ_ANDROID_SYNTHAPKS
// TODO: replace with Android implementation of WebappOSUtils.isLaunchable.
Cu.import("resource://gre/modules/Webapps.jsm");
DOMApplicationRegistry.allAppsLaunchable = true;
#else
WebappsUI.init();
#endif
RemoteDebugger.init();
Reader.init();
UserAgentOverrides.init();
@ -770,9 +762,6 @@ var BrowserApp = {
HealthReportStatusListener.uninit();
CharacterEncoding.uninit();
SearchEngines.uninit();
#ifndef MOZ_ANDROID_SYNTHAPKS
WebappsUI.uninit();
#endif
RemoteDebugger.uninit();
Reader.uninit();
UserAgentOverrides.uninit();
@ -961,7 +950,6 @@ var BrowserApp = {
sendMessageToJava(message);
},
#ifdef MOZ_ANDROID_SYNTHAPKS
_loadWebapp: function(aMessage) {
this._initRuntime(this._startupStatus, aMessage.url, aUrl => {
@ -969,7 +957,6 @@ var BrowserApp = {
this.addTab(aUrl, { title: aMessage.name });
});
},
#endif
// Calling this will update the state in BrowserApp after a tab has been
// closed in the Java UI.
@ -1627,7 +1614,6 @@ var BrowserApp = {
this.notifyPrefObservers(aData);
break;
#ifdef MOZ_ANDROID_SYNTHAPKS
case "webapps-runtime-install":
WebappManager.install(JSON.parse(aData), aSubject);
break;
@ -1661,7 +1647,6 @@ var BrowserApp = {
case "Webapps:AutoUninstall":
WebappManager.autoUninstall(JSON.parse(aData));
break;
#endif
case "Locale:Changed":
if (aData) {
@ -7034,246 +7019,6 @@ var ActivityObserver = {
}
};
#ifndef MOZ_ANDROID_SYNTHAPKS
var WebappsUI = {
init: function init() {
Cu.import("resource://gre/modules/Webapps.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
DOMApplicationRegistry.allAppsLaunchable = true;
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-install-error", false);
},
uninit: function unint() {
Services.obs.removeObserver(this, "webapps-ask-install");
Services.obs.removeObserver(this, "webapps-launch");
Services.obs.removeObserver(this, "webapps-uninstall");
Services.obs.removeObserver(this, "webapps-install-error");
},
DEFAULT_ICON: "chrome://browser/skin/images/default-app-icon.png",
DEFAULT_PREFS_FILENAME: "default-prefs.js",
observe: function observe(aSubject, aTopic, aData) {
let data = {};
try {
data = JSON.parse(aData);
data.mm = aSubject;
} catch(ex) { }
switch (aTopic) {
case "webapps-install-error":
let msg = "";
switch (aData) {
case "INVALID_MANIFEST":
case "MANIFEST_PARSE_ERROR":
msg = Strings.browser.GetStringFromName("webapps.manifestInstallError");
break;
case "NETWORK_ERROR":
case "MANIFEST_URL_ERROR":
msg = Strings.browser.GetStringFromName("webapps.networkInstallError");
break;
default:
msg = Strings.browser.GetStringFromName("webapps.installError");
}
NativeWindow.toast.show(msg, "short");
console.log("Error installing app: " + aData);
break;
case "webapps-ask-install":
this.doInstall(data);
break;
case "webapps-launch":
this.openURL(data.manifestURL, data.origin);
break;
case "webapps-uninstall":
sendMessageToJava({
type: "Webapps:Uninstall",
origin: data.origin
});
break;
}
},
doInstall: function doInstall(aData) {
let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
let manifest = new ManifestHelper(jsonManifest, aData.app.origin);
if (Services.prompt.confirm(null, Strings.browser.GetStringFromName("webapps.installTitle"), manifest.name + "\n" + aData.app.origin)) {
// Get a profile for the app to be installed in. We'll download everything before creating the icons.
let origin = aData.app.origin;
sendMessageToJava({
type: "Webapps:Preinstall",
name: manifest.name,
manifestURL: aData.app.manifestURL,
origin: origin
}, (data) => {
let profilePath = data.profile;
if (!profilePath)
return;
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath(profilePath);
let self = this;
DOMApplicationRegistry.confirmInstall(aData, file,
function (aManifest) {
let localeManifest = new ManifestHelper(aManifest, aData.app.origin);
// the manifest argument is the manifest from within the zip file,
// TODO so now would be a good time to ask about permissions.
self.makeBase64Icon(localeManifest.biggestIconURL || this.DEFAULT_ICON,
function(scaledIcon, fullsizeIcon) {
// if java returned a profile path to us, try to use it to pre-populate the app cache
// also save the icon so that it can be used in the splash screen
try {
let iconFile = file.clone();
iconFile.append("logo.png");
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
persist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
let source = Services.io.newURI(fullsizeIcon, "UTF8", null);
persist.saveURI(source, null, null, null, null, iconFile, null);
// aData.app.origin may now point to the app: url that hosts this app
sendMessageToJava({
type: "Webapps:Postinstall",
name: localeManifest.name,
manifestURL: aData.app.manifestURL,
originalOrigin: origin,
origin: aData.app.origin,
iconURL: fullsizeIcon
});
if (!!aData.isPackage) {
// For packaged apps, put a notification in the notification bar.
let message = Strings.browser.GetStringFromName("webapps.alertSuccess");
let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
alerts.showAlertNotification("drawable://alert_app", localeManifest.name, message, true, "", {
observe: function () {
self.openURL(aData.app.manifestURL, aData.app.origin);
}
}, "webapp");
}
// Create a system notification allowing the user to launch the app
let observer = {
observe: function (aSubject, aTopic) {
if (aTopic == "alertclickcallback") {
WebappsUI.openURL(aData.app.manifestURL, origin);
}
}
};
let message = Strings.browser.GetStringFromName("webapps.alertSuccess");
let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
alerts.showAlertNotification("drawable://alert_app", localeManifest.name, message, true, "", observer, "webapp");
} catch(ex) {
console.log(ex);
}
self.writeDefaultPrefs(file, localeManifest);
}
);
}
);
});
} else {
DOMApplicationRegistry.denyInstall(aData);
}
},
writeDefaultPrefs: function webapps_writeDefaultPrefs(aProfile, aManifest) {
// build any app specific default prefs
let prefs = [];
if (aManifest.orientation) {
prefs.push({name:"app.orientation.default", value: aManifest.orientation.join(",") });
}
// write them into the app profile
let defaultPrefsFile = aProfile.clone();
defaultPrefsFile.append(this.DEFAULT_PREFS_FILENAME);
this._writeData(defaultPrefsFile, prefs);
},
_writeData: function(aFile, aPrefs) {
if (aPrefs.length > 0) {
let array = new TextEncoder().encode(JSON.stringify(aPrefs));
OS.File.writeAtomic(aFile.path, array, { tmpPath: aFile.path + ".tmp" }).then(null, function onError(reason) {
console.log("Error writing default prefs: " + reason);
});
}
},
openURL: function openURL(aManifestURL, aOrigin) {
sendMessageToJava({
type: "Webapps:Open",
manifestURL: aManifestURL,
origin: aOrigin
});
},
get iconSize() {
let iconSize = 64;
try {
let jni = new JNI();
let cls = jni.findClass("org/mozilla/gecko/GeckoAppShell");
let method = jni.getStaticMethodID(cls, "getPreferredIconSize", "()I");
iconSize = jni.callStaticIntMethod(cls, method);
jni.close();
} catch(ex) {
console.log(ex);
}
delete this.iconSize;
return this.iconSize = iconSize;
},
makeBase64Icon: function loadAndMakeBase64Icon(aIconURL, aCallbackFunction) {
let size = this.iconSize;
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
canvas.width = canvas.height = size;
let ctx = canvas.getContext("2d");
let favicon = new Image();
favicon.onload = function() {
ctx.drawImage(favicon, 0, 0, size, size);
let scaledIcon = canvas.toDataURL("image/png", "");
canvas.width = favicon.width;
canvas.height = favicon.height;
ctx.drawImage(favicon, 0, 0, favicon.width, favicon.height);
let fullsizeIcon = canvas.toDataURL("image/png", "");
canvas = null;
aCallbackFunction.call(null, scaledIcon, fullsizeIcon);
};
favicon.onerror = function() {
Cu.reportError("CreateShortcut: favicon image load error");
// if the image failed to load, and it was not our default icon, attempt to
// use our default as a fallback
if (favicon.src != WebappsUI.DEFAULT_ICON) {
favicon.src = WebappsUI.DEFAULT_ICON;
}
};
favicon.src = aIconURL;
},
createShortcut: function createShortcut(aTitle, aURL, aIconURL, aType) {
this.makeBase64Icon(aIconURL, function _createShortcut(icon) {
try {
let shell = Cc["@mozilla.org/browser/shell-service;1"].createInstance(Ci.nsIShellService);
shell.createShortcut(aTitle, aURL, icon, aType);
} catch(e) {
Cu.reportError(e);
}
});
}
}
#endif
var RemoteDebugger = {
init: function rd_init() {
Services.prefs.addObserver("devtools.debugger.", this, false);

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

@ -113,12 +113,10 @@ contract @mozilla.org/snippets;1 {a78d7e59-b558-4321-a3d6-dffe2f1e76dd}
category profile-after-change Snippets @mozilla.org/snippets;1
category update-timer Snippets @mozilla.org/snippets;1,getService,snippets-update-timer,browser.snippets.updateInterval,86400
#ifdef MOZ_ANDROID_SYNTHAPKS
# WebappsUpdateTimer.js
component {8f7002cb-e959-4f0a-a2e8-563232564385} WebappsUpdateTimer.js
contract @mozilla.org/webapps-update-timer;1 {8f7002cb-e959-4f0a-a2e8-563232564385}
category update-timer WebappsUpdateTimer @mozilla.org/webapps-update-timer;1,getService,webapp-background-update-timer,browser.webapps.updateInterval,86400
#endif
# ColorPicker.js
component {430b987f-bb9f-46a3-99a5-241749220b29} ColorPicker.js

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

@ -67,8 +67,5 @@ MOZ_DATA_REPORTING=1
# Enable runtime locale switching.
MOZ_LOCALE_SWITCHER=1
# Enable the "synthetic APKs" implementation of Open Web Apps.
MOZ_ANDROID_SYNTHAPKS=1
# Enable second screen and casting support for external devices.
MOZ_DEVICES=1

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

@ -621,10 +621,7 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
@BINPATH@/components/marionettecomponent.js
#endif
#ifdef MOZ_ANDROID_SYNTHAPKS
@BINPATH@/components/WebappsUpdateTimer.js
#endif
@BINPATH@/components/DataStore.manifest
@BINPATH@/components/DataStoreImpl.js
@BINPATH@/components/dom_datastore.xpt

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

@ -242,16 +242,6 @@ timer.start=%S: timer started
# %1$S=name of timer, %2$S=number of milliseconds
timer.end=%1$S: %2$Sms
# Webapps
webapps.installTitle=Install Application
webapps.alertSuccess=Successfully installed
# Shown when there is a generic problem installing an app
webapps.installError=Error installing application
# Shown when there is something wrong with an apps manifest
webapps.manifestInstallError=Invalid application manifest
# Shown when a network error prevented installing an app
webapps.networkInstallError=Could not download manifest
# Click to play plugins
clickToPlayPlugins.message2=%S contains plugin content. Would you like to activate it?
clickToPlayPlugins.activate=Activate

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

@ -37,9 +37,7 @@
locale/@AB_CD@/browser/phishing.dtd (%chrome/phishing.dtd)
locale/@AB_CD@/browser/payments.properties (%chrome/payments.properties)
locale/@AB_CD@/browser/handling.properties (%chrome/handling.properties)
#ifdef MOZ_ANDROID_SYNTHAPKS
locale/@AB_CD@/browser/webapp.properties (%chrome/webapp.properties)
#endif
# overrides for toolkit l10n, also for en-US
relativesrcdir toolkit/locales:

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

@ -22,16 +22,10 @@ EXTRA_JS_MODULES += [
'SharedPreferences.jsm',
'SimpleServiceDiscovery.jsm',
'SSLExceptions.jsm',
'WebappManagerWorker.js',
]
EXTRA_PP_JS_MODULES += [
'RokuApp.jsm',
'WebappManager.jsm',
]
if CONFIG['MOZ_ANDROID_SYNTHAPKS']:
EXTRA_PP_JS_MODULES += [
'WebappManager.jsm',
]
EXTRA_JS_MODULES += [
'WebappManagerWorker.js',
]