summaryrefslogtreecommitdiffstats
path: root/mobile/android/services/src/main/java/org/mozilla/gecko/background
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/services/src/main/java/org/mozilla/gecko/background')
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/ReadingListConstants.java23
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/EditorBranch.java82
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/GlobalConstants.java90
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/PrefsBranch.java83
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/Logger.java232
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLevelCachingLogWriter.java132
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLogWriter.java46
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LevelFilteringLogWriter.java67
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LogWriter.java29
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/PrintLogWriter.java77
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/SimpleTagLogWriter.java21
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/StringLogWriter.java57
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/TagLogWriter.java55
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/ThreadLocalTagLogWriter.java25
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/common/telemetry/TelemetryWrapper.java56
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/db/CursorDumper.java99
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/db/Tab.java86
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java52
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java36
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient.java24
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java914
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClientException.java133
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountRemoteError.java33
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java217
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/PasswordStretcher.java12
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java35
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/SkewHandler.java111
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountAbstractClient.java224
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountAbstractClientException.java68
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountOAuthClient10.java129
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountOAuthRemoteError.java19
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/profile/FxAccountProfileClient10.java59
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/nativecode/NativeCrypto.java60
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/preferences/PreferenceFragment.java326
-rw-r--r--mobile/android/services/src/main/java/org/mozilla/gecko/background/preferences/PreferenceManagerCompat.java226
35 files changed, 0 insertions, 3938 deletions
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/ReadingListConstants.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/ReadingListConstants.java
deleted file mode 100644
index df603a58e..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/ReadingListConstants.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/* 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.background;
-
-import org.mozilla.gecko.AppConstants;
-
-/**
- * This is in 'background' not 'reading' so that it's still usable even when the
- * Reading List feature is build-time disabled.
- */
-public class ReadingListConstants {
- public static final String GLOBAL_LOG_TAG = "FxReadingList";
- public static final String USER_AGENT = "Firefox-Android-FxReader/" + AppConstants.MOZ_APP_VERSION + " (" + AppConstants.MOZ_APP_UA_NAME + ")";
- public static final String DEFAULT_DEV_ENDPOINT = "https://readinglist.dev.mozaws.net/v1/";
- public static final String DEFAULT_PROD_ENDPOINT = "https://readinglist.services.mozilla.com/v1/";
-
- public static final String OAUTH_SCOPE_READINGLIST = "readinglist";
- public static final String AUTH_TOKEN_TYPE = "oauth::" + OAUTH_SCOPE_READINGLIST;
-
- public static boolean DEBUG = false;
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/EditorBranch.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/EditorBranch.java
deleted file mode 100644
index 1ead09afa..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/EditorBranch.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/* 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.background.common;
-
-import java.util.Set;
-
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-
-public class EditorBranch implements Editor {
-
- private final String prefix;
- private Editor editor;
-
- public EditorBranch(final SharedPreferences prefs, final String prefix) {
- if (!prefix.endsWith(".")) {
- throw new IllegalArgumentException("No trailing period in prefix.");
- }
- this.prefix = prefix;
- this.editor = prefs.edit();
- }
-
- @Override
- public void apply() {
- this.editor.apply();
- }
-
- @Override
- public Editor clear() {
- this.editor = this.editor.clear();
- return this;
- }
-
- @Override
- public boolean commit() {
- return this.editor.commit();
- }
-
- @Override
- public Editor putBoolean(String key, boolean value) {
- this.editor = this.editor.putBoolean(prefix + key, value);
- return this;
- }
-
- @Override
- public Editor putFloat(String key, float value) {
- this.editor = this.editor.putFloat(prefix + key, value);
- return this;
- }
-
- @Override
- public Editor putInt(String key, int value) {
- this.editor = this.editor.putInt(prefix + key, value);
- return this;
- }
-
- @Override
- public Editor putLong(String key, long value) {
- this.editor = this.editor.putLong(prefix + key, value);
- return this;
- }
-
- @Override
- public Editor putString(String key, String value) {
- this.editor = this.editor.putString(prefix + key, value);
- return this;
- }
-
- // Not marking as Override, because Android <= 10 doesn't have
- // putStringSet. Neither can we implement it.
- public Editor putStringSet(String key, Set<String> value) {
- throw new RuntimeException("putStringSet not available.");
- }
-
- @Override
- public Editor remove(String key) {
- this.editor = this.editor.remove(prefix + key);
- return this;
- }
-} \ No newline at end of file
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/GlobalConstants.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/GlobalConstants.java
deleted file mode 100644
index d661e62dc..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/GlobalConstants.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/* 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.background.common;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.AppConstants.Versions;
-
-/**
- * Constant values common to all Android services.
- */
-public class GlobalConstants {
- public static final String BROWSER_INTENT_PACKAGE = AppConstants.ANDROID_PACKAGE_NAME;
- public static final String BROWSER_INTENT_CLASS = AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS;
-
- public static final int SHARED_PREFERENCES_MODE = 0;
-
- // Common time values.
- public static final long MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
- public static final long MILLISECONDS_PER_SIX_MONTHS = 180 * MILLISECONDS_PER_DAY;
-
- // Acceptable cipher suites.
- /**
- * We support only a very limited range of strong cipher suites and protocols:
- * no SSLv3 or TLSv1.0 (if we can), no DHE ciphers that might be vulnerable to Logjam
- * (https://weakdh.org/), no RC4.
- *
- * Backstory: Bug 717691 (we no longer support Android 2.2, so the name
- * workaround is unnecessary), Bug 1081953, Bug 1061273, Bug 1166839.
- *
- * See <http://developer.android.com/reference/javax/net/ssl/SSLSocket.html> for
- * supported Android versions for each set of protocols and cipher suites.
- *
- * Note that currently we need to support connections to Sync 1.1 on Mozilla-hosted infra,
- * as well as connections to FxA and Sync 1.5 on AWS.
- *
- * ELB cipher suites:
- * <http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-security-policy-table.html>
- */
- public static final String[] DEFAULT_CIPHER_SUITES;
- public static final String[] DEFAULT_PROTOCOLS;
-
- static {
- // Prioritize 128 over 256 as a tradeoff between device CPU/battery and the minor
- // increase in strength.
- if (Versions.feature20Plus) {
- DEFAULT_CIPHER_SUITES = new String[]
- {
- "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 20+
- "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // 20+
- "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", // 20+
- "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // 11+
- "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", // 20+
- "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", // 20+
- "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // 11+
-
- // For Sync 1.1.
- "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", // 9+
- "TLS_RSA_WITH_AES_128_CBC_SHA", // 9+
- };
- } else {
- DEFAULT_CIPHER_SUITES = new String[]
- {
- "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // 11+
- "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", // 11+
- "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // 11+
-
- // For Sync 1.1.
- "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", // 9+
- "TLS_RSA_WITH_AES_128_CBC_SHA", // 9+
- };
- }
-
- if (Versions.feature16Plus) {
- DEFAULT_PROTOCOLS = new String[]
- {
- "TLSv1.2",
- "TLSv1.1",
- "TLSv1", // We would like to remove this, and will do so when we can.
- };
- } else {
- // Fall back to TLSv1 if there's nothing better.
- DEFAULT_PROTOCOLS = new String[]
- {
- "TLSv1",
- };
- }
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/PrefsBranch.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/PrefsBranch.java
deleted file mode 100644
index 78d5f61a1..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/PrefsBranch.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/* 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.background.common;
-
-import java.util.Map;
-import java.util.Set;
-
-import android.content.SharedPreferences;
-
-/**
- * A wrapper around a portion of the SharedPreferences space.
- */
-public class PrefsBranch implements SharedPreferences {
- private final SharedPreferences prefs;
- private final String prefix; // Including trailing period.
-
- public PrefsBranch(SharedPreferences prefs, String prefix) {
- if (!prefix.endsWith(".")) {
- throw new IllegalArgumentException("No trailing period in prefix.");
- }
- this.prefs = prefs;
- this.prefix = prefix;
- }
-
- @Override
- public boolean contains(String key) {
- return prefs.contains(prefix + key);
- }
-
- @Override
- public Editor edit() {
- return new EditorBranch(prefs, prefix);
- }
-
- @Override
- public Map<String, ?> getAll() {
- // Not implemented. TODO
- return null;
- }
-
- @Override
- public boolean getBoolean(String key, boolean defValue) {
- return prefs.getBoolean(prefix + key, defValue);
- }
-
- @Override
- public float getFloat(String key, float defValue) {
- return prefs.getFloat(prefix + key, defValue);
- }
-
- @Override
- public int getInt(String key, int defValue) {
- return prefs.getInt(prefix + key, defValue);
- }
-
- @Override
- public long getLong(String key, long defValue) {
- return prefs.getLong(prefix + key, defValue);
- }
-
- @Override
- public String getString(String key, String defValue) {
- return prefs.getString(prefix + key, defValue);
- }
-
- // Not marking as Override, because Android <= 10 doesn't have
- // getStringSet. Neither can we implement it.
- public Set<String> getStringSet(String key, Set<String> defValue) {
- throw new RuntimeException("getStringSet not available.");
- }
-
- @Override
- public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
- prefs.registerOnSharedPreferenceChangeListener(listener);
- }
-
- @Override
- public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
- prefs.unregisterOnSharedPreferenceChangeListener(listener);
- }
-} \ No newline at end of file
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/Logger.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/Logger.java
deleted file mode 100644
index 2575717eb..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/Logger.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/* 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.background.common.log;
-
-import java.io.PrintWriter;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import org.mozilla.gecko.background.common.GlobalConstants;
-import org.mozilla.gecko.background.common.log.writers.AndroidLevelCachingLogWriter;
-import org.mozilla.gecko.background.common.log.writers.AndroidLogWriter;
-import org.mozilla.gecko.background.common.log.writers.LogWriter;
-import org.mozilla.gecko.background.common.log.writers.PrintLogWriter;
-import org.mozilla.gecko.background.common.log.writers.SimpleTagLogWriter;
-import org.mozilla.gecko.background.common.log.writers.ThreadLocalTagLogWriter;
-
-import android.util.Log;
-
-/**
- * Logging helper class. Serializes all log operations (by synchronizing).
- */
-public class Logger {
- public static final String LOGGER_TAG = "Logger";
- public static final String DEFAULT_LOG_TAG = "GeckoLogger";
-
- // For extra debugging.
- public static boolean LOG_PERSONAL_INFORMATION = false;
-
- /**
- * Allow each thread to use its own global log tag. This allows
- * independent services to log as different sources.
- *
- * When your thread sets up logging, it should do something like the following:
- *
- * Logger.setThreadLogTag("MyTag");
- *
- * The value is inheritable, so worker threads and such do not need to
- * set the same log tag as their parent.
- */
- private static final InheritableThreadLocal<String> logTag = new InheritableThreadLocal<String>() {
- @Override
- protected String initialValue() {
- return DEFAULT_LOG_TAG;
- }
- };
-
- public static void setThreadLogTag(final String logTag) {
- Logger.logTag.set(logTag);
- }
- public static String getThreadLogTag() {
- return Logger.logTag.get();
- }
-
- /**
- * Current set of writers to which we will log.
- * <p>
- * We want logging to be available while running tests, so we initialize
- * this set statically.
- */
- protected final static Set<LogWriter> logWriters;
- static {
- final Set<LogWriter> defaultWriters = Logger.defaultLogWriters();
- logWriters = new LinkedHashSet<LogWriter>(defaultWriters);
- }
-
- /**
- * Default set of log writers to log to.
- */
- public final static Set<LogWriter> defaultLogWriters() {
- final String processedPackage = GlobalConstants.BROWSER_INTENT_PACKAGE.replace("org.mozilla.", "");
-
- final Set<LogWriter> defaultLogWriters = new LinkedHashSet<LogWriter>();
-
- final LogWriter log = new AndroidLogWriter();
- final LogWriter cache = new AndroidLevelCachingLogWriter(log);
-
- final LogWriter single = new SimpleTagLogWriter(processedPackage, new ThreadLocalTagLogWriter(Logger.logTag, cache));
-
- defaultLogWriters.add(single);
- return defaultLogWriters;
- }
-
- public static synchronized void startLoggingTo(LogWriter logWriter) {
- logWriters.add(logWriter);
- }
-
- public static synchronized void startLoggingToWriters(Set<LogWriter> writers) {
- logWriters.addAll(writers);
- }
-
- public static synchronized void stopLoggingTo(LogWriter logWriter) {
- try {
- logWriter.close();
- } catch (Exception e) {
- Log.e(LOGGER_TAG, "Got exception closing and removing LogWriter " + logWriter + ".", e);
- }
- logWriters.remove(logWriter);
- }
-
- public static synchronized void stopLoggingToAll() {
- for (LogWriter logWriter : logWriters) {
- try {
- logWriter.close();
- } catch (Exception e) {
- Log.e(LOGGER_TAG, "Got exception closing and removing LogWriter " + logWriter + ".", e);
- }
- }
- logWriters.clear();
- }
-
- /**
- * Write to only the default log writers.
- */
- public static synchronized void resetLogging() {
- stopLoggingToAll();
- logWriters.addAll(Logger.defaultLogWriters());
- }
-
- /**
- * Start writing log output to stdout.
- * <p>
- * Use <code>resetLogging</code> to stop logging to stdout.
- */
- public static synchronized void startLoggingToConsole() {
- setThreadLogTag("Test");
- startLoggingTo(new PrintLogWriter(new PrintWriter(System.out, true)));
- }
-
- // Synchronized version for other classes to use.
- public static synchronized boolean shouldLogVerbose(String logTag) {
- for (LogWriter logWriter : logWriters) {
- if (logWriter.shouldLogVerbose(logTag)) {
- return true;
- }
- }
- return false;
- }
-
- public static void error(String tag, String message) {
- Logger.error(tag, message, null);
- }
-
- public static void warn(String tag, String message) {
- Logger.warn(tag, message, null);
- }
-
- public static void info(String tag, String message) {
- Logger.info(tag, message, null);
- }
-
- public static void debug(String tag, String message) {
- Logger.debug(tag, message, null);
- }
-
- public static void trace(String tag, String message) {
- Logger.trace(tag, message, null);
- }
-
- public static void pii(String tag, String message) {
- if (LOG_PERSONAL_INFORMATION) {
- Logger.debug(tag, "$$PII$$: " + message);
- }
- }
-
- public static synchronized void error(String tag, String message, Throwable error) {
- Iterator<LogWriter> it = logWriters.iterator();
- while (it.hasNext()) {
- LogWriter writer = it.next();
- try {
- writer.error(tag, message, error);
- } catch (Exception e) {
- Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e);
- it.remove();
- }
- }
- }
-
- public static synchronized void warn(String tag, String message, Throwable error) {
- Iterator<LogWriter> it = logWriters.iterator();
- while (it.hasNext()) {
- LogWriter writer = it.next();
- try {
- writer.warn(tag, message, error);
- } catch (Exception e) {
- Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e);
- it.remove();
- }
- }
- }
-
- public static synchronized void info(String tag, String message, Throwable error) {
- Iterator<LogWriter> it = logWriters.iterator();
- while (it.hasNext()) {
- LogWriter writer = it.next();
- try {
- writer.info(tag, message, error);
- } catch (Exception e) {
- Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e);
- it.remove();
- }
- }
- }
-
- public static synchronized void debug(String tag, String message, Throwable error) {
- Iterator<LogWriter> it = logWriters.iterator();
- while (it.hasNext()) {
- LogWriter writer = it.next();
- try {
- writer.debug(tag, message, error);
- } catch (Exception e) {
- Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e);
- it.remove();
- }
- }
- }
-
- public static synchronized void trace(String tag, String message, Throwable error) {
- Iterator<LogWriter> it = logWriters.iterator();
- while (it.hasNext()) {
- LogWriter writer = it.next();
- try {
- writer.trace(tag, message, error);
- } catch (Exception e) {
- Log.e(LOGGER_TAG, "Got exception logging; removing LogWriter " + writer + ".", e);
- it.remove();
- }
- }
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLevelCachingLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLevelCachingLogWriter.java
deleted file mode 100644
index ac4250a03..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLevelCachingLogWriter.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/* 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.background.common.log.writers;
-
-import java.util.IdentityHashMap;
-import java.util.Map;
-
-import android.util.Log;
-
-/**
- * Make a <code>LogWriter</code> only log when the Android log system says to.
- */
-public class AndroidLevelCachingLogWriter extends LogWriter {
- protected final LogWriter inner;
-
- public AndroidLevelCachingLogWriter(LogWriter inner) {
- this.inner = inner;
- }
-
- // I can't believe we have to implement this ourselves.
- // These aren't synchronized (and neither are the setters) because
- // the logging calls themselves are synchronized.
- private Map<String, Boolean> isErrorLoggable = new IdentityHashMap<String, Boolean>();
- private Map<String, Boolean> isWarnLoggable = new IdentityHashMap<String, Boolean>();
- private Map<String, Boolean> isInfoLoggable = new IdentityHashMap<String, Boolean>();
- private Map<String, Boolean> isDebugLoggable = new IdentityHashMap<String, Boolean>();
- private Map<String, Boolean> isVerboseLoggable = new IdentityHashMap<String, Boolean>();
-
- /**
- * Empty the caches of log levels.
- */
- public void refreshLogLevels() {
- isErrorLoggable = new IdentityHashMap<String, Boolean>();
- isWarnLoggable = new IdentityHashMap<String, Boolean>();
- isInfoLoggable = new IdentityHashMap<String, Boolean>();
- isDebugLoggable = new IdentityHashMap<String, Boolean>();
- isVerboseLoggable = new IdentityHashMap<String, Boolean>();
- }
-
- private boolean shouldLogError(String logTag) {
- Boolean out = isErrorLoggable.get(logTag);
- if (out != null) {
- return out;
- }
- out = Log.isLoggable(logTag, Log.ERROR);
- isErrorLoggable.put(logTag, out);
- return out;
- }
-
- private boolean shouldLogWarn(String logTag) {
- Boolean out = isWarnLoggable.get(logTag);
- if (out != null) {
- return out;
- }
- out = Log.isLoggable(logTag, Log.WARN);
- isWarnLoggable.put(logTag, out);
- return out;
- }
-
- private boolean shouldLogInfo(String logTag) {
- Boolean out = isInfoLoggable.get(logTag);
- if (out != null) {
- return out;
- }
- out = Log.isLoggable(logTag, Log.INFO);
- isInfoLoggable.put(logTag, out);
- return out;
- }
-
- private boolean shouldLogDebug(String logTag) {
- Boolean out = isDebugLoggable.get(logTag);
- if (out != null) {
- return out;
- }
- out = Log.isLoggable(logTag, Log.DEBUG);
- isDebugLoggable.put(logTag, out);
- return out;
- }
-
- @Override
- public boolean shouldLogVerbose(String logTag) {
- Boolean out = isVerboseLoggable.get(logTag);
- if (out != null) {
- return out;
- }
- out = Log.isLoggable(logTag, Log.VERBOSE);
- isVerboseLoggable.put(logTag, out);
- return out;
- }
-
- @Override
- public void error(String tag, String message, Throwable error) {
- if (shouldLogError(tag)) {
- inner.error(tag, message, error);
- }
- }
-
- @Override
- public void warn(String tag, String message, Throwable error) {
- if (shouldLogWarn(tag)) {
- inner.warn(tag, message, error);
- }
- }
-
- @Override
- public void info(String tag, String message, Throwable error) {
- if (shouldLogInfo(tag)) {
- inner.info(tag, message, error);
- }
- }
-
- @Override
- public void debug(String tag, String message, Throwable error) {
- if (shouldLogDebug(tag)) {
- inner.debug(tag, message, error);
- }
- }
-
- @Override
- public void trace(String tag, String message, Throwable error) {
- if (shouldLogVerbose(tag)) {
- inner.trace(tag, message, error);
- }
- }
-
- @Override
- public void close() {
- inner.close();
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLogWriter.java
deleted file mode 100644
index 9d309844d..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/AndroidLogWriter.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/* 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.background.common.log.writers;
-
-import android.util.Log;
-
-/**
- * Log to the Android log.
- */
-public class AndroidLogWriter extends LogWriter {
- @Override
- public boolean shouldLogVerbose(String logTag) {
- return true;
- }
-
- @Override
- public void error(String tag, String message, Throwable error) {
- Log.e(tag, message, error);
- }
-
- @Override
- public void warn(String tag, String message, Throwable error) {
- Log.w(tag, message, error);
- }
-
- @Override
- public void info(String tag, String message, Throwable error) {
- Log.i(tag, message, error);
- }
-
- @Override
- public void debug(String tag, String message, Throwable error) {
- Log.d(tag, message, error);
- }
-
- @Override
- public void trace(String tag, String message, Throwable error) {
- Log.v(tag, message, error);
- }
-
- @Override
- public void close() {
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LevelFilteringLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LevelFilteringLogWriter.java
deleted file mode 100644
index 74c3608c4..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LevelFilteringLogWriter.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/* 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.background.common.log.writers;
-
-import android.util.Log;
-
-/**
- * A LogWriter that logs only if the message is as important as the specified
- * level. For example, if the specified level is <code>Log.WARN</code>, only
- * <code>warn</code> and <code>error</code> will log.
- */
-public class LevelFilteringLogWriter extends LogWriter {
- protected final LogWriter inner;
- protected final int logLevel;
-
- public LevelFilteringLogWriter(int logLevel, LogWriter inner) {
- this.inner = inner;
- this.logLevel = logLevel;
- }
-
- @Override
- public void close() {
- inner.close();
- }
-
- @Override
- public void error(String tag, String message, Throwable error) {
- if (logLevel <= Log.ERROR) {
- inner.error(tag, message, error);
- }
- }
-
- @Override
- public void warn(String tag, String message, Throwable error) {
- if (logLevel <= Log.WARN) {
- inner.warn(tag, message, error);
- }
- }
-
- @Override
- public void info(String tag, String message, Throwable error) {
- if (logLevel <= Log.INFO) {
- inner.info(tag, message, error);
- }
- }
-
- @Override
- public void debug(String tag, String message, Throwable error) {
- if (logLevel <= Log.DEBUG) {
- inner.debug(tag, message, error);
- }
- }
-
- @Override
- public void trace(String tag, String message, Throwable error) {
- if (logLevel <= Log.VERBOSE) {
- inner.trace(tag, message, error);
- }
- }
-
- @Override
- public boolean shouldLogVerbose(String tag) {
- return logLevel <= Log.VERBOSE;
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LogWriter.java
deleted file mode 100644
index acfb09969..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/LogWriter.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/* 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.background.common.log.writers;
-
-/**
- * An abstract object that logs information in some way.
- * <p>
- * Intended to be composed with other log writers, for example a log
- * writer could make all log entries have the same single log tag, or
- * could ignore certain log levels, before delegating to an inner log
- * writer.
- */
-public abstract class LogWriter {
- public abstract void error(String tag, String message, Throwable error);
- public abstract void warn(String tag, String message, Throwable error);
- public abstract void info(String tag, String message, Throwable error);
- public abstract void debug(String tag, String message, Throwable error);
- public abstract void trace(String tag, String message, Throwable error);
-
- /**
- * We expect <code>close</code> to be called only by static
- * synchronized methods in class <code>Logger</code>.
- */
- public abstract void close();
-
- public abstract boolean shouldLogVerbose(String tag);
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/PrintLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/PrintLogWriter.java
deleted file mode 100644
index 6e1f63de3..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/PrintLogWriter.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/* 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.background.common.log.writers;
-
-import java.io.PrintWriter;
-
-/**
- * Log to a <code>PrintWriter</code>.
- */
-public class PrintLogWriter extends LogWriter {
- protected final PrintWriter pw;
- protected boolean closed = false;
-
- public static final String ERROR = " :: E :: ";
- public static final String WARN = " :: W :: ";
- public static final String INFO = " :: I :: ";
- public static final String DEBUG = " :: D :: ";
- public static final String VERBOSE = " :: V :: ";
-
- public PrintLogWriter(PrintWriter pw) {
- this.pw = pw;
- }
-
- protected void log(String tag, String message, Throwable error) {
- if (closed) {
- return;
- }
-
- pw.println(tag + message);
- if (error != null) {
- error.printStackTrace(pw);
- }
- }
-
- @Override
- public void error(String tag, String message, Throwable error) {
- log(tag, ERROR + message, error);
- }
-
- @Override
- public void warn(String tag, String message, Throwable error) {
- log(tag, WARN + message, error);
- }
-
- @Override
- public void info(String tag, String message, Throwable error) {
- log(tag, INFO + message, error);
- }
-
- @Override
- public void debug(String tag, String message, Throwable error) {
- log(tag, DEBUG + message, error);
- }
-
- @Override
- public void trace(String tag, String message, Throwable error) {
- log(tag, VERBOSE + message, error);
- }
-
- @Override
- public boolean shouldLogVerbose(String tag) {
- return true;
- }
-
- @Override
- public void close() {
- if (closed) {
- return;
- }
- if (pw != null) {
- pw.close();
- }
- closed = true;
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/SimpleTagLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/SimpleTagLogWriter.java
deleted file mode 100644
index a17654371..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/SimpleTagLogWriter.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/* 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.background.common.log.writers;
-
-/**
- * Make a <code>LogWriter</code> only log with a single string tag.
- */
-public class SimpleTagLogWriter extends TagLogWriter {
- final String tag;
- public SimpleTagLogWriter(String tag, LogWriter inner) {
- super(inner);
- this.tag = tag;
- }
-
- @Override
- protected String getMainTag() {
- return tag;
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/StringLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/StringLogWriter.java
deleted file mode 100644
index d6a9f5eb8..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/StringLogWriter.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/* 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.background.common.log.writers;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-public class StringLogWriter extends LogWriter {
- protected final StringWriter sw;
- protected final PrintLogWriter inner;
-
- public StringLogWriter() {
- sw = new StringWriter();
- inner = new PrintLogWriter(new PrintWriter(sw));
- }
-
- public String toString() {
- return sw.toString();
- }
-
- @Override
- public boolean shouldLogVerbose(String tag) {
- return true;
- }
-
- @Override
- public void error(String tag, String message, Throwable error) {
- inner.error(tag, message, error);
- }
-
- @Override
- public void warn(String tag, String message, Throwable error) {
- inner.warn(tag, message, error);
- }
-
- @Override
- public void info(String tag, String message, Throwable error) {
- inner.info(tag, message, error);
- }
-
- @Override
- public void debug(String tag, String message, Throwable error) {
- inner.debug(tag, message, error);
- }
-
- @Override
- public void trace(String tag, String message, Throwable error) {
- inner.trace(tag, message, error);
- }
-
- @Override
- public void close() {
- inner.close();
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/TagLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/TagLogWriter.java
deleted file mode 100644
index fbcd94a91..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/TagLogWriter.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/* 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.background.common.log.writers;
-
-/**
- * A @link{LogWriter} that logs each message under a parent tag.
- */
-public abstract class TagLogWriter extends LogWriter {
-
- protected final LogWriter inner;
-
- public TagLogWriter(final LogWriter inner) {
- super();
- this.inner = inner;
- }
-
- protected abstract String getMainTag();
-
- @Override
- public void error(String tag, String message, Throwable error) {
- inner.error(this.getMainTag(), tag + " :: " + message, error);
- }
-
- @Override
- public void warn(String tag, String message, Throwable error) {
- inner.warn(this.getMainTag(), tag + " :: " + message, error);
- }
-
- @Override
- public void info(String tag, String message, Throwable error) {
- inner.info(this.getMainTag(), tag + " :: " + message, error);
- }
-
- @Override
- public void debug(String tag, String message, Throwable error) {
- inner.debug(this.getMainTag(), tag + " :: " + message, error);
- }
-
- @Override
- public void trace(String tag, String message, Throwable error) {
- inner.trace(this.getMainTag(), tag + " :: " + message, error);
- }
-
- @Override
- public boolean shouldLogVerbose(String tag) {
- return inner.shouldLogVerbose(this.getMainTag());
- }
-
- @Override
- public void close() {
- inner.close();
- }
-} \ No newline at end of file
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/ThreadLocalTagLogWriter.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/ThreadLocalTagLogWriter.java
deleted file mode 100644
index 0c83504a0..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/log/writers/ThreadLocalTagLogWriter.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/* 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.background.common.log.writers;
-
-/**
- * Log with a single global tag… but that tag can be different for each thread.
- *
- * Takes a @link{ThreadLocal} as a constructor parameter.
- */
-public class ThreadLocalTagLogWriter extends TagLogWriter {
-
- private final ThreadLocal<String> tag;
-
- public ThreadLocalTagLogWriter(ThreadLocal<String> tag, LogWriter inner) {
- super(inner);
- this.tag = tag;
- }
-
- @Override
- protected String getMainTag() {
- return this.tag.get();
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/telemetry/TelemetryWrapper.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/telemetry/TelemetryWrapper.java
deleted file mode 100644
index 6639b817d..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/common/telemetry/TelemetryWrapper.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/* 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.background.common.telemetry;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import org.mozilla.gecko.background.common.log.Logger;
-
-/**
- * Android Background Services are normally built into Fennec, but can also be
- * built as a stand-alone APK for rapid local development. The current Telemetry
- * implementation is coupled to Gecko, and Background Services should not
- * interact with Gecko directly. To maintain this independence, Background
- * Services lazily introspects the relevant Telemetry class from the enclosing
- * package, warning but otherwise ignoring failures during introspection or
- * invocation.
- * <p>
- * It is possible that Background Services will introspect and invoke the
- * Telemetry implementation while Gecko is not running. In this case, the Fennec
- * process itself buffers Telemetry events until such time as they can be
- * flushed to disk and uploaded. <b>There is no guarantee that all Telemetry
- * events will be uploaded!</b> Depending on the volume of data and the
- * application lifecycle, Telemetry events may be dropped.
- */
-public class TelemetryWrapper {
- private static final String LOG_TAG = TelemetryWrapper.class.getSimpleName();
-
- // Marking this volatile maintains thread safety cheaply.
- private static volatile Method mAddToHistogram;
-
- public static void addToHistogram(String key, int value) {
- if (mAddToHistogram == null) {
- try {
- final Class<?> telemetry = Class.forName("org.mozilla.gecko.Telemetry");
- mAddToHistogram = telemetry.getMethod("addToHistogram", String.class, int.class);
- } catch (ClassNotFoundException e) {
- Logger.warn(LOG_TAG, "org.mozilla.gecko.Telemetry class found!");
- return;
- } catch (NoSuchMethodException e) {
- Logger.warn(LOG_TAG, "org.mozilla.gecko.Telemetry.addToHistogram(String, int) method not found!");
- return;
- }
- }
-
- if (mAddToHistogram != null) {
- try {
- mAddToHistogram.invoke(null, key, value);
- } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
- Logger.warn(LOG_TAG, "Got exception invoking telemetry!");
- }
- }
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/db/CursorDumper.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/db/CursorDumper.java
deleted file mode 100644
index bce968b00..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/db/CursorDumper.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/* 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.background.db;
-
-import android.database.Cursor;
-
-/**
- * A utility for dumping a cursor the debug log.
- * <p>
- * <b>For debugging only!</p>
- */
-public class CursorDumper {
- protected static String fixedWidth(int width, String s) {
- if (s == null) {
- return spaces(width);
- }
- int length = s.length();
- if (width == length) {
- return s;
- }
- if (width > length) {
- return s + spaces(width - length);
- }
- return s.substring(0, width);
- }
-
- protected static String spaces(int i) {
- return " ".substring(0, i);
- }
-
- protected static String dashes(int i) {
- return "-------------------------------------".substring(0, i);
- }
-
- /**
- * Dump a cursor to the debug log, ignoring any log level settings.
- * <p>
- * The position in the cursor is maintained. Caller is responsible for opening
- * and closing cursor.
- *
- * @param cursor
- * to dump.
- */
- public static void dumpCursor(Cursor cursor) {
- dumpCursor(cursor, 18, "records");
- }
-
- /**
- * Dump a cursor to the debug log, ignoring any log level settings.
- * <p>
- * The position in the cursor is maintained. Caller is responsible for opening
- * and closing cursor.
- *
- * @param cursor
- * to dump.
- * @param columnWidth
- * how many characters per cursor column.
- * @param tags
- * a descriptor, printed like "(10 tags)", in the header row.
- */
- protected static void dumpCursor(Cursor cursor, int columnWidth, String tags) {
- int originalPosition = cursor.getPosition();
- try {
- String[] columnNames = cursor.getColumnNames();
- int columnCount = cursor.getColumnCount();
-
- for (int i = 0; i < columnCount; ++i) {
- System.out.print(fixedWidth(columnWidth, columnNames[i]) + " | ");
- }
- System.out.println("(" + cursor.getCount() + " " + tags + ")");
- for (int i = 0; i < columnCount; ++i) {
- System.out.print(dashes(columnWidth) + " | ");
- }
- System.out.println("");
- if (!cursor.moveToFirst()) {
- System.out.println("EMPTY");
- return;
- }
-
- cursor.moveToFirst();
- while (!cursor.isAfterLast()) {
- for (int i = 0; i < columnCount; ++i) {
- System.out.print(fixedWidth(columnWidth, cursor.getString(i)) + " | ");
- }
- System.out.println("");
- cursor.moveToNext();
- }
- for (int i = 0; i < columnCount-1; ++i) {
- System.out.print(dashes(columnWidth + 3));
- }
- System.out.print(dashes(columnWidth + 3 - 1));
- System.out.println("");
- } finally {
- cursor.moveToPosition(originalPosition);
- }
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/db/Tab.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/db/Tab.java
deleted file mode 100644
index f38cfdf0e..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/db/Tab.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/* 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.background.db;
-
-import org.json.simple.JSONArray;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserContract.Tabs;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.repositories.android.RepoUtils;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-
-// Immutable.
-public class Tab {
- public final String title;
- public final String icon;
- public final JSONArray history;
- public final long lastUsed;
-
- public Tab(String title, String icon, JSONArray history, long lastUsed) {
- this.title = title;
- this.icon = icon;
- this.history = history;
- this.lastUsed = lastUsed;
- }
-
- public ContentValues toContentValues(String clientGUID, int position) {
- ContentValues out = new ContentValues();
- out.put(BrowserContract.Tabs.POSITION, position);
- out.put(BrowserContract.Tabs.CLIENT_GUID, clientGUID);
-
- out.put(BrowserContract.Tabs.FAVICON, this.icon);
- out.put(BrowserContract.Tabs.LAST_USED, this.lastUsed);
- out.put(BrowserContract.Tabs.TITLE, this.title);
- out.put(BrowserContract.Tabs.URL, (String) this.history.get(0));
- out.put(BrowserContract.Tabs.HISTORY, this.history.toJSONString());
- return out;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof Tab)) {
- return false;
- }
- final Tab other = (Tab) o;
-
- if (!RepoUtils.stringsEqual(this.title, other.title)) {
- return false;
- }
- if (!RepoUtils.stringsEqual(this.icon, other.icon)) {
- return false;
- }
-
- if (!(this.lastUsed == other.lastUsed)) {
- return false;
- }
-
- return Utils.sameArrays(this.history, other.history);
- }
-
- @Override
- public int hashCode() {
- return super.hashCode();
- }
-
- /**
- * Extract a <code>Tab</code> from a cursor row.
- * <p>
- * Caller is responsible for creating, positioning, and closing the cursor.
- *
- * @param cursor
- * to inspect.
- * @return <code>Tab</code> instance.
- */
- public static Tab fromCursor(final Cursor cursor) {
- final String title = RepoUtils.getStringFromCursor(cursor, Tabs.TITLE);
- final String icon = RepoUtils.getStringFromCursor(cursor, Tabs.FAVICON);
- final JSONArray history = RepoUtils.getJSONArrayFromCursor(cursor, Tabs.HISTORY);
- final long lastUsed = RepoUtils.getLongFromCursor(cursor, Tabs.LAST_USED);
-
- return new Tab(title, icon, history, lastUsed);
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java
deleted file mode 100644
index 98809137f..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20CreateDelegate.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/* 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.background.fxa;
-
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Utils;
-
-import java.io.UnsupportedEncodingException;
-import java.security.GeneralSecurityException;
-
-public class FxAccount20CreateDelegate {
- protected final byte[] emailUTF8;
- protected final byte[] authPW;
- protected final boolean preVerified;
-
- /**
- * Make a new "create account" delegate.
- *
- * @param emailUTF8
- * email as UTF-8 bytes.
- * @param quickStretchedPW
- * quick stretched password as bytes.
- * @param preVerified
- * true if account should be marked already verified; only effective
- * for non-production auth servers.
- * @throws UnsupportedEncodingException
- * @throws GeneralSecurityException
- */
- public FxAccount20CreateDelegate(byte[] emailUTF8, byte[] quickStretchedPW, boolean preVerified) throws UnsupportedEncodingException, GeneralSecurityException {
- this.emailUTF8 = emailUTF8;
- this.authPW = FxAccountUtils.generateAuthPW(quickStretchedPW);
- this.preVerified = preVerified;
- }
-
- public ExtendedJSONObject getCreateBody() throws FxAccountClientException {
- final ExtendedJSONObject body = new ExtendedJSONObject();
- try {
- body.put("email", new String(emailUTF8, "UTF-8"));
- body.put("authPW", Utils.byte2Hex(authPW));
- if (preVerified) {
- // Production endpoints do not allow preVerified; this assumes we only
- // set it when it's okay to send it.
- body.put("preVerified", preVerified);
- }
- return body;
- } catch (UnsupportedEncodingException e) {
- throw new FxAccountClientException(e);
- }
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java
deleted file mode 100644
index 0266a6eab..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccount20LoginDelegate.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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.background.fxa;
-
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Utils;
-
-import java.io.UnsupportedEncodingException;
-import java.security.GeneralSecurityException;
-
-/**
- * An abstraction around providing an email and authorization token to the auth
- * server.
- */
-public class FxAccount20LoginDelegate {
- protected final byte[] emailUTF8;
- protected final byte[] authPW;
-
- public FxAccount20LoginDelegate(byte[] emailUTF8, byte[] quickStretchedPW) throws UnsupportedEncodingException, GeneralSecurityException {
- this.emailUTF8 = emailUTF8;
- this.authPW = FxAccountUtils.generateAuthPW(quickStretchedPW);
- }
-
- public ExtendedJSONObject getCreateBody() throws FxAccountClientException {
- final ExtendedJSONObject body = new ExtendedJSONObject();
- try {
- body.put("email", new String(emailUTF8, "UTF-8"));
- body.put("authPW", Utils.byte2Hex(authPW));
- return body;
- } catch (UnsupportedEncodingException e) {
- throw new FxAccountClientException(e);
- }
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient.java
deleted file mode 100644
index ed959ff0e..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 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.background.fxa;
-
-import org.mozilla.gecko.background.fxa.FxAccountClient20.AccountStatusResponse;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.RecoveryEmailStatusResponse;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.RequestDelegate;
-import org.mozilla.gecko.background.fxa.FxAccountClient20.TwoKeys;
-import org.mozilla.gecko.fxa.FxAccountDevice;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-
-import java.util.List;
-
-public interface FxAccountClient {
- public void accountStatus(String uid, RequestDelegate<AccountStatusResponse> requestDelegate);
- public void recoveryEmailStatus(byte[] sessionToken, RequestDelegate<RecoveryEmailStatusResponse> requestDelegate);
- public void keys(byte[] keyFetchToken, RequestDelegate<TwoKeys> requestDelegate);
- public void sign(byte[] sessionToken, ExtendedJSONObject publicKey, long certificateDurationInMilliseconds, RequestDelegate<String> requestDelegate);
- public void registerOrUpdateDevice(byte[] sessionToken, FxAccountDevice device, RequestDelegate<FxAccountDevice> requestDelegate);
- public void deviceList(byte[] sessionToken, RequestDelegate<FxAccountDevice[]> requestDelegate);
- public void notifyDevices(byte[] sessionToken, List<String> deviceIds, ExtendedJSONObject payload, Long TTL, RequestDelegate<ExtendedJSONObject> requestDelegate);
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java
deleted file mode 100644
index 596f4525e..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClient20.java
+++ /dev/null
@@ -1,914 +0,0 @@
-/* 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.background.fxa;
-
-import android.support.annotation.NonNull;
-
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientMalformedResponseException;
-import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.Locales;
-import org.mozilla.gecko.fxa.FxAccountDevice;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.HKDF;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-import org.mozilla.gecko.sync.net.HawkAuthHeaderProvider;
-import org.mozilla.gecko.sync.net.Resource;
-import org.mozilla.gecko.sync.net.SyncResponse;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URLEncoder;
-import java.security.GeneralSecurityException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.Executor;
-
-import javax.crypto.Mac;
-
-import ch.boye.httpclientandroidlib.HttpEntity;
-import ch.boye.httpclientandroidlib.HttpHeaders;
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-
-/**
- * An HTTP client for talking to an FxAccount server.
- * <p>
- * <p>
- * The delegate structure used is a little different from the rest of the code
- * base. We add a <code>RequestDelegate</code> layer that processes a typed
- * value extracted from the body of a successful response.
- */
-public class FxAccountClient20 implements FxAccountClient {
- protected static final String LOG_TAG = FxAccountClient20.class.getSimpleName();
-
- protected static final String ACCEPT_HEADER = "application/json;charset=utf-8";
-
- public static final String JSON_KEY_EMAIL = "email";
- public static final String JSON_KEY_KEYFETCHTOKEN = "keyFetchToken";
- public static final String JSON_KEY_SESSIONTOKEN = "sessionToken";
- public static final String JSON_KEY_UID = "uid";
- public static final String JSON_KEY_VERIFIED = "verified";
- public static final String JSON_KEY_ERROR = "error";
- public static final String JSON_KEY_MESSAGE = "message";
- public static final String JSON_KEY_INFO = "info";
- public static final String JSON_KEY_CODE = "code";
- public static final String JSON_KEY_ERRNO = "errno";
- public static final String JSON_KEY_EXISTS = "exists";
-
- protected static final String[] requiredErrorStringFields = { JSON_KEY_ERROR, JSON_KEY_MESSAGE, JSON_KEY_INFO };
- protected static final String[] requiredErrorLongFields = { JSON_KEY_CODE, JSON_KEY_ERRNO };
-
- /**
- * The server's URI.
- * <p>
- * We assume throughout that this ends with a trailing slash (and guarantee as
- * much in the constructor).
- */
- protected final String serverURI;
-
- protected final Executor executor;
-
- public FxAccountClient20(String serverURI, Executor executor) {
- if (serverURI == null) {
- throw new IllegalArgumentException("Must provide a server URI.");
- }
- if (executor == null) {
- throw new IllegalArgumentException("Must provide a non-null executor.");
- }
- this.serverURI = serverURI.endsWith("/") ? serverURI : serverURI + "/";
- if (!this.serverURI.endsWith("/")) {
- throw new IllegalArgumentException("Constructed serverURI must end with a trailing slash: " + this.serverURI);
- }
- this.executor = executor;
- }
-
- protected BaseResource getBaseResource(String path, Map<String, String> queryParameters) throws UnsupportedEncodingException, URISyntaxException {
- if (queryParameters == null || queryParameters.isEmpty()) {
- return getBaseResource(path);
- }
- final String[] array = new String[2 * queryParameters.size()];
- int i = 0;
- for (Entry<String, String> entry : queryParameters.entrySet()) {
- array[i++] = entry.getKey();
- array[i++] = entry.getValue();
- }
- return getBaseResource(path, array);
- }
-
- /**
- * Create <code>BaseResource</code>, encoding query parameters carefully.
- * <p>
- * This is equivalent to <code>android.net.Uri.Builder</code>, which is not
- * present in our JUnit 4 tests.
- *
- * @param path fragment.
- * @param queryParameters list of key/value query parameter pairs. Must be even length!
- * @return <code>BaseResource<instance>
- * @throws URISyntaxException
- * @throws UnsupportedEncodingException
- */
- protected BaseResource getBaseResource(String path, String... queryParameters) throws URISyntaxException, UnsupportedEncodingException {
- final StringBuilder sb = new StringBuilder(serverURI);
- sb.append(path);
- if (queryParameters != null) {
- int i = 0;
- while (i < queryParameters.length) {
- sb.append(i > 0 ? "&" : "?");
- final String key = queryParameters[i++];
- final String val = queryParameters[i++];
- sb.append(URLEncoder.encode(key, "UTF-8"));
- sb.append("=");
- sb.append(URLEncoder.encode(val, "UTF-8"));
- }
- }
- return new BaseResource(new URI(sb.toString()));
- }
-
- /**
- * Process a typed value extracted from a successful response (in an
- * endpoint-dependent way).
- */
- public interface RequestDelegate<T> {
- public void handleError(Exception e);
- public void handleFailure(FxAccountClientRemoteException e);
- public void handleSuccess(T result);
- }
-
- /**
- * Thin container for two cryptographic keys.
- */
- public static class TwoKeys {
- public final byte[] kA;
- public final byte[] wrapkB;
- public TwoKeys(byte[] kA, byte[] wrapkB) {
- this.kA = kA;
- this.wrapkB = wrapkB;
- }
- }
-
- protected <T> void invokeHandleError(final RequestDelegate<T> delegate, final Exception e) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- delegate.handleError(e);
- }
- });
- }
-
- enum ResponseType {
- JSON_ARRAY,
- JSON_OBJECT
- }
-
- /**
- * Translate resource callbacks into request callbacks invoked on the provided
- * executor.
- * <p>
- * Override <code>handleSuccess</code> to parse the body of the resource
- * request and call the request callback. <code>handleSuccess</code> is
- * invoked via the executor, so you don't need to delegate further.
- */
- protected abstract class ResourceDelegate<T> extends BaseResourceDelegate {
-
- protected void handleSuccess(final int status, HttpResponse response, final ExtendedJSONObject body) throws Exception {
- throw new UnsupportedOperationException();
- }
-
- protected void handleSuccess(final int status, HttpResponse response, final JSONArray body) throws Exception {
- throw new UnsupportedOperationException();
- }
-
- protected final RequestDelegate<T> delegate;
-
- protected final byte[] tokenId;
- protected final byte[] reqHMACKey;
- protected final SkewHandler skewHandler;
- protected final ResponseType responseType;
-
- /**
- * Create a delegate for an un-authenticated resource.
- */
- public ResourceDelegate(final Resource resource, final RequestDelegate<T> delegate, ResponseType responseType) {
- this(resource, delegate, responseType, null, null);
- }
-
- /**
- * Create a delegate for a Hawk-authenticated resource.
- * <p>
- * Every Hawk request that encloses an entity (PATCH, POST, and PUT) will
- * include the payload verification hash.
- */
- public ResourceDelegate(final Resource resource, final RequestDelegate<T> delegate, ResponseType responseType, final byte[] tokenId, final byte[] reqHMACKey) {
- super(resource);
- this.delegate = delegate;
- this.reqHMACKey = reqHMACKey;
- this.tokenId = tokenId;
- this.skewHandler = SkewHandler.getSkewHandlerForResource(resource);
- this.responseType = responseType;
- }
-
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- if (tokenId != null && reqHMACKey != null) {
- // We always include the payload verification hash for FxA Hawk-authenticated requests.
- final boolean includePayloadVerificationHash = true;
- return new HawkAuthHeaderProvider(Utils.byte2Hex(tokenId), reqHMACKey, includePayloadVerificationHash, skewHandler.getSkewInSeconds());
- }
- return super.getAuthHeaderProvider();
- }
-
- @Override
- public String getUserAgent() {
- return FxAccountConstants.USER_AGENT;
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- try {
- final int status = validateResponse(response);
- skewHandler.updateSkew(response, now());
- invokeHandleSuccess(status, response);
- } catch (FxAccountClientRemoteException e) {
- if (!skewHandler.updateSkew(response, now())) {
- // If we couldn't update skew, but we got a failure, let's try clearing the skew.
- skewHandler.resetSkew();
- }
- invokeHandleFailure(e);
- }
- }
-
- protected void invokeHandleFailure(final FxAccountClientRemoteException e) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- delegate.handleFailure(e);
- }
- });
- }
-
- protected void invokeHandleSuccess(final int status, final HttpResponse response) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- try {
- SyncResponse syncResponse = new SyncResponse(response);
- if (responseType == ResponseType.JSON_ARRAY) {
- JSONArray body = syncResponse.jsonArrayBody();
- ResourceDelegate.this.handleSuccess(status, response, body);
- } else {
- ExtendedJSONObject body = syncResponse.jsonObjectBody();
- ResourceDelegate.this.handleSuccess(status, response, body);
- }
- } catch (Exception e) {
- delegate.handleError(e);
- }
- }
- });
- }
-
- @Override
- public void handleHttpProtocolException(final ClientProtocolException e) {
- invokeHandleError(delegate, e);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- invokeHandleError(delegate, e);
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- invokeHandleError(delegate, e);
- }
-
- @Override
- public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
- super.addHeaders(request, client);
-
- // The basics.
- final Locale locale = Locale.getDefault();
- request.addHeader(HttpHeaders.ACCEPT_LANGUAGE, Locales.getLanguageTag(locale));
- request.addHeader(HttpHeaders.ACCEPT, ACCEPT_HEADER);
- }
- }
-
- protected <T> void post(BaseResource resource, final ExtendedJSONObject requestBody) {
- if (requestBody == null) {
- resource.post((HttpEntity) null);
- } else {
- resource.post(requestBody);
- }
- }
-
- @SuppressWarnings("static-method")
- public long now() {
- return System.currentTimeMillis();
- }
-
- /**
- * Intepret a response from the auth server.
- * <p>
- * Throw an appropriate exception on errors; otherwise, return the response's
- * status code.
- *
- * @return response's HTTP status code.
- * @throws FxAccountClientException
- */
- public static int validateResponse(HttpResponse response) throws FxAccountClientRemoteException {
- final int status = response.getStatusLine().getStatusCode();
- if (status == 200) {
- return status;
- }
- int code;
- int errno;
- String error;
- String message;
- String info;
- ExtendedJSONObject body;
- try {
- body = new SyncStorageResponse(response).jsonObjectBody();
- body.throwIfFieldsMissingOrMisTyped(requiredErrorStringFields, String.class);
- body.throwIfFieldsMissingOrMisTyped(requiredErrorLongFields, Long.class);
- code = body.getLong(JSON_KEY_CODE).intValue();
- errno = body.getLong(JSON_KEY_ERRNO).intValue();
- error = body.getString(JSON_KEY_ERROR);
- message = body.getString(JSON_KEY_MESSAGE);
- info = body.getString(JSON_KEY_INFO);
- } catch (Exception e) {
- throw new FxAccountClientMalformedResponseException(response);
- }
- throw new FxAccountClientRemoteException(response, code, errno, error, message, info, body);
- }
-
- /**
- * Don't call this directly. Use <code>unbundleBody</code> instead.
- */
- protected void unbundleBytes(byte[] bundleBytes, byte[] respHMACKey, byte[] respXORKey, byte[]... rest)
- throws InvalidKeyException, NoSuchAlgorithmException, FxAccountClientException {
- if (bundleBytes.length < 32) {
- throw new IllegalArgumentException("input bundle must include HMAC");
- }
- int len = respXORKey.length;
- if (bundleBytes.length != len + 32) {
- throw new IllegalArgumentException("input bundle and XOR key with HMAC have different lengths");
- }
- int left = len;
- for (byte[] array : rest) {
- left -= array.length;
- }
- if (left != 0) {
- throw new IllegalArgumentException("XOR key and total output arrays have different lengths");
- }
-
- byte[] ciphertext = new byte[len];
- byte[] HMAC = new byte[32];
- System.arraycopy(bundleBytes, 0, ciphertext, 0, len);
- System.arraycopy(bundleBytes, len, HMAC, 0, 32);
-
- Mac hmacHasher = HKDF.makeHMACHasher(respHMACKey);
- byte[] computedHMAC = hmacHasher.doFinal(ciphertext);
- if (!Arrays.equals(computedHMAC, HMAC)) {
- throw new FxAccountClientException("Bad message HMAC");
- }
-
- int offset = 0;
- for (byte[] array : rest) {
- for (int i = 0; i < array.length; i++) {
- array[i] = (byte) (respXORKey[offset + i] ^ ciphertext[offset + i]);
- }
- offset += array.length;
- }
- }
-
- protected void unbundleBody(ExtendedJSONObject body, byte[] requestKey, byte[] ctxInfo, byte[]... rest) throws Exception {
- int length = 0;
- for (byte[] array : rest) {
- length += array.length;
- }
-
- if (body == null) {
- throw new FxAccountClientException("body must be non-null");
- }
- String bundle = body.getString("bundle");
- if (bundle == null) {
- throw new FxAccountClientException("bundle must be a non-null string");
- }
- byte[] bundleBytes = Utils.hex2Byte(bundle);
-
- final byte[] respHMACKey = new byte[32];
- final byte[] respXORKey = new byte[length];
- HKDF.deriveMany(requestKey, new byte[0], ctxInfo, respHMACKey, respXORKey);
- unbundleBytes(bundleBytes, respHMACKey, respXORKey, rest);
- }
-
- public void keys(byte[] keyFetchToken, final RequestDelegate<TwoKeys> delegate) {
- final byte[] tokenId = new byte[32];
- final byte[] reqHMACKey = new byte[32];
- final byte[] requestKey = new byte[32];
- try {
- HKDF.deriveMany(keyFetchToken, new byte[0], FxAccountUtils.KW("keyFetchToken"), tokenId, reqHMACKey, requestKey);
- } catch (Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- BaseResource resource;
- try {
- resource = getBaseResource("account/keys");
- } catch (URISyntaxException | UnsupportedEncodingException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<TwoKeys>(resource, delegate, ResponseType.JSON_OBJECT, tokenId, reqHMACKey) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) throws Exception {
- byte[] kA = new byte[FxAccountUtils.CRYPTO_KEY_LENGTH_BYTES];
- byte[] wrapkB = new byte[FxAccountUtils.CRYPTO_KEY_LENGTH_BYTES];
- unbundleBody(body, requestKey, FxAccountUtils.KW("account/keys"), kA, wrapkB);
- delegate.handleSuccess(new TwoKeys(kA, wrapkB));
- }
- };
- resource.get();
- }
-
- /**
- * Thin container for account status response.
- */
- public static class AccountStatusResponse {
- public final boolean exists;
- public AccountStatusResponse(boolean exists) {
- this.exists = exists;
- }
- }
-
- /**
- * Query the account status of an account given a uid.
- *
- * @param uid to query.
- * @param delegate to invoke callbacks.
- */
- public void accountStatus(String uid, final RequestDelegate<AccountStatusResponse> delegate) {
- final BaseResource resource;
- try {
- final Map<String, String> params = new HashMap<>(1);
- params.put("uid", uid);
- resource = getBaseResource("account/status", params);
- } catch (URISyntaxException | UnsupportedEncodingException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<AccountStatusResponse>(resource, delegate, ResponseType.JSON_OBJECT) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) throws Exception {
- boolean exists = body.getBoolean(JSON_KEY_EXISTS);
- delegate.handleSuccess(new AccountStatusResponse(exists));
- }
- };
- resource.get();
- }
-
- /**
- * Thin container for recovery email status response.
- */
- public static class RecoveryEmailStatusResponse {
- public final String email;
- public final boolean verified;
- public RecoveryEmailStatusResponse(String email, boolean verified) {
- this.email = email;
- this.verified = verified;
- }
- }
-
- /**
- * Query the recovery email status of an account given a valid session token.
- * <p>
- * This API is a little odd: the auth server returns the email and
- * verification state of the account that corresponds to the (opaque) session
- * token. It might fail if the session token is unknown (or invalid, or
- * revoked).
- *
- * @param sessionToken
- * to query.
- * @param delegate
- * to invoke callbacks.
- */
- public void recoveryEmailStatus(byte[] sessionToken, final RequestDelegate<RecoveryEmailStatusResponse> delegate) {
- final byte[] tokenId = new byte[32];
- final byte[] reqHMACKey = new byte[32];
- final byte[] requestKey = new byte[32];
- try {
- HKDF.deriveMany(sessionToken, new byte[0], FxAccountUtils.KW("sessionToken"), tokenId, reqHMACKey, requestKey);
- } catch (Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- BaseResource resource;
- try {
- resource = getBaseResource("recovery_email/status");
- } catch (URISyntaxException | UnsupportedEncodingException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<RecoveryEmailStatusResponse>(resource, delegate, ResponseType.JSON_OBJECT, tokenId, reqHMACKey) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) throws Exception {
- String[] requiredStringFields = new String[] { JSON_KEY_EMAIL };
- body.throwIfFieldsMissingOrMisTyped(requiredStringFields, String.class);
- String email = body.getString(JSON_KEY_EMAIL);
- Boolean verified = body.getBoolean(JSON_KEY_VERIFIED);
- delegate.handleSuccess(new RecoveryEmailStatusResponse(email, verified));
- }
- };
- resource.get();
- }
-
- @SuppressWarnings("unchecked")
- public void sign(final byte[] sessionToken, final ExtendedJSONObject publicKey, long durationInMilliseconds, final RequestDelegate<String> delegate) {
- final ExtendedJSONObject body = new ExtendedJSONObject();
- body.put("publicKey", publicKey);
- body.put("duration", durationInMilliseconds);
-
- final byte[] tokenId = new byte[32];
- final byte[] reqHMACKey = new byte[32];
- try {
- HKDF.deriveMany(sessionToken, new byte[0], FxAccountUtils.KW("sessionToken"), tokenId, reqHMACKey);
- } catch (Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- BaseResource resource;
- try {
- resource = getBaseResource("certificate/sign");
- } catch (URISyntaxException | UnsupportedEncodingException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<String>(resource, delegate, ResponseType.JSON_OBJECT, tokenId, reqHMACKey) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) throws Exception {
- String cert = body.getString("cert");
- if (cert == null) {
- delegate.handleError(new FxAccountClientException("cert must be a non-null string"));
- return;
- }
- delegate.handleSuccess(cert);
- }
- };
- post(resource, body);
- }
-
- protected static final String[] LOGIN_RESPONSE_REQUIRED_STRING_FIELDS = new String[] { JSON_KEY_UID, JSON_KEY_SESSIONTOKEN };
- protected static final String[] LOGIN_RESPONSE_REQUIRED_STRING_FIELDS_KEYS = new String[] { JSON_KEY_UID, JSON_KEY_SESSIONTOKEN, JSON_KEY_KEYFETCHTOKEN, };
- protected static final String[] LOGIN_RESPONSE_REQUIRED_BOOLEAN_FIELDS = new String[] { JSON_KEY_VERIFIED };
-
- /**
- * Thin container for login response.
- * <p>
- * The <code>remoteEmail</code> field is the email address as normalized by the
- * server, and is <b>not necessarily</b> the email address delivered to the
- * <code>login</code> or <code>create</code> call.
- */
- public static class LoginResponse {
- public final String remoteEmail;
- public final String uid;
- public final byte[] sessionToken;
- public final boolean verified;
- public final byte[] keyFetchToken;
-
- public LoginResponse(String remoteEmail, String uid, boolean verified, byte[] sessionToken, byte[] keyFetchToken) {
- this.remoteEmail = remoteEmail;
- this.uid = uid;
- this.verified = verified;
- this.sessionToken = sessionToken;
- this.keyFetchToken = keyFetchToken;
- }
- }
-
- // Public for testing only; prefer login and loginAndGetKeys (without boolean parameter).
- public void login(final byte[] emailUTF8, final byte[] quickStretchedPW, final boolean getKeys,
- final Map<String, String> queryParameters,
- final RequestDelegate<LoginResponse> delegate) {
- final BaseResource resource;
- final ExtendedJSONObject body;
- try {
- final String path = "account/login";
- final Map<String, String> modifiedParameters = new HashMap<>();
- if (queryParameters != null) {
- modifiedParameters.putAll(queryParameters);
- }
- if (getKeys) {
- modifiedParameters.put("keys", "true");
- }
- resource = getBaseResource(path, modifiedParameters);
- body = new FxAccount20LoginDelegate(emailUTF8, quickStretchedPW).getCreateBody();
- } catch (Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<LoginResponse>(resource, delegate, ResponseType.JSON_OBJECT) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) throws Exception {
- final String[] requiredStringFields = getKeys ? LOGIN_RESPONSE_REQUIRED_STRING_FIELDS_KEYS : LOGIN_RESPONSE_REQUIRED_STRING_FIELDS;
- body.throwIfFieldsMissingOrMisTyped(requiredStringFields, String.class);
-
- final String[] requiredBooleanFields = LOGIN_RESPONSE_REQUIRED_BOOLEAN_FIELDS;
- body.throwIfFieldsMissingOrMisTyped(requiredBooleanFields, Boolean.class);
-
- String uid = body.getString(JSON_KEY_UID);
- boolean verified = body.getBoolean(JSON_KEY_VERIFIED);
- byte[] sessionToken = Utils.hex2Byte(body.getString(JSON_KEY_SESSIONTOKEN));
- byte[] keyFetchToken = null;
- if (getKeys) {
- keyFetchToken = Utils.hex2Byte(body.getString(JSON_KEY_KEYFETCHTOKEN));
- }
- LoginResponse loginResponse = new LoginResponse(new String(emailUTF8, "UTF-8"), uid, verified, sessionToken, keyFetchToken);
-
- delegate.handleSuccess(loginResponse);
- }
- };
-
- post(resource, body);
- }
-
- public void createAccount(final byte[] emailUTF8, final byte[] quickStretchedPW,
- final boolean getKeys,
- final boolean preVerified,
- final Map<String, String> queryParameters,
- final RequestDelegate<LoginResponse> delegate) {
- final BaseResource resource;
- final ExtendedJSONObject body;
- try {
- final String path = "account/create";
- final Map<String, String> modifiedParameters = new HashMap<>();
- if (queryParameters != null) {
- modifiedParameters.putAll(queryParameters);
- }
- if (getKeys) {
- modifiedParameters.put("keys", "true");
- }
- resource = getBaseResource(path, modifiedParameters);
- body = new FxAccount20CreateDelegate(emailUTF8, quickStretchedPW, preVerified).getCreateBody();
- } catch (Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- // This is very similar to login, except verified is not required.
- resource.delegate = new ResourceDelegate<LoginResponse>(resource, delegate, ResponseType.JSON_OBJECT) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) throws Exception {
- final String[] requiredStringFields = getKeys ? LOGIN_RESPONSE_REQUIRED_STRING_FIELDS_KEYS : LOGIN_RESPONSE_REQUIRED_STRING_FIELDS;
- body.throwIfFieldsMissingOrMisTyped(requiredStringFields, String.class);
-
- String uid = body.getString(JSON_KEY_UID);
- boolean verified = false; // In production, we're definitely not verified immediately upon creation.
- Boolean tempVerified = body.getBoolean(JSON_KEY_VERIFIED);
- if (tempVerified != null) {
- verified = tempVerified;
- }
- byte[] sessionToken = Utils.hex2Byte(body.getString(JSON_KEY_SESSIONTOKEN));
- byte[] keyFetchToken = null;
- if (getKeys) {
- keyFetchToken = Utils.hex2Byte(body.getString(JSON_KEY_KEYFETCHTOKEN));
- }
- LoginResponse loginResponse = new LoginResponse(new String(emailUTF8, "UTF-8"), uid, verified, sessionToken, keyFetchToken);
-
- delegate.handleSuccess(loginResponse);
- }
- };
-
- post(resource, body);
- }
-
- /**
- * We want users to be able to enter their email address case-insensitively.
- * We stretch the password locally using the email address as a salt, to make
- * dictionary attacks more expensive. This means that a client with a
- * case-differing email address is unable to produce the correct
- * authorization, even though it knows the password. In this case, the server
- * returns the email that the account was created with, so that the client can
- * re-stretch the password locally with the correct email salt. This version
- * of <code>login</code> retries at most one time with a server provided email
- * address.
- * <p>
- * Be aware that consumers will not see the initial error response from the
- * server providing an alternate email (if there is one).
- *
- * @param emailUTF8
- * user entered email address.
- * @param stretcher
- * delegate to stretch and re-stretch password.
- * @param getKeys
- * true if a <code>keyFetchToken</code> should be returned (in
- * addition to the standard <code>sessionToken</code>).
- * @param queryParameters
- * @param delegate
- * to invoke callbacks.
- */
- public void login(final byte[] emailUTF8, final PasswordStretcher stretcher, final boolean getKeys,
- final Map<String, String> queryParameters,
- final RequestDelegate<LoginResponse> delegate) {
- byte[] quickStretchedPW;
- try {
- FxAccountUtils.pii(LOG_TAG, "Trying user provided email: '" + new String(emailUTF8, "UTF-8") + "'" );
- quickStretchedPW = stretcher.getQuickStretchedPW(emailUTF8);
- } catch (Exception e) {
- delegate.handleError(e);
- return;
- }
-
- this.login(emailUTF8, quickStretchedPW, getKeys, queryParameters, new RequestDelegate<LoginResponse>() {
- @Override
- public void handleSuccess(LoginResponse result) {
- delegate.handleSuccess(result);
- }
-
- @Override
- public void handleError(Exception e) {
- delegate.handleError(e);
- }
-
- @Override
- public void handleFailure(FxAccountClientRemoteException e) {
- String alternateEmail = e.body.getString(JSON_KEY_EMAIL);
- if (!e.isBadEmailCase() || alternateEmail == null) {
- delegate.handleFailure(e);
- return;
- };
-
- Logger.info(LOG_TAG, "Server returned alternate email; retrying login with provided email.");
- FxAccountUtils.pii(LOG_TAG, "Trying server provided email: '" + alternateEmail + "'" );
-
- try {
- // Nota bene: this is not recursive, since we call the fixed password
- // signature here, which invokes a non-retrying version.
- byte[] alternateEmailUTF8 = alternateEmail.getBytes("UTF-8");
- byte[] alternateQuickStretchedPW = stretcher.getQuickStretchedPW(alternateEmailUTF8);
- login(alternateEmailUTF8, alternateQuickStretchedPW, getKeys, queryParameters, delegate);
- } catch (Exception innerException) {
- delegate.handleError(innerException);
- return;
- }
- }
- });
- }
-
- /**
- * Registers a device given a valid session token.
- *
- * @param sessionToken to query.
- * @param delegate to invoke callbacks.
- */
- @Override
- public void registerOrUpdateDevice(byte[] sessionToken, FxAccountDevice device, RequestDelegate<FxAccountDevice> delegate) {
- final byte[] tokenId = new byte[32];
- final byte[] reqHMACKey = new byte[32];
- final byte[] requestKey = new byte[32];
- try {
- HKDF.deriveMany(sessionToken, new byte[0], FxAccountUtils.KW("sessionToken"), tokenId, reqHMACKey, requestKey);
- } catch (Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- final BaseResource resource;
- final ExtendedJSONObject body;
- try {
- resource = getBaseResource("account/device");
- body = device.toJson();
- } catch (URISyntaxException | UnsupportedEncodingException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<FxAccountDevice>(resource, delegate, ResponseType.JSON_OBJECT, tokenId, reqHMACKey) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
- try {
- delegate.handleSuccess(FxAccountDevice.fromJson(body));
- } catch (Exception e) {
- delegate.handleError(e);
- }
- }
- };
-
- post(resource, body);
- }
-
- @Override
- public void deviceList(byte[] sessionToken, RequestDelegate<FxAccountDevice[]> delegate) {
- final byte[] tokenId = new byte[32];
- final byte[] reqHMACKey = new byte[32];
- final byte[] requestKey = new byte[32];
- try {
- HKDF.deriveMany(sessionToken, new byte[0], FxAccountUtils.KW("sessionToken"), tokenId, reqHMACKey, requestKey);
- } catch (Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- final BaseResource resource;
- try {
- resource = getBaseResource("account/devices");
- } catch (URISyntaxException | UnsupportedEncodingException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<FxAccountDevice[]>(resource, delegate, ResponseType.JSON_ARRAY, tokenId, reqHMACKey) {
- @Override
- public void handleSuccess(int status, HttpResponse response, JSONArray devicesJson) {
- try {
- FxAccountDevice[] devices = new FxAccountDevice[devicesJson.size()];
- for (int i = 0; i < devices.length; i++) {
- ExtendedJSONObject deviceJson = new ExtendedJSONObject((JSONObject) devicesJson.get(i));
- devices[i] = FxAccountDevice.fromJson(deviceJson);
- }
- delegate.handleSuccess(devices);
- } catch (Exception e) {
- delegate.handleError(e);
- }
- }
- };
-
- resource.get();
- }
-
- @Override
- public void notifyDevices(@NonNull byte[] sessionToken, @NonNull List<String> deviceIds, ExtendedJSONObject payload, Long TTL, RequestDelegate<ExtendedJSONObject> delegate) {
- final byte[] tokenId = new byte[32];
- final byte[] reqHMACKey = new byte[32];
- final byte[] requestKey = new byte[32];
- try {
- HKDF.deriveMany(sessionToken, new byte[0], FxAccountUtils.KW("sessionToken"), tokenId, reqHMACKey, requestKey);
- } catch (Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- final BaseResource resource;
- final ExtendedJSONObject body = createNotifyDevicesBody(deviceIds, payload, TTL);
- try {
- resource = getBaseResource("account/devices/notify");
- } catch (URISyntaxException | UnsupportedEncodingException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<ExtendedJSONObject>(resource, delegate, ResponseType.JSON_OBJECT, tokenId, reqHMACKey) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
- try {
- delegate.handleSuccess(body);
- } catch (Exception e) {
- delegate.handleError(e);
- }
- }
- };
-
- post(resource, body);
- }
-
- @NonNull
- @SuppressWarnings("unchecked")
- private ExtendedJSONObject createNotifyDevicesBody(@NonNull List<String> deviceIds, ExtendedJSONObject payload, Long TTL) {
- final ExtendedJSONObject body = new ExtendedJSONObject();
- final JSONArray to = new JSONArray();
- to.addAll(deviceIds);
- body.put("to", to);
- if (payload != null) {
- body.put("payload", payload);
- }
- if (TTL != null) {
- body.put("TTL", TTL);
- }
- return body;
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClientException.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClientException.java
deleted file mode 100644
index 28ee5630e..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountClientException.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/* 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.background.fxa;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.HTTPFailureException;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.HttpStatus;
-
-/**
- * From <a href="https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md">https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md</a>.
- */
-public class FxAccountClientException extends Exception {
- private static final long serialVersionUID = 7953459541558266597L;
-
- public FxAccountClientException(String detailMessage) {
- super(detailMessage);
- }
-
- public FxAccountClientException(Exception e) {
- super(e);
- }
-
- public static class FxAccountClientRemoteException extends FxAccountClientException {
- private static final long serialVersionUID = 2209313149952001097L;
-
- public final HttpResponse response;
- public final long httpStatusCode;
- public final long apiErrorNumber;
- public final String error;
- public final String message;
- public final String info;
- public final ExtendedJSONObject body;
-
- public FxAccountClientRemoteException(HttpResponse response, long httpStatusCode, long apiErrorNumber, String error, String message, String info, ExtendedJSONObject body) {
- super(new HTTPFailureException(new SyncStorageResponse(response)));
- if (body == null) {
- throw new IllegalArgumentException("body must not be null");
- }
- this.response = response;
- this.httpStatusCode = httpStatusCode;
- this.apiErrorNumber = apiErrorNumber;
- this.error = error;
- this.message = message;
- this.info = info;
- this.body = body;
- }
-
- @Override
- public String toString() {
- return "<FxAccountClientRemoteException " + this.httpStatusCode + " [" + this.apiErrorNumber + "]: " + this.message + ">";
- }
-
- public boolean isInvalidAuthentication() {
- return httpStatusCode == HttpStatus.SC_UNAUTHORIZED;
- }
-
- public boolean isAccountAlreadyExists() {
- return apiErrorNumber == FxAccountRemoteError.ATTEMPT_TO_CREATE_AN_ACCOUNT_THAT_ALREADY_EXISTS;
- }
-
- public boolean isAccountDoesNotExist() {
- return apiErrorNumber == FxAccountRemoteError.ATTEMPT_TO_ACCESS_AN_ACCOUNT_THAT_DOES_NOT_EXIST;
- }
-
- public boolean isBadPassword() {
- return apiErrorNumber == FxAccountRemoteError.INCORRECT_PASSWORD;
- }
-
- public boolean isUnverified() {
- return apiErrorNumber == FxAccountRemoteError.ATTEMPT_TO_OPERATE_ON_AN_UNVERIFIED_ACCOUNT;
- }
-
- public boolean isUpgradeRequired() {
- return
- apiErrorNumber == FxAccountRemoteError.ENDPOINT_IS_NO_LONGER_SUPPORTED ||
- apiErrorNumber == FxAccountRemoteError.INCORRECT_LOGIN_METHOD_FOR_THIS_ACCOUNT ||
- apiErrorNumber == FxAccountRemoteError.INCORRECT_KEY_RETRIEVAL_METHOD_FOR_THIS_ACCOUNT ||
- apiErrorNumber == FxAccountRemoteError.INCORRECT_API_VERSION_FOR_THIS_ACCOUNT;
- }
-
- public boolean isTooManyRequests() {
- return apiErrorNumber == FxAccountRemoteError.CLIENT_HAS_SENT_TOO_MANY_REQUESTS;
- }
-
- public boolean isServerUnavailable() {
- return apiErrorNumber == FxAccountRemoteError.SERVICE_TEMPORARILY_UNAVAILABLE_DUE_TO_HIGH_LOAD;
- }
-
- public boolean isBadEmailCase() {
- return apiErrorNumber == FxAccountRemoteError.INCORRECT_EMAIL_CASE;
- }
-
- public boolean isAccountLocked() {
- return apiErrorNumber == FxAccountRemoteError.ACCOUNT_LOCKED;
- }
-
- public int getErrorMessageStringResource() {
- if (isUpgradeRequired()) {
- return R.string.fxaccount_remote_error_UPGRADE_REQUIRED;
- } else if (isAccountAlreadyExists()) {
- return R.string.fxaccount_remote_error_ATTEMPT_TO_CREATE_AN_ACCOUNT_THAT_ALREADY_EXISTS;
- } else if (isAccountDoesNotExist()) {
- return R.string.fxaccount_remote_error_ATTEMPT_TO_ACCESS_AN_ACCOUNT_THAT_DOES_NOT_EXIST;
- } else if (isBadPassword()) {
- return R.string.fxaccount_remote_error_INCORRECT_PASSWORD;
- } else if (isUnverified()) {
- return R.string.fxaccount_remote_error_ATTEMPT_TO_OPERATE_ON_AN_UNVERIFIED_ACCOUNT;
- } else if (isTooManyRequests()) {
- return R.string.fxaccount_remote_error_CLIENT_HAS_SENT_TOO_MANY_REQUESTS;
- } else if (isServerUnavailable()) {
- return R.string.fxaccount_remote_error_SERVICE_TEMPORARILY_UNAVAILABLE_TO_DUE_HIGH_LOAD;
- } else if (isAccountLocked()) {
- return R.string.fxaccount_remote_error_ACCOUNT_LOCKED;
- } else {
- return R.string.fxaccount_remote_error_UNKNOWN_ERROR;
- }
- }
- }
-
- public static class FxAccountClientMalformedResponseException extends FxAccountClientRemoteException {
- private static final long serialVersionUID = 2209313149952001098L;
-
- public FxAccountClientMalformedResponseException(HttpResponse response) {
- super(response, 0, FxAccountRemoteError.UNKNOWN_ERROR, "Response malformed", "Response malformed", "Response malformed", new ExtendedJSONObject());
- }
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountRemoteError.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountRemoteError.java
deleted file mode 100644
index 5a89561cb..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountRemoteError.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* 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.background.fxa;
-
-public interface FxAccountRemoteError {
- public static final int ATTEMPT_TO_CREATE_AN_ACCOUNT_THAT_ALREADY_EXISTS = 101;
- public static final int ATTEMPT_TO_ACCESS_AN_ACCOUNT_THAT_DOES_NOT_EXIST = 102;
- public static final int INCORRECT_PASSWORD = 103;
- public static final int ATTEMPT_TO_OPERATE_ON_AN_UNVERIFIED_ACCOUNT = 104;
- public static final int INVALID_VERIFICATION_CODE = 105;
- public static final int REQUEST_BODY_WAS_NOT_VALID_JSON = 106;
- public static final int REQUEST_BODY_CONTAINS_INVALID_PARAMETERS = 107;
- public static final int REQUEST_BODY_MISSING_REQUIRED_PARAMETERS = 108;
- public static final int INVALID_REQUEST_SIGNATURE = 109;
- public static final int INVALID_AUTHENTICATION_TOKEN = 110;
- public static final int INVALID_AUTHENTICATION_TIMESTAMP = 111;
- public static final int CONTENT_LENGTH_HEADER_WAS_NOT_PROVIDED = 112;
- public static final int REQUEST_BODY_TOO_LARGE = 113;
- public static final int CLIENT_HAS_SENT_TOO_MANY_REQUESTS = 114;
- public static final int INVALID_NONCE_IN_REQUEST_SIGNATURE = 115;
- public static final int ENDPOINT_IS_NO_LONGER_SUPPORTED = 116;
- public static final int INCORRECT_LOGIN_METHOD_FOR_THIS_ACCOUNT = 117;
- public static final int INCORRECT_KEY_RETRIEVAL_METHOD_FOR_THIS_ACCOUNT = 118;
- public static final int INCORRECT_API_VERSION_FOR_THIS_ACCOUNT = 119;
- public static final int INCORRECT_EMAIL_CASE = 120;
- public static final int ACCOUNT_LOCKED = 121;
- public static final int UNKNOWN_DEVICE = 123;
- public static final int DEVICE_SESSION_CONFLICT = 124;
- public static final int SERVICE_TEMPORARILY_UNAVAILABLE_DUE_TO_HIGH_LOAD = 201;
- public static final int UNKNOWN_ERROR = 999;
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java
deleted file mode 100644
index 2d29725a0..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/FxAccountUtils.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/* 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.background.fxa;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.nativecode.NativeCrypto;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.HKDF;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.crypto.PBKDF2;
-
-import android.content.Context;
-
-public class FxAccountUtils {
- private static final String LOG_TAG = FxAccountUtils.class.getSimpleName();
-
- public static final int SALT_LENGTH_BYTES = 32;
- public static final int SALT_LENGTH_HEX = 2 * SALT_LENGTH_BYTES;
-
- public static final int HASH_LENGTH_BYTES = 16;
- public static final int HASH_LENGTH_HEX = 2 * HASH_LENGTH_BYTES;
-
- public static final int CRYPTO_KEY_LENGTH_BYTES = 32;
- public static final int CRYPTO_KEY_LENGTH_HEX = 2 * CRYPTO_KEY_LENGTH_BYTES;
-
- public static final String KW_VERSION_STRING = "identity.mozilla.com/picl/v1/";
-
- public static final int NUMBER_OF_QUICK_STRETCH_ROUNDS = 1000;
-
- // For extra debugging. Not final so it can be changed from Fennec, or from
- // an add-on.
- public static boolean LOG_PERSONAL_INFORMATION = false;
-
- public static void pii(String tag, String message) {
- if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
- Logger.info(tag, "$$FxA PII$$: " + message);
- }
- }
-
- public static String bytes(String string) throws UnsupportedEncodingException {
- return Utils.byte2Hex(string.getBytes("UTF-8"));
- }
-
- public static byte[] KW(String name) throws UnsupportedEncodingException {
- return Utils.concatAll(
- KW_VERSION_STRING.getBytes("UTF-8"),
- name.getBytes("UTF-8"));
- }
-
- public static byte[] KWE(String name, byte[] emailUTF8) throws UnsupportedEncodingException {
- return Utils.concatAll(
- KW_VERSION_STRING.getBytes("UTF-8"),
- name.getBytes("UTF-8"),
- ":".getBytes("UTF-8"),
- emailUTF8);
- }
-
- /**
- * Calculate the SRP verifier <tt>x</tt> value.
- */
- public static BigInteger srpVerifierLowercaseX(byte[] emailUTF8, byte[] srpPWBytes, byte[] srpSaltBytes)
- throws NoSuchAlgorithmException, UnsupportedEncodingException {
- byte[] inner = Utils.sha256(Utils.concatAll(emailUTF8, ":".getBytes("UTF-8"), srpPWBytes));
- byte[] outer = Utils.sha256(Utils.concatAll(srpSaltBytes, inner));
- return new BigInteger(1, outer);
- }
-
- /**
- * Calculate the SRP verifier <tt>v</tt> value.
- */
- public static BigInteger srpVerifierLowercaseV(byte[] emailUTF8, byte[] srpPWBytes, byte[] srpSaltBytes, BigInteger g, BigInteger N)
- throws NoSuchAlgorithmException, UnsupportedEncodingException {
- BigInteger x = srpVerifierLowercaseX(emailUTF8, srpPWBytes, srpSaltBytes);
- BigInteger v = g.modPow(x, N);
- return v;
- }
-
- /**
- * Format x modulo N in hexadecimal, using as many characters as N takes (in hexadecimal).
- * @param x to format.
- * @param N modulus.
- * @return x modulo N in hexadecimal.
- */
- public static String hexModN(BigInteger x, BigInteger N) {
- int byteLength = (N.bitLength() + 7) / 8;
- int hexLength = 2 * byteLength;
- return Utils.byte2Hex(Utils.hex2Byte((x.mod(N)).toString(16), byteLength), hexLength);
- }
-
- /**
- * The first engineering milestone of PICL (Profile-in-the-Cloud) was
- * comprised of Sync 1.1 fronted by a Firefox Account. The sync key was
- * generated from the Firefox Account password-derived kB value using this
- * method.
- */
- public static KeyBundle generateSyncKeyBundle(final byte[] kB) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
- byte[] encryptionKey = new byte[32];
- byte[] hmacKey = new byte[32];
- byte[] derived = HKDF.derive(kB, new byte[0], FxAccountUtils.KW("oldsync"), 2*32);
- System.arraycopy(derived, 0*32, encryptionKey, 0, 1*32);
- System.arraycopy(derived, 1*32, hmacKey, 0, 1*32);
- return new KeyBundle(encryptionKey, hmacKey);
- }
-
- /**
- * Firefox Accounts are password authenticated, but clients should not store
- * the plain-text password for any amount of time. Equivalent, but slightly
- * more secure, is the quickly client-side stretched password.
- * <p>
- * We separate this since multiple login-time operations want it, and the
- * PBKDF2 operation is computationally expensive.
- */
- public static byte[] generateQuickStretchedPW(byte[] emailUTF8, byte[] passwordUTF8) throws GeneralSecurityException, UnsupportedEncodingException {
- byte[] S = FxAccountUtils.KWE("quickStretch", emailUTF8);
- try {
- return NativeCrypto.pbkdf2SHA256(passwordUTF8, S, NUMBER_OF_QUICK_STRETCH_ROUNDS, 32);
- } catch (final LinkageError e) {
- // This will throw UnsatisfiedLinkError (missing mozglue) the first time it is called, and
- // ClassNotDefFoundError, for the uninitialized NativeCrypto class, each subsequent time this
- // is called; LinkageError is their common ancestor.
- Logger.warn(LOG_TAG, "Got throwable stretching password using native pbkdf2SHA256 " +
- "implementation; ignoring and using Java implementation.", e);
- return PBKDF2.pbkdf2SHA256(passwordUTF8, S, NUMBER_OF_QUICK_STRETCH_ROUNDS, 32);
- }
- }
-
- /**
- * The password-derived credential used to authenticate to the Firefox Account
- * auth server.
- */
- public static byte[] generateAuthPW(byte[] quickStretchedPW) throws GeneralSecurityException, UnsupportedEncodingException {
- return HKDF.derive(quickStretchedPW, new byte[0], FxAccountUtils.KW("authPW"), 32);
- }
-
- /**
- * The password-derived credential used to unwrap keys managed by the Firefox
- * Account auth server.
- */
- public static byte[] generateUnwrapBKey(byte[] quickStretchedPW) throws GeneralSecurityException, UnsupportedEncodingException {
- return HKDF.derive(quickStretchedPW, new byte[0], FxAccountUtils.KW("unwrapBkey"), 32);
- }
-
- public static byte[] unwrapkB(byte[] unwrapkB, byte[] wrapkB) {
- if (unwrapkB == null) {
- throw new IllegalArgumentException("unwrapkB must not be null");
- }
- if (wrapkB == null) {
- throw new IllegalArgumentException("wrapkB must not be null");
- }
- if (unwrapkB.length != CRYPTO_KEY_LENGTH_BYTES || wrapkB.length != CRYPTO_KEY_LENGTH_BYTES) {
- throw new IllegalArgumentException("unwrapkB and wrapkB must be " + CRYPTO_KEY_LENGTH_BYTES + " bytes long");
- }
- byte[] kB = new byte[CRYPTO_KEY_LENGTH_BYTES];
- for (int i = 0; i < wrapkB.length; i++) {
- kB[i] = (byte) (wrapkB[i] ^ unwrapkB[i]);
- }
- return kB;
- }
-
- /**
- * The token server accepts an X-Client-State header, which is the
- * lowercase-hex-encoded first 16 bytes of the SHA-256 hash of the
- * bytes of kB.
- * @param kB a byte array, expected to be 32 bytes long.
- * @return a 32-character string.
- * @throws NoSuchAlgorithmException
- */
- public static String computeClientState(byte[] kB) throws NoSuchAlgorithmException {
- if (kB == null ||
- kB.length != 32) {
- throw new IllegalArgumentException("Unexpected kB.");
- }
- byte[] sha256 = Utils.sha256(kB);
- byte[] truncated = new byte[16];
- System.arraycopy(sha256, 0, truncated, 0, 16);
- return Utils.byte2Hex(truncated); // This is automatically lowercase.
- }
-
- /**
- * Given an endpoint, calculate the corresponding BrowserID audience.
- * <p>
- * This is the domain, in web parlance.
- *
- * @param serverURI endpoint.
- * @return BrowserID audience.
- * @throws URISyntaxException
- */
- public static String getAudienceForURL(String serverURI) throws URISyntaxException {
- URI uri = new URI(serverURI);
- return new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), null, null, null).toString();
- }
-
- public static String defaultClientName(Context context) {
- String name = AppConstants.MOZ_APP_DISPLAYNAME; // The display name is never translated.
- // Change "Firefox Aurora" or similar into "Aurora".
- if (name.contains("Aurora")) {
- name = "Aurora";
- } else if (name.contains("Beta")) {
- name = "Beta";
- } else if (name.contains("Nightly")) {
- name = "Nightly";
- }
- return context.getResources().getString(R.string.sync_default_client_name, name, android.os.Build.MODEL);
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/PasswordStretcher.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/PasswordStretcher.java
deleted file mode 100644
index 2debf3c77..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/PasswordStretcher.java
+++ /dev/null
@@ -1,12 +0,0 @@
-/* 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.background.fxa;
-
-import java.io.UnsupportedEncodingException;
-import java.security.GeneralSecurityException;
-
-public interface PasswordStretcher {
- public byte[] getQuickStretchedPW(byte[] emailUTF8) throws UnsupportedEncodingException, GeneralSecurityException;
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java
deleted file mode 100644
index bf4b1bc97..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/QuickPasswordStretcher.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/* 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.background.fxa;
-
-import java.io.UnsupportedEncodingException;
-import java.security.GeneralSecurityException;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.mozilla.gecko.sync.Utils;
-
-public class QuickPasswordStretcher implements PasswordStretcher {
- protected final String password;
- protected final Map<String, String> cache = new HashMap<String, String>();
-
- public QuickPasswordStretcher(String password) {
- this.password = password;
- }
-
- @Override
- public synchronized byte[] getQuickStretchedPW(byte[] emailUTF8) throws UnsupportedEncodingException, GeneralSecurityException {
- if (emailUTF8 == null) {
- throw new IllegalArgumentException("emailUTF8 must not be null");
- }
- String key = Utils.byte2Hex(emailUTF8);
- if (!cache.containsKey(key)) {
- byte[] value = FxAccountUtils.generateQuickStretchedPW(emailUTF8, password.getBytes("UTF-8"));
- cache.put(key, Utils.byte2Hex(value));
- return value;
- }
- return Utils.hex2Byte(cache.get(key));
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/SkewHandler.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/SkewHandler.java
deleted file mode 100644
index 9d0ad5e03..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/SkewHandler.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/* 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.background.fxa;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.HashMap;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.net.Resource;
-
-import ch.boye.httpclientandroidlib.Header;
-import ch.boye.httpclientandroidlib.HttpHeaders;
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.impl.cookie.DateParseException;
-import ch.boye.httpclientandroidlib.impl.cookie.DateUtils;
-
-public class SkewHandler {
- private static final String LOG_TAG = "SkewHandler";
- protected volatile long skewMillis = 0L;
- protected final String hostname;
-
- private static final HashMap<String, SkewHandler> skewHandlers = new HashMap<String, SkewHandler>();
-
- public static SkewHandler getSkewHandlerForResource(final Resource resource) {
- return getSkewHandlerForHostname(resource.getHostname());
- }
-
- public static SkewHandler getSkewHandlerFromEndpointString(final String url) throws URISyntaxException {
- if (url == null) {
- throw new IllegalArgumentException("url must not be null.");
- }
- URI u = new URI(url);
- return getSkewHandlerForHostname(u.getHost());
- }
-
- public static synchronized SkewHandler getSkewHandlerForHostname(final String hostname) {
- SkewHandler handler = skewHandlers.get(hostname);
- if (handler == null) {
- handler = new SkewHandler(hostname);
- skewHandlers.put(hostname, handler);
- }
- return handler;
- }
-
- public static synchronized void clearSkewHandlers() {
- skewHandlers.clear();
- }
-
- public SkewHandler(final String hostname) {
- this.hostname = hostname;
- }
-
- public boolean updateSkewFromServerMillis(long millis, long now) {
- skewMillis = millis - now;
- Logger.debug(LOG_TAG, "Updated skew: " + skewMillis + "ms for hostname " + this.hostname);
- return true;
- }
-
- public boolean updateSkewFromHTTPDateString(String date, long now) {
- try {
- final long millis = DateUtils.parseDate(date).getTime();
- return updateSkewFromServerMillis(millis, now);
- } catch (DateParseException e) {
- Logger.warn(LOG_TAG, "Unexpected: invalid Date header from " + this.hostname);
- return false;
- }
- }
-
- public boolean updateSkewFromDateHeader(Header header, long now) {
- String date = header.getValue();
- if (null == date) {
- Logger.warn(LOG_TAG, "Unexpected: null Date header from " + this.hostname);
- return false;
- }
- return updateSkewFromHTTPDateString(date, now);
- }
-
- /**
- * Update our tracked skew value to account for the local clock differing from
- * the server's.
- *
- * @param response
- * the received HTTP response.
- * @param now
- * the current time in milliseconds.
- * @return true if the skew value was updated, false otherwise.
- */
- public boolean updateSkew(HttpResponse response, long now) {
- Header header = response.getFirstHeader(HttpHeaders.DATE);
- if (null == header) {
- Logger.warn(LOG_TAG, "Unexpected: missing Date header from " + this.hostname);
- return false;
- }
- return updateSkewFromDateHeader(header, now);
- }
-
- public long getSkewInMillis() {
- return skewMillis;
- }
-
- public long getSkewInSeconds() {
- return skewMillis / 1000;
- }
-
- public void resetSkew() {
- skewMillis = 0L;
- }
-} \ No newline at end of file
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountAbstractClient.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountAbstractClient.java
deleted file mode 100644
index 4bdaa6690..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountAbstractClient.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/* 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.background.fxa.oauth;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.util.Locale;
-import java.util.concurrent.Executor;
-
-import org.mozilla.gecko.background.fxa.FxAccountClientException;
-import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException.FxAccountAbstractClientMalformedResponseException;
-import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException.FxAccountAbstractClientRemoteException;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.Locales;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-import org.mozilla.gecko.sync.net.Resource;
-import org.mozilla.gecko.sync.net.SyncResponse;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-
-import ch.boye.httpclientandroidlib.HttpEntity;
-import ch.boye.httpclientandroidlib.HttpHeaders;
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-
-public abstract class FxAccountAbstractClient {
- protected static final String LOG_TAG = FxAccountAbstractClient.class.getSimpleName();
-
- protected static final String ACCEPT_HEADER = "application/json;charset=utf-8";
- protected static final String AUTHORIZATION_RESPONSE_TYPE = "token";
-
- public static final String JSON_KEY_ERROR = "error";
- public static final String JSON_KEY_MESSAGE = "message";
- public static final String JSON_KEY_CODE = "code";
- public static final String JSON_KEY_ERRNO = "errno";
-
- protected static final String[] requiredErrorStringFields = { JSON_KEY_ERROR, JSON_KEY_MESSAGE };
- protected static final String[] requiredErrorLongFields = { JSON_KEY_CODE, JSON_KEY_ERRNO };
-
- /**
- * The server's URI.
- * <p>
- * We assume throughout that this ends with a trailing slash (and guarantee as
- * much in the constructor).
- */
- protected final String serverURI;
-
- protected final Executor executor;
-
- public FxAccountAbstractClient(String serverURI, Executor executor) {
- if (serverURI == null) {
- throw new IllegalArgumentException("Must provide a server URI.");
- }
- if (executor == null) {
- throw new IllegalArgumentException("Must provide a non-null executor.");
- }
- this.serverURI = serverURI.endsWith("/") ? serverURI : serverURI + "/";
- if (!this.serverURI.endsWith("/")) {
- throw new IllegalArgumentException("Constructed serverURI must end with a trailing slash: " + this.serverURI);
- }
- this.executor = executor;
- }
-
- /**
- * Process a typed value extracted from a successful response (in an
- * endpoint-dependent way).
- */
- public interface RequestDelegate<T> {
- public void handleError(Exception e);
- public void handleFailure(FxAccountAbstractClientRemoteException e);
- public void handleSuccess(T result);
- }
-
- /**
- * Intepret a response from the auth server.
- * <p>
- * Throw an appropriate exception on errors; otherwise, return the response's
- * status code.
- *
- * @return response's HTTP status code.
- * @throws FxAccountClientException
- */
- public static int validateResponse(HttpResponse response) throws FxAccountAbstractClientRemoteException {
- final int status = response.getStatusLine().getStatusCode();
- if (status == 200) {
- return status;
- }
- int code;
- int errno;
- String error;
- String message;
- ExtendedJSONObject body;
- try {
- body = new SyncStorageResponse(response).jsonObjectBody();
- body.throwIfFieldsMissingOrMisTyped(requiredErrorStringFields, String.class);
- body.throwIfFieldsMissingOrMisTyped(requiredErrorLongFields, Long.class);
- code = body.getLong(JSON_KEY_CODE).intValue();
- errno = body.getLong(JSON_KEY_ERRNO).intValue();
- error = body.getString(JSON_KEY_ERROR);
- message = body.getString(JSON_KEY_MESSAGE);
- } catch (Exception e) {
- throw new FxAccountAbstractClientMalformedResponseException(response);
- }
- throw new FxAccountAbstractClientRemoteException(response, code, errno, error, message, body);
- }
-
- protected <T> void invokeHandleError(final RequestDelegate<T> delegate, final Exception e) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- delegate.handleError(e);
- }
- });
- }
-
- protected <T> void post(BaseResource resource, final ExtendedJSONObject requestBody, final RequestDelegate<T> delegate) {
- try {
- if (requestBody == null) {
- resource.post((HttpEntity) null);
- } else {
- resource.post(requestBody);
- }
- } catch (Exception e) {
- invokeHandleError(delegate, e);
- return;
- }
- }
-
- /**
- * Translate resource callbacks into request callbacks invoked on the provided
- * executor.
- * <p>
- * Override <code>handleSuccess</code> to parse the body of the resource
- * request and call the request callback. <code>handleSuccess</code> is
- * invoked via the executor, so you don't need to delegate further.
- */
- protected abstract class ResourceDelegate<T> extends BaseResourceDelegate {
- protected abstract void handleSuccess(final int status, HttpResponse response, final ExtendedJSONObject body);
-
- protected final RequestDelegate<T> delegate;
-
- /**
- * Create a delegate for an un-authenticated resource.
- */
- public ResourceDelegate(final Resource resource, final RequestDelegate<T> delegate) {
- super(resource);
- this.delegate = delegate;
- }
-
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return super.getAuthHeaderProvider();
- }
-
- @Override
- public String getUserAgent() {
- return FxAccountConstants.USER_AGENT;
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- try {
- final int status = validateResponse(response);
- invokeHandleSuccess(status, response);
- } catch (FxAccountAbstractClientRemoteException e) {
- invokeHandleFailure(e);
- }
- }
-
- protected void invokeHandleFailure(final FxAccountAbstractClientRemoteException e) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- delegate.handleFailure(e);
- }
- });
- }
-
- protected void invokeHandleSuccess(final int status, final HttpResponse response) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- try {
- ExtendedJSONObject body = new SyncResponse(response).jsonObjectBody();
- ResourceDelegate.this.handleSuccess(status, response, body);
- } catch (Exception e) {
- delegate.handleError(e);
- }
- }
- });
- }
-
- @Override
- public void handleHttpProtocolException(final ClientProtocolException e) {
- invokeHandleError(delegate, e);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- invokeHandleError(delegate, e);
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- invokeHandleError(delegate, e);
- }
-
- @Override
- public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
- super.addHeaders(request, client);
-
- // The basics.
- final Locale locale = Locale.getDefault();
- request.addHeader(HttpHeaders.ACCEPT_LANGUAGE, Locales.getLanguageTag(locale));
- request.addHeader(HttpHeaders.ACCEPT, ACCEPT_HEADER);
- }
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountAbstractClientException.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountAbstractClientException.java
deleted file mode 100644
index 21025af0a..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountAbstractClientException.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/* 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.background.fxa.oauth;
-
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.HTTPFailureException;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.HttpStatus;
-
-/**
- * From <a href="https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md">https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md</a>.
- */
-public class FxAccountAbstractClientException extends Exception {
- private static final long serialVersionUID = 1953459541558266597L;
-
- public FxAccountAbstractClientException(String detailMessage) {
- super(detailMessage);
- }
-
- public FxAccountAbstractClientException(Exception e) {
- super(e);
- }
-
- public static class FxAccountAbstractClientRemoteException extends FxAccountAbstractClientException {
- private static final long serialVersionUID = 1209313149952001097L;
-
- public final HttpResponse response;
- public final long httpStatusCode;
- public final long apiErrorNumber;
- public final String error;
- public final String message;
- public final ExtendedJSONObject body;
-
- public FxAccountAbstractClientRemoteException(HttpResponse response, long httpStatusCode, long apiErrorNumber, String error, String message, ExtendedJSONObject body) {
- super(new HTTPFailureException(new SyncStorageResponse(response)));
- if (body == null) {
- throw new IllegalArgumentException("body must not be null");
- }
- this.response = response;
- this.httpStatusCode = httpStatusCode;
- this.apiErrorNumber = apiErrorNumber;
- this.error = error;
- this.message = message;
- this.body = body;
- }
-
- @Override
- public String toString() {
- return "<FxAccountAbstractClientRemoteException " + this.httpStatusCode + " [" + this.apiErrorNumber + "]: " + this.message + ">";
- }
-
- public boolean isInvalidAuthentication() {
- return this.httpStatusCode == HttpStatus.SC_UNAUTHORIZED;
- }
- }
-
- public static class FxAccountAbstractClientMalformedResponseException extends FxAccountAbstractClientRemoteException {
- private static final long serialVersionUID = 1209313149952001098L;
-
- public FxAccountAbstractClientMalformedResponseException(HttpResponse response) {
- super(response, 0, FxAccountOAuthRemoteError.UNKNOWN_ERROR, "Response malformed", "Response malformed", new ExtendedJSONObject());
- }
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountOAuthClient10.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountOAuthClient10.java
deleted file mode 100644
index 4f233695b..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountOAuthClient10.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/* 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.background.fxa.oauth;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.concurrent.Executor;
-
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.net.BaseResource;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-
-/**
- * Talk to an fxa-oauth-server to get "implicitly granted" OAuth tokens.
- * <p>
- * To use this client, you will need a pre-allocated fxa-oauth-server
- * "client_id" with special "implicit grant" permissions.
- * <p>
- * This client was written against the API documented at <a href="https://github.com/mozilla/fxa-oauth-server/blob/41538990df9e91158558ae5a8115194383ac3b05/docs/api.md">https://github.com/mozilla/fxa-oauth-server/blob/41538990df9e91158558ae5a8115194383ac3b05/docs/api.md</a>.
- */
-public class FxAccountOAuthClient10 extends FxAccountAbstractClient {
- protected static final String LOG_TAG = FxAccountOAuthClient10.class.getSimpleName();
-
- protected static final String AUTHORIZATION_RESPONSE_TYPE = "token";
-
- protected static final String JSON_KEY_ACCESS_TOKEN = "access_token";
- protected static final String JSON_KEY_ASSERTION = "assertion";
- protected static final String JSON_KEY_CLIENT_ID = "client_id";
- protected static final String JSON_KEY_RESPONSE_TYPE = "response_type";
- protected static final String JSON_KEY_SCOPE = "scope";
- protected static final String JSON_KEY_STATE = "state";
- protected static final String JSON_KEY_TOKEN = "token";
- protected static final String JSON_KEY_TOKEN_TYPE = "token_type";
-
- // access_token: A string that can be used for authorized requests to service providers.
- // scope: A string of space-separated permissions that this token has. May differ from requested scopes, since user can deny permissions.
- // token_type: A string representing the token type. Currently will always be "bearer".
- protected static final String[] AUTHORIZATION_RESPONSE_REQUIRED_STRING_FIELDS = new String[] { JSON_KEY_ACCESS_TOKEN, JSON_KEY_SCOPE, JSON_KEY_TOKEN_TYPE };
-
- public FxAccountOAuthClient10(String serverURI, Executor executor) {
- super(serverURI, executor);
- }
-
- /**
- * Thin container for an authorization response.
- */
- public static class AuthorizationResponse {
- public final String access_token;
- public final String token_type;
- public final String scope;
-
- public AuthorizationResponse(String access_token, String token_type, String scope) {
- this.access_token = access_token;
- this.token_type = token_type;
- this.scope = scope;
- }
- }
-
- public void authorization(String client_id, String assertion, String state, String scope,
- RequestDelegate<AuthorizationResponse> delegate) {
- final BaseResource resource;
- try {
- resource = new BaseResource(new URI(serverURI + "authorization"));
- } catch (URISyntaxException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<AuthorizationResponse>(resource, delegate) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
- try {
- body.throwIfFieldsMissingOrMisTyped(AUTHORIZATION_RESPONSE_REQUIRED_STRING_FIELDS, String.class);
- String access_token = body.getString(JSON_KEY_ACCESS_TOKEN);
- String token_type = body.getString(JSON_KEY_TOKEN_TYPE);
- String scope = body.getString(JSON_KEY_SCOPE);
- delegate.handleSuccess(new AuthorizationResponse(access_token, token_type, scope));
- return;
- } catch (Exception e) {
- delegate.handleError(e);
- return;
- }
- }
- };
-
- final ExtendedJSONObject requestBody = new ExtendedJSONObject();
- requestBody.put(JSON_KEY_RESPONSE_TYPE, AUTHORIZATION_RESPONSE_TYPE);
- requestBody.put(JSON_KEY_CLIENT_ID, client_id);
- requestBody.put(JSON_KEY_ASSERTION, assertion);
- if (scope != null) {
- requestBody.put(JSON_KEY_SCOPE, scope);
- }
- if (state != null) {
- requestBody.put(JSON_KEY_STATE, state);
- }
-
- post(resource, requestBody, delegate);
- }
-
- public void deleteToken(final String token, final RequestDelegate<Void> delegate) {
- final BaseResource resource;
- try {
- resource = new BaseResource(new URI(serverURI + "destroy"));
- } catch (URISyntaxException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<Void>(resource, delegate) {
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
- try {
- delegate.handleSuccess(null);
- return;
- } catch (Exception e) {
- delegate.handleError(e);
- return;
- }
- }
- };
-
- final ExtendedJSONObject requestBody = new ExtendedJSONObject();
- requestBody.put(JSON_KEY_TOKEN, token);
- post(resource, requestBody, delegate);
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountOAuthRemoteError.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountOAuthRemoteError.java
deleted file mode 100644
index d949d316b..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/oauth/FxAccountOAuthRemoteError.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 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.background.fxa.oauth;
-
-public interface FxAccountOAuthRemoteError {
- public static final int ATTEMPT_TO_CREATE_AN_ACCOUNT_THAT_ALREADY_EXISTS = 101;
- public static final int UNKNOWN_CLIENT_ID = 101;
- public static final int INCORRECT_CLIENT_SECRET = 102;
- public static final int REDIRECT_URI_DOES_NOT_MATCH_REGISTERED_VALUE = 103;
- public static final int INVALID_FXA_ASSERTION = 104;
- public static final int UNKNOWN_CODE = 105;
- public static final int INCORRECT_CODE = 106;
- public static final int EXPIRED_CODE = 107;
- public static final int INVALID_TOKEN = 108;
- public static final int INVALID_REQUEST_PARAMETER = 109;
- public static final int UNKNOWN_ERROR = 999;
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/profile/FxAccountProfileClient10.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/profile/FxAccountProfileClient10.java
deleted file mode 100644
index cb851a8db..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/fxa/profile/FxAccountProfileClient10.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/* 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.background.fxa.profile;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.concurrent.Executor;
-
-import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClient;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BearerAuthHeaderProvider;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-
-
-/**
- * Talk to an fxa-profile-server to get profile information like name, age, gender, and avatar image.
- * <p>
- * This client was written against the API documented at <a href="https://github.com/mozilla/fxa-profile-server/blob/0c065619f5a2e867f813a343b4c67da3fe2c82a4/docs/API.md">https://github.com/mozilla/fxa-profile-server/blob/0c065619f5a2e867f813a343b4c67da3fe2c82a4/docs/API.md</a>.
- */
-public class FxAccountProfileClient10 extends FxAccountAbstractClient {
- public FxAccountProfileClient10(String serverURI, Executor executor) {
- super(serverURI, executor);
- }
-
- public void profile(final String token, RequestDelegate<ExtendedJSONObject> delegate) {
- BaseResource resource;
- try {
- resource = new BaseResource(new URI(serverURI + "profile"));
- } catch (URISyntaxException e) {
- invokeHandleError(delegate, e);
- return;
- }
-
- resource.delegate = new ResourceDelegate<ExtendedJSONObject>(resource, delegate) {
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return new BearerAuthHeaderProvider(token);
- }
-
- @Override
- public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
- try {
- delegate.handleSuccess(body);
- return;
- } catch (Exception e) {
- delegate.handleError(e);
- return;
- }
- }
- };
-
- resource.get();
- }
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/nativecode/NativeCrypto.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/nativecode/NativeCrypto.java
deleted file mode 100644
index 25f0f84d9..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/nativecode/NativeCrypto.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/* 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.background.nativecode;
-
-import java.security.GeneralSecurityException;
-
-import org.mozilla.gecko.annotation.RobocopTarget;
-import org.mozilla.gecko.AppConstants;
-
-import android.util.Log;
-
-@RobocopTarget
-public class NativeCrypto {
- static {
- try {
- System.loadLibrary("mozglue");
- } catch (UnsatisfiedLinkError e) {
- Log.wtf("NativeCrypto", "Couldn't load mozglue. Trying /data/app-lib path.");
- try {
- System.load("/data/app-lib/" + AppConstants.ANDROID_PACKAGE_NAME + "/libmozglue.so");
- } catch (Throwable ee) {
- try {
- Log.wtf("NativeCrypto", "Couldn't load mozglue: " + ee + ". Trying /data/data path.");
- System.load("/data/data/" + AppConstants.ANDROID_PACKAGE_NAME + "/lib/libmozglue.so");
- } catch (UnsatisfiedLinkError eee) {
- Log.wtf("NativeCrypto", "Failed every attempt to load mozglue. Giving up.");
- throw new RuntimeException("Unable to load mozglue", eee);
- }
- }
- }
- }
-
- /**
- * Wrapper to perform PBKDF2-HMAC-SHA-256 in native code.
- */
- public native static byte[] pbkdf2SHA256(byte[] password, byte[] salt, int c, int dkLen)
- throws GeneralSecurityException;
-
- /**
- * Wrapper to perform SHA-1 in native code.
- */
- public native static byte[] sha1(byte[] str);
-
- /**
- * Wrapper to perform SHA-256 init in native code. Returns a SHA-256 context.
- */
- public native static byte[] sha256init();
-
- /**
- * Wrapper to update a SHA-256 context in native code.
- */
- public native static void sha256update(byte[] ctx, byte[] str, int len);
-
- /**
- * Wrapper to finalize a SHA-256 context in native code. Returns digest.
- */
- public native static byte[] sha256finalize(byte[] ctx);
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/preferences/PreferenceFragment.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/preferences/PreferenceFragment.java
deleted file mode 100644
index 5bc5422c8..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/preferences/PreferenceFragment.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.mozilla.gecko.background.preferences;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.util.WeakReferenceHandler;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.preference.Preference;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceManager;
-import android.preference.PreferenceScreen;
-import android.support.v4.app.Fragment;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnKeyListener;
-import android.view.ViewGroup;
-import android.widget.ListView;
-
-public abstract class PreferenceFragment extends Fragment implements PreferenceManagerCompat.OnPreferenceTreeClickListener {
- private static final String PREFERENCES_TAG = "android:preferences";
-
- private PreferenceManager mPreferenceManager;
- private ListView mList;
- private boolean mHavePrefs;
- private boolean mInitDone;
-
- /**
- * The starting request code given out to preference framework.
- */
- private static final int FIRST_REQUEST_CODE = 100;
-
- private static final int MSG_BIND_PREFERENCES = 1;
-
- private static class PreferenceFragmentHandler extends WeakReferenceHandler<PreferenceFragment> {
- public PreferenceFragmentHandler(final PreferenceFragment that) {
- super(that);
- }
-
- @Override
- public void handleMessage(Message msg) {
- final PreferenceFragment that = mTarget.get();
- if (that == null) {
- return;
- }
-
- switch (msg.what) {
-
- case MSG_BIND_PREFERENCES:
- that.bindPreferences();
- break;
- }
- }
- }
-
- private final Handler mHandler = new PreferenceFragmentHandler(this);
-
- final private Runnable mRequestFocus = new Runnable() {
- @Override
- public void run() {
- mList.focusableViewAvailable(mList);
- }
- };
-
- /**
- * Interface that PreferenceFragment's containing activity should
- * implement to be able to process preference items that wish to
- * switch to a new fragment.
- */
- public interface OnPreferenceStartFragmentCallback {
- /**
- * Called when the user has clicked on a Preference that has
- * a fragment class name associated with it. The implementation
- * to should instantiate and switch to an instance of the given
- * fragment.
- */
- boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref);
- }
-
- @Override
- public void onCreate(Bundle paramBundle) {
- super.onCreate(paramBundle);
- mPreferenceManager = PreferenceManagerCompat.newInstance(getActivity(), FIRST_REQUEST_CODE);
- PreferenceManagerCompat.setFragment(mPreferenceManager, this);
- }
-
- @Override
- public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) {
- return paramLayoutInflater.inflate(R.layout.fxaccount_preference_list_fragment, paramViewGroup,
- false);
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- if (mHavePrefs) {
- bindPreferences();
- }
-
- mInitDone = true;
-
- if (savedInstanceState != null) {
- Bundle container = savedInstanceState.getBundle(PREFERENCES_TAG);
- if (container != null) {
- final PreferenceScreen preferenceScreen = getPreferenceScreen();
- if (preferenceScreen != null) {
- preferenceScreen.restoreHierarchyState(container);
- }
- }
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- PreferenceManagerCompat.setOnPreferenceTreeClickListener(mPreferenceManager, this);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- PreferenceManagerCompat.dispatchActivityStop(mPreferenceManager);
- PreferenceManagerCompat.setOnPreferenceTreeClickListener(mPreferenceManager, null);
- }
-
- @Override
- public void onDestroyView() {
- mList = null;
- mHandler.removeCallbacks(mRequestFocus);
- mHandler.removeMessages(MSG_BIND_PREFERENCES);
- super.onDestroyView();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- PreferenceManagerCompat.dispatchActivityDestroy(mPreferenceManager);
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
-
- final PreferenceScreen preferenceScreen = getPreferenceScreen();
- if (preferenceScreen != null) {
- Bundle container = new Bundle();
- preferenceScreen.saveHierarchyState(container);
- outState.putBundle(PREFERENCES_TAG, container);
- }
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- PreferenceManagerCompat.dispatchActivityResult(mPreferenceManager, requestCode, resultCode, data);
- }
-
- /**
- * Returns the {@link PreferenceManager} used by this fragment.
- * @return The {@link PreferenceManager}.
- */
- public PreferenceManager getPreferenceManager() {
- return mPreferenceManager;
- }
-
- /**
- * Sets the root of the preference hierarchy that this fragment is showing.
- *
- * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
- */
- public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
- if (PreferenceManagerCompat.setPreferences(mPreferenceManager, preferenceScreen) && preferenceScreen != null) {
- mHavePrefs = true;
- if (mInitDone) {
- postBindPreferences();
- }
- }
- }
-
- /**
- * Gets the root of the preference hierarchy that this fragment is showing.
- *
- * @return The {@link PreferenceScreen} that is the root of the preference
- * hierarchy.
- */
- public PreferenceScreen getPreferenceScreen() {
- return PreferenceManagerCompat.getPreferenceScreen(mPreferenceManager);
- }
-
- /**
- * Adds preferences from activities that match the given {@link Intent}.
- *
- * @param intent The {@link Intent} to query activities.
- */
- public void addPreferencesFromIntent(Intent intent) {
- requirePreferenceManager();
-
- setPreferenceScreen(PreferenceManagerCompat.inflateFromIntent(mPreferenceManager, intent, getPreferenceScreen()));
- }
-
- /**
- * Inflates the given XML resource and adds the preference hierarchy to the current
- * preference hierarchy.
- *
- * @param preferencesResId The XML resource ID to inflate.
- */
- public void addPreferencesFromResource(int preferencesResId) {
- requirePreferenceManager();
-
- setPreferenceScreen(PreferenceManagerCompat.inflateFromResource(mPreferenceManager, getActivity(),
- preferencesResId, getPreferenceScreen()));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
- Preference preference) {
- //if (preference.getFragment() != null &&
- if (
- getActivity() instanceof OnPreferenceStartFragmentCallback) {
- return ((OnPreferenceStartFragmentCallback)getActivity()).onPreferenceStartFragment(
- this, preference);
- }
- return false;
- }
-
- /**
- * Finds a {@link Preference} based on its key.
- *
- * @param key The key of the preference to retrieve.
- * @return The {@link Preference} with the key, or null.
- * @see PreferenceGroup#findPreference(CharSequence)
- */
- public Preference findPreference(CharSequence key) {
- if (mPreferenceManager == null) {
- return null;
- }
- return mPreferenceManager.findPreference(key);
- }
-
- private void requirePreferenceManager() {
- if (mPreferenceManager == null) {
- throw new RuntimeException("This should be called after super.onCreate.");
- }
- }
-
- private void postBindPreferences() {
- if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
- mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
- }
-
- private void bindPreferences() {
- final PreferenceScreen preferenceScreen = getPreferenceScreen();
- if (preferenceScreen != null) {
- preferenceScreen.bind(getListView());
- }
- }
-
- public ListView getListView() {
- ensureList();
- return mList;
- }
-
- private void ensureList() {
- if (mList != null) {
- return;
- }
- View root = getView();
- if (root == null) {
- throw new IllegalStateException("Content view not yet created");
- }
- View rawListView = root.findViewById(android.R.id.list);
- if (!(rawListView instanceof ListView)) {
- throw new RuntimeException(
- "Content has view with id attribute 'android.R.id.list' "
- + "that is not a ListView class");
- }
- mList = (ListView)rawListView;
- if (mList == null) {
- throw new RuntimeException(
- "Your content must have a ListView whose id attribute is " +
- "'android.R.id.list'");
- }
- mList.setOnKeyListener(mListOnKeyListener);
- mHandler.post(mRequestFocus);
- }
-
- private final OnKeyListener mListOnKeyListener = new OnKeyListener() {
-
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- Object selectedItem = mList.getSelectedItem();
- if (selectedItem instanceof Preference) {
- @SuppressWarnings("unused")
- View selectedView = mList.getSelectedView();
- //return ((Preference)selectedItem).onKey(
- // selectedView, keyCode, event);
- return false;
- }
- return false;
- }
-
- };
-}
diff --git a/mobile/android/services/src/main/java/org/mozilla/gecko/background/preferences/PreferenceManagerCompat.java b/mobile/android/services/src/main/java/org/mozilla/gecko/background/preferences/PreferenceManagerCompat.java
deleted file mode 100644
index 22c62e431..000000000
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/background/preferences/PreferenceManagerCompat.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.mozilla.gecko.background.preferences;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.preference.Preference;
-import android.preference.PreferenceManager;
-import android.preference.PreferenceScreen;
-import android.util.Log;
-
-public class PreferenceManagerCompat {
-
- private static final String TAG = PreferenceManagerCompat.class.getSimpleName();
-
- /**
- * Interface definition for a callback to be invoked when a {@link Preference} in the hierarchy
- * rooted at this {@link PreferenceScreen} is clicked.
- */
- interface OnPreferenceTreeClickListener {
- /**
- * Called when a preference in the tree rooted at this {@link PreferenceScreen} has been
- * clicked.
- *
- * @param preferenceScreen The {@link PreferenceScreen} that the preference is located in.
- * @param preference The preference that was clicked.
- *
- * @return Whether the click was handled.
- */
- boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference);
- }
-
- static PreferenceManager newInstance(Activity activity, int firstRequestCode) {
- try {
- Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class);
- c.setAccessible(true);
- return c.newInstance(activity, firstRequestCode);
- } catch (Exception e) {
- Log.w(TAG, "Couldn't call constructor PreferenceManager by reflection", e);
- }
- return null;
- }
-
- /**
- * Sets the owning preference fragment
- */
- static void setFragment(PreferenceManager manager, PreferenceFragment fragment) {
- // stub
- }
-
- /**
- * Sets the callback to be invoked when a {@link Preference} in the hierarchy rooted at this
- * {@link PreferenceManager} is clicked.
- *
- * @param listener The callback to be invoked.
- */
- static void setOnPreferenceTreeClickListener(PreferenceManager manager, final OnPreferenceTreeClickListener listener) {
- try {
- Field onPreferenceTreeClickListener = PreferenceManager.class.getDeclaredField("mOnPreferenceTreeClickListener");
- onPreferenceTreeClickListener.setAccessible(true);
- if (listener != null) {
- Object proxy = Proxy.newProxyInstance(
- onPreferenceTreeClickListener.getType().getClassLoader(),
- new Class<?>[] { onPreferenceTreeClickListener.getType() },
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) {
- if (method.getName().equals("onPreferenceTreeClick")) {
- return listener.onPreferenceTreeClick((PreferenceScreen) args[0], (Preference) args[1]);
- } else {
- return null;
- }
- }
- });
- onPreferenceTreeClickListener.set(manager, proxy);
- } else {
- onPreferenceTreeClickListener.set(manager, null);
- }
- } catch (Exception e) {
- Log.w(TAG, "Couldn't set PreferenceManager.mOnPreferenceTreeClickListener by reflection", e);
- }
- }
-
- /**
- * Inflates a preference hierarchy from the preference hierarchies of {@link Activity Activities}
- * that match the given {@link Intent}. An {@link Activity} defines its preference hierarchy with
- * meta-data using the {@link #METADATA_KEY_PREFERENCES} key.
- * <p/>
- * If a preference hierarchy is given, the new preference hierarchies will be merged in.
- *
- * @param queryIntent The intent to match activities.
- * @param rootPreferences Optional existing hierarchy to merge the new hierarchies into.
- *
- * @return The root hierarchy (if one was not provided, the new hierarchy's root).
- */
- static PreferenceScreen inflateFromIntent(PreferenceManager manager, Intent intent, PreferenceScreen screen) {
- try {
- Method m = PreferenceManager.class.getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class);
- m.setAccessible(true);
- PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(manager, intent, screen);
- return prefScreen;
- } catch (Exception e) {
- Log.w(TAG, "Couldn't call PreferenceManager.inflateFromIntent by reflection", e);
- }
- return null;
- }
-
- /**
- * Inflates a preference hierarchy from XML. If a preference hierarchy is given, the new
- * preference hierarchies will be merged in.
- *
- * @param context The context of the resource.
- * @param resId The resource ID of the XML to inflate.
- * @param rootPreferences Optional existing hierarchy to merge the new hierarchies into.
- *
- * @return The root hierarchy (if one was not provided, the new hierarchy's root).
- *
- * @hide
- */
- static PreferenceScreen inflateFromResource(PreferenceManager manager, Activity activity, int resId, PreferenceScreen screen) {
- try {
- Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
- m.setAccessible(true);
- PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(manager, activity, resId, screen);
- return prefScreen;
- } catch (Exception e) {
- Log.w(TAG, "Couldn't call PreferenceManager.inflateFromResource by reflection", e);
- }
- return null;
- }
-
- /**
- * Returns the root of the preference hierarchy managed by this class.
- *
- * @return The {@link PreferenceScreen} object that is at the root of the hierarchy.
- */
- static PreferenceScreen getPreferenceScreen(PreferenceManager manager) {
- try {
- Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen");
- m.setAccessible(true);
- return (PreferenceScreen) m.invoke(manager);
- } catch (Exception e) {
- Log.w(TAG, "Couldn't call PreferenceManager.getPreferenceScreen by reflection", e);
- }
- return null;
- }
-
- /**
- * Called by the {@link PreferenceManager} to dispatch a subactivity result.
- */
- static void dispatchActivityResult(PreferenceManager manager, int requestCode, int resultCode, Intent data) {
- try {
- Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class);
- m.setAccessible(true);
- m.invoke(manager, requestCode, resultCode, data);
- } catch (Exception e) {
- Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityResult by reflection", e);
- }
- }
-
- /**
- * Called by the {@link PreferenceManager} to dispatch the activity stop event.
- */
- static void dispatchActivityStop(PreferenceManager manager) {
- try {
- Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop");
- m.setAccessible(true);
- m.invoke(manager);
- } catch (Exception e) {
- Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityStop by reflection", e);
- }
- }
-
- /**
- * Called by the {@link PreferenceManager} to dispatch the activity destroy event.
- */
- static void dispatchActivityDestroy(PreferenceManager manager) {
- try {
- Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy");
- m.setAccessible(true);
- m.invoke(manager);
- } catch (Exception e) {
- Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityDestroy by reflection", e);
- }
- }
-
- /**
- * Sets the root of the preference hierarchy.
- *
- * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
- *
- * @return Whether the {@link PreferenceScreen} given is different than the previous.
- */
- static boolean setPreferences(PreferenceManager manager, PreferenceScreen screen) {
- try {
- Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class);
- m.setAccessible(true);
- return ((Boolean) m.invoke(manager, screen));
- } catch (Exception e) {
- Log.w(TAG, "Couldn't call PreferenceManager.setPreferences by reflection", e);
- }
- return false;
- }
-
-}