Bug 834681 - Add support for basic distribution modifications. r=mfinkle

This commit is contained in:
Margaret Leibovic 2013-02-01 15:45:33 -08:00
Родитель 91cbf694b0
Коммит ce0533c704
6 изменённых файлов: 199 добавлений и 19 удалений

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

@ -239,6 +239,8 @@ abstract public class BrowserApp extends GeckoApp
registerEventListener("Feedback:MaybeLater");
registerEventListener("Dex:Load");
registerEventListener("Telemetry:Gather");
Distribution.init(this);
}
@Override

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

@ -0,0 +1,92 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
*
* 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/.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import org.mozilla.gecko.util.GeckoBackgroundThread;
import android.app.Activity;
import android.content.SharedPreferences;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.Exception;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public final class Distribution {
private static final String LOGTAG = "Distribution";
/**
* Initializes distribution if it hasn't already been initalized.
*/
public static void init(final Activity activity) {
// Read/write preferences and files on the background thread.
GeckoBackgroundThread.getHandler().post(new Runnable() {
public void run() {
// Bail if we've already initialized the distribution.
SharedPreferences settings = activity.getPreferences(Activity.MODE_PRIVATE);
String keyName = activity.getPackageName() + ".distribution_initialized";
if (settings.getBoolean(keyName, false))
return;
settings.edit().putBoolean(keyName, true).commit();
try {
copyFiles(activity);
} catch (IOException e) {
Log.e(LOGTAG, "Error copying distribution files", e);
}
}
});
}
/**
* Copies the /distribution folder out of the APK and into the app's data directory.
*/
private static void copyFiles(Activity activity) throws IOException {
File applicationPackage = new File(activity.getPackageResourcePath());
ZipFile zip = new ZipFile(applicationPackage);
Enumeration<? extends ZipEntry> zipEntries = zip.entries();
while (zipEntries.hasMoreElements()) {
ZipEntry fileEntry = zipEntries.nextElement();
String name = fileEntry.getName();
if (!name.startsWith("distribution/"))
continue;
File dataDir = new File(activity.getApplicationInfo().dataDir);
File outFile = new File(dataDir, name);
File dir = outFile.getParentFile();
if (!dir.exists())
dir.mkdirs();
InputStream fileStream = zip.getInputStream(fileEntry);
OutputStream outStream = new FileOutputStream(outFile);
int b;
while ((b = fileStream.read()) != -1)
outStream.write(b);
fileStream.close();
outStream.close();
outFile.setLastModified(fileEntry.getTime());
}
zip.close();
}
}

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

@ -65,6 +65,7 @@ FENNEC_JAVA_FILES = \
db/BrowserDB.java \
db/LocalBrowserDB.java \
db/DBUtils.java \
Distribution.java \
DoorHanger.java \
DoorHangerPopup.java \
Favicons.java \

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

@ -8135,37 +8135,25 @@ var Distribution = {
init: function dc_init() {
Services.obs.addObserver(this, "Distribution:Set", false);
Services.obs.addObserver(this, "prefservice:after-app-defaults", false);
// Reload the default prefs so we can observe "prefservice:after-app-defaults"
Services.prefs.QueryInterface(Ci.nsIObserver).observe(null, "reload-default-prefs", null);
// Look for file outside the APK:
// /data/data/org.mozilla.fennec/distribution.json
this._file = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
this._file.append("distribution.json");
if (this._file.exists()) {
let channel = NetUtil.newChannel(this._file);
channel.contentType = "application/json";
NetUtil.asyncFetch(channel, function(aStream, aResult) {
if (!Components.isSuccessCode(aResult)) {
Cu.reportError("Distribution: Could not read from distribution.json file");
return;
}
let raw = NetUtil.readInputStreamToString(aStream, aStream.available(), { charset : "UTF-8" }) || "";
aStream.close();
try {
this.update(JSON.parse(raw));
} catch (ex) {
Cu.reportError("Distribution: Could not parse JSON: " + ex);
}
}.bind(this));
}
this.readJSON(this._file, this.update);
},
uninit: function dc_uninit() {
Services.obs.removeObserver(this, "Distribution:Set");
Services.obs.removeObserver(this, "prefservice:after-app-defaults");
},
observe: function dc_observe(aSubject, aTopic, aData) {
// This event is only used for campaign tracking
if (aTopic == "Distribution:Set") {
// Update the prefs for this session
try {
@ -8185,6 +8173,8 @@ var Distribution = {
// Asynchronously copy the data to the file.
let istream = converter.convertToInputStream(aData);
NetUtil.asyncCopy(istream, ostream, function(rc) { });
} else if (aTopic == "prefservice:after-app-defaults") {
this.getPrefs();
}
},
@ -8193,6 +8183,99 @@ var Distribution = {
let defaults = Services.prefs.getDefaultBranch(null);
defaults.setCharPref("distribution.id", aData.id);
defaults.setCharPref("distribution.version", aData.version);
},
getPrefs: function dc_getPrefs() {
// Look for preferences file outside the APK:
// /data/data/org.mozilla.fennec/distribution/preferences.json
let file = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
file.append("distribution");
file.append("preferences.json");
this.readJSON(file, this.applyPrefs);
},
applyPrefs: function dc_applyPrefs(aData) {
// Check for required Global preferences
let global = aData["Global"];
if (!(global && global["id"] && global["version"] && global["about"])) {
Cu.reportError("Distribution: missing or incomplete Global preferences");
return;
}
// Force the distribution preferences on the default branch
let defaults = Services.prefs.getDefaultBranch(null);
defaults.setCharPref("distribution.id", global["id"]);
defaults.setCharPref("distribution.version", global["version"]);
let locale = Services.prefs.getCharPref("general.useragent.locale");
let aboutString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
aboutString.data = global["about." + locale] || global["about"];
defaults.setComplexValue("distribution.about", Ci.nsISupportsString, aboutString);
let prefs = aData["Preferences"];
for (let key in prefs) {
try {
let value = prefs[key];
switch (typeof value) {
case "boolean":
defaults.setBoolPref(key, value);
break;
case "number":
defaults.setIntPref(key, value);
break;
case "string":
case "undefined":
defaults.setCharPref(key, value);
break;
}
} catch (e) { /* ignore bad prefs and move on */ }
}
let localizedString = Cc["@mozilla.org/pref-localizedstring;1"].createInstance(Ci.nsIPrefLocalizedString);
let localizeablePrefs = aData["LocalizablePreferences"];
for (let key in localizeablePrefs) {
try {
let value = localizeablePrefs[key];
value = value.replace("%LOCALE%", locale, "g");
localizedString.data = "data:text/plain," + key + "=" + value;
defaults.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedString);
} catch (e) { /* ignore bad prefs and move on */ }
}
let localizeablePrefsOverrides = aData["LocalizablePreferences." + locale];
for (let key in localizeablePrefsOverrides) {
try {
let value = localizeablePrefsOverrides[key];
localizedString.data = "data:text/plain," + key + "=" + value;
defaults.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedString);
} catch (e) { /* ignore bad prefs and move on */ }
}
},
// aFile is an nsIFile
// aCallback takes the parsed JSON object as a parameter
readJSON: function dc_readJSON(aFile, aCallback) {
if (!aFile.exists())
return;
let channel = NetUtil.newChannel(aFile);
channel.contentType = "application/json";
NetUtil.asyncFetch(channel, function(aStream, aResult) {
if (!Components.isSuccessCode(aResult)) {
Cu.reportError("Distribution: Could not read from " + aFile.leafName + " file");
return;
}
let raw = NetUtil.readInputStreamToString(aStream, aStream.available(), { charset : "UTF-8" }) || "";
aStream.close();
try {
aCallback(JSON.parse(raw));
} catch (e) {
Cu.reportError("Distribution: Could not parse JSON: " + e);
}
});
}
};

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

@ -58,6 +58,7 @@
@BINPATH@/res/drawable-hdpi
@BINPATH@/res/layout
@BINPATH@/recommended-addons.json
@BINPATH@/distribution/*
[browser]
; [Base Browser Files]

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

@ -294,6 +294,7 @@ DIST_FILES += \
update.locale \
removed-files \
recommended-addons.json \
distribution \
$(NULL)
ifdef MOZ_ENABLE_SZIP