зеркало из https://github.com/mozilla/gecko-dev.git
Bug 834681 - Add support for basic distribution modifications. r=mfinkle
This commit is contained in:
Родитель
91cbf694b0
Коммит
ce0533c704
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче