author | Nick Alexander <nalexander@mozilla.com> |
Tue, 17 Dec 2013 15:14:57 -0800 | |
changeset 161504 | 5663a2789f97da77b3f51774fc8d737e7257c0c5 |
parent 161503 | 136b89107d14d69df8a94fce6d95c1340ef0b987 |
child 161505 | 755f7983b4e27cd63717a4d50299762ab7242d73 |
push id | 25884 |
push user | ttaubert@mozilla.com |
push date | Sat, 21 Dec 2013 00:37:32 +0000 |
treeherder | mozilla-central@b3d4af4ec2df [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | rnewman |
bugs | 899217 |
milestone | 29.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/mobile/android/base/BrowserApp.java +++ b/mobile/android/base/BrowserApp.java @@ -171,16 +171,18 @@ abstract public class BrowserApp extends private boolean mDynamicToolbarCanScroll = false; private Integer mPrefObserverId; private SharedPreferencesHelper mSharedPreferencesHelper; private OrderedBroadcastHelper mOrderedBroadcastHelper; + private FirefoxAccountsHelper mFirefoxAccountsHelper; + private BrowserHealthReporter mBrowserHealthReporter; // The tab to be selected on editing mode exit. private Integer mTargetTabForEditingMode = null; // The animator used to toggle HomePager visibility has a race where if the HomePager is shown // (starting the animation), the HomePager is hidden, and the HomePager animation completes, // both the web content and the HomePager will be hidden. This flag is used to prevent the @@ -536,16 +538,17 @@ abstract public class BrowserApp extends registerEventListener("Settings:Show"); registerEventListener("Updater:Launch"); registerEventListener("Reader:GoToReadingList"); Distribution.init(this); JavaAddonManager.getInstance().init(getApplicationContext()); mSharedPreferencesHelper = new SharedPreferencesHelper(getApplicationContext()); mOrderedBroadcastHelper = new OrderedBroadcastHelper(getApplicationContext()); + mFirefoxAccountsHelper = new FirefoxAccountsHelper(getApplicationContext()); mBrowserHealthReporter = new BrowserHealthReporter(); if (AppConstants.MOZ_ANDROID_BEAM && Build.VERSION.SDK_INT >= 14) { NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this); if (nfc != null) { nfc.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() { @Override public NdefMessage createNdefMessage(NfcEvent event) { @@ -828,16 +831,21 @@ abstract public class BrowserApp extends mSharedPreferencesHelper = null; } if (mOrderedBroadcastHelper != null) { mOrderedBroadcastHelper.uninit(); mOrderedBroadcastHelper = null; } + if (mFirefoxAccountsHelper != null) { + mFirefoxAccountsHelper.uninit(); + mFirefoxAccountsHelper = null; + } + if (mBrowserHealthReporter != null) { mBrowserHealthReporter.uninit(); mBrowserHealthReporter = null; } unregisterEventListener("CharEncoding:Data"); unregisterEventListener("CharEncoding:State"); unregisterEventListener("Feedback:LastUrl");
new file mode 100644 --- /dev/null +++ b/mobile/android/base/FirefoxAccountsHelper.java @@ -0,0 +1,126 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import org.mozilla.gecko.util.EventDispatcher; +import org.mozilla.gecko.util.GeckoEventListener; + +import org.mozilla.gecko.fxa.authenticator.FxAccountAuthenticator; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.accounts.Account; +import android.content.Context; + +import android.util.Log; + +/** + * Helper class to manage Firefox Accounts. + * + * Listens for messages starting "FxAccount:" from Javascript, and creates a new + * Android account object in response to "FxAccount:{Verified,Login}". + * + * "FxAccount:Create" is ignored: it corresponds to a user creating a Firefox + * Account on the server; but they have not yet completed an email verification + * loop. The provided data will not include the users keys. + * + * "FxAccount:Verified" corresponds to a user signing up: creating a Firefox + * Account on the server, and then completing an email verification loop while + * still in the about:accounts window. + * + * "FxAccount:Login" corresponds to a user signing in to an existing verified + * Firefox Account. + */ +public final class FirefoxAccountsHelper + implements GeckoEventListener +{ + public static final String LOGTAG = "FxAcctsHelper"; + + // For extra debugging. Not final so it can be changed by an add-on. + public static boolean LOG_PERSONAL_INFORMATION = false; + + public static final String EVENT_CREATE = "FxAccount:Create"; + public static final String EVENT_LOGIN = "FxAccount:Login"; + public static final String EVENT_VERIFIED = "FxAccount:Verified"; + + protected final Context mContext; + + public FirefoxAccountsHelper(Context context) { + mContext = context; + + EventDispatcher dispatcher = GeckoAppShell.getEventDispatcher(); + if (dispatcher == null) { + Log.e(LOGTAG, "Gecko event dispatcher must not be null", new RuntimeException()); + return; + } + dispatcher.registerEventListener(EVENT_CREATE, this); + dispatcher.registerEventListener(EVENT_LOGIN, this); + dispatcher.registerEventListener(EVENT_VERIFIED, this); + } + + public synchronized void uninit() { + EventDispatcher dispatcher = GeckoAppShell.getEventDispatcher(); + if (dispatcher == null) { + Log.e(LOGTAG, "Gecko event dispatcher must not be null", new RuntimeException()); + return; + } + dispatcher.unregisterEventListener(EVENT_CREATE, this); + dispatcher.unregisterEventListener(EVENT_LOGIN, this); + dispatcher.unregisterEventListener(EVENT_VERIFIED, this); + } + + @Override + public void handleMessage(String event, JSONObject message) { + Log.i(LOGTAG, "FirefoxAccountsHelper got event " + event); + if (!(EVENT_CREATE.equals(event) || + EVENT_LOGIN.equals(event) || + EVENT_VERIFIED.equals(event))) { + Log.e(LOGTAG, "FirefoxAccountsHelper got unexpected event " + event); + return; + } + + if (EVENT_CREATE.equals(event)) { + Log.i(LOGTAG, "FirefoxAccountsHelper ignoring event " + event); + return; + } + + try { + final JSONObject data = message.getJSONObject("data"); + if (data == null) { + Log.e(LOGTAG, "data must not be null"); + return; + } + + if (LOG_PERSONAL_INFORMATION) { + Log.w(LOGTAG, "data: " + data.toString()); + } + + String email = data.optString("email"); + String uid = data.optString("uid"); + String sessionToken = data.optString("sessionToken"); + String kA = data.optString("kA"); + String kB = data.optString("kB"); + + if (LOG_PERSONAL_INFORMATION) { + Log.w(LOGTAG, "email: " + email); + Log.w(LOGTAG, "uid: " + uid); + Log.w(LOGTAG, "sessionToken: " + sessionToken); + Log.w(LOGTAG, "kA: " + kA); + Log.w(LOGTAG, "kB: " + kB); + } + + Account account = FxAccountAuthenticator.addAccount(mContext, email, uid, sessionToken, kA, kB); + if (account == null) { + Log.e(LOGTAG, "Got null adding FxAccount."); + return; + } + } catch (Exception e) { + Log.e(LOGTAG, "Got exception in handleMessage handling event " + event, e); + return; + } + } +}
--- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -126,16 +126,17 @@ gbjar.sources += [ 'favicons/cache/FaviconCacheElement.java', 'favicons/cache/FaviconsForURL.java', 'favicons/Favicons.java', 'favicons/LoadFaviconTask.java', 'favicons/OnFaviconLoadedListener.java', 'FilePickerResultHandler.java', 'FilePickerResultHandlerSync.java', 'FindInPageBar.java', + 'FirefoxAccountsHelper.java', 'FormAssistPopup.java', 'GeckoAccessibility.java', 'GeckoActivity.java', 'GeckoActivityStatus.java', 'GeckoApp.java', 'GeckoApplication.java', 'GeckoAppShell.java', 'GeckoBatteryManager.java',
--- a/mobile/android/chrome/content/aboutAccounts.js +++ b/mobile/android/chrome/content/aboutAccounts.js @@ -31,16 +31,20 @@ try { let level = Services.prefs.getPrefType(PREF_LOG_LEVEL) == Ci.nsIPrefBranch.PREF_STRING && Services.prefs.getCharPref(PREF_LOG_LEVEL); log.level = Log.Level[level] || Log.Level.Error; } catch (e) { log.error(e); } +function sendMessageToJava(message) { + return Services.androidBridge.handleGeckoMessage(JSON.stringify(message)); +} + let wrapper = { iframe: null, init: function () { log.info("about:accounts init"); let iframe = document.getElementById("remote"); this.iframe = iframe; iframe.addEventListener("load", this); @@ -58,26 +62,38 @@ let wrapper = { this.handleRemoteCommand(evt); break; } }, onLogin: function (data) { log.debug("Received: 'login'. Data:" + JSON.stringify(data)); this.injectData("message", { status: "login" }); + sendMessageToJava({ + type: "FxAccount:Login", + data: data, + }); }, onCreate: function (data) { log.debug("Received: 'create'. Data:" + JSON.stringify(data)); this.injectData("message", { status: "create" }); + sendMessageToJava({ + type: "FxAccount:Create", + data: data, + }); }, onVerified: function (data) { log.debug("Received: 'verified'. Data:" + JSON.stringify(data)); this.injectData("message", { status: "verified" }); + sendMessageToJava({ + type: "FxAccount:Verified", + data: data, + }); }, get accountsURI() { delete this.accountsURI; return this.accountsURI = Services.urlFormatter.formatURLPref("firefox.accounts.remoteUrl"); }, handleRemoteCommand: function (evt) {