Skip to content

Commit e608129

Browse files
MozLandoGrisha Kruglov
and
Grisha Kruglov
committed
4413: Closes mozilla-mobile#4412: Ability to configure FxaWebChannelFeature with capabilities r=Amejia481 a=grigoryk First capability we have is "choose what to sync". If configured, supported engines will be presented during a sign-up auth flow. Co-authored-by: Grisha Kruglov <[email protected]>
2 parents beae2a5 + a4f4dfc commit e608129

File tree

3 files changed

+92
-13
lines changed

3 files changed

+92
-13
lines changed

components/feature/accounts/src/main/java/mozilla/components/feature/accounts/FxaWebChannelFeature.kt

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ import org.json.JSONObject
2828
import java.lang.ClassCastException
2929
import java.util.WeakHashMap
3030

31+
/**
32+
* Configurable FxA capabilities.
33+
*/
34+
enum class FxaCapability {
35+
// Enables "choose what to sync" selection during support auth flows (currently, sign-up).
36+
CHOOSE_WHAT_TO_SYNC
37+
}
38+
3139
/**
3240
* Feature implementation that provides Firefox Accounts WebChannel support.
3341
* For more information https://github.com/mozilla/fxa/blob/master/packages/fxa-content-server/docs/relier-communication-protocols/fx-webchannel.md
@@ -40,14 +48,16 @@ import java.util.WeakHashMap
4048
* @property engine a reference to application's browser engine.
4149
* @property sessionManager a reference to application's [SessionManager].
4250
* @property accountManager a reference to application's [FxaAccountManager].
51+
* @property fxaCapabilities a set of [FxaCapability] that client supports.
4352
*/
4453
@Suppress("TooManyFunctions")
4554
class FxaWebChannelFeature(
4655
private val context: Context,
4756
private val customTabSessionId: String?,
4857
private val engine: Engine,
4958
private val sessionManager: SessionManager,
50-
private val accountManager: FxaAccountManager
59+
private val accountManager: FxaAccountManager,
60+
private val fxaCapabilities: Set<FxaCapability> = emptySet()
5161
) : SelectionAwareSessionObserver(sessionManager), LifecycleAwareFeature {
5262

5363
override fun start() {
@@ -90,7 +100,8 @@ class FxaWebChannelFeature(
90100
*/
91101
private class WebChannelViewContentMessageHandler(
92102
private val engineSession: EngineSession,
93-
private val accountManager: FxaAccountManager
103+
private val accountManager: FxaAccountManager,
104+
private val fxaCapabilities: Set<FxaCapability>
94105
) : MessageHandler {
95106
override fun onPortConnected(port: Port) {
96107
ports[port.engineSession] = port
@@ -139,7 +150,7 @@ class FxaWebChannelFeature(
139150
messageId, engineSession
140151
)
141152
WebChannelCommand.FXA_STATUS -> processFxaStatusCommand(
142-
accountManager, messageId, engineSession
153+
accountManager, messageId, engineSession, fxaCapabilities
143154
)
144155
WebChannelCommand.OAUTH_LOGIN -> processOauthLoginCommand(
145156
accountManager, payload
@@ -150,7 +161,9 @@ class FxaWebChannelFeature(
150161

151162
private fun registerContentMessageHandler(session: Session) {
152163
val engineSession = sessionManager.getOrCreateEngineSession(session)
153-
val messageHandler = WebChannelViewContentMessageHandler(engineSession, accountManager)
164+
val messageHandler = WebChannelViewContentMessageHandler(
165+
engineSession, accountManager, fxaCapabilities
166+
)
154167
registerMessageHandler(engineSession, messageHandler)
155168
}
156169

@@ -259,7 +272,8 @@ class FxaWebChannelFeature(
259272
private fun processFxaStatusCommand(
260273
accountManager: FxaAccountManager,
261274
messageId: String,
262-
engineSession: EngineSession
275+
engineSession: EngineSession,
276+
fxaCapabilities: Set<FxaCapability>
263277
) {
264278
val status = JSONObject().also { status ->
265279
status.put("id", CHANNEL_ID)
@@ -273,6 +287,10 @@ class FxaWebChannelFeature(
273287
engines.put(engine.nativeName)
274288
} ?: emptyArray<SyncEngine>()
275289
})
290+
291+
if (fxaCapabilities.contains(FxaCapability.CHOOSE_WHAT_TO_SYNC)) {
292+
capabilities.put("choose_what_to_sync", true)
293+
}
276294
})
277295
// Since accountManager currently can't provide us with a sessionToken, this is
278296
// hard-coded to null.

components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FxaWebChannelFeatureTest.kt

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import mozilla.components.support.test.eq
2323
import mozilla.components.support.test.mock
2424
import mozilla.components.support.test.robolectric.testContext
2525
import mozilla.components.support.test.whenever
26+
import org.json.JSONException
2627
import org.json.JSONObject
2728
import org.junit.Assert.assertEquals
2829
import org.junit.Assert.assertFalse
@@ -155,6 +156,47 @@ class FxaWebChannelFeatureTest {
155156
assertTrue(FxaWebChannelFeature.ports.containsValue(port))
156157
}
157158

159+
@Test
160+
fun `COMMAND_STATUS configured with CWTS must provided a boolean=true flag to the web-channel`() {
161+
val sessionManager = mock<SessionManager>()
162+
val accountManager = mock<FxaAccountManager>()
163+
val session = mock<Session>()
164+
val engineSession = mock<EngineSession>()
165+
val ext = mock<WebExtension>()
166+
val messageHandler = argumentCaptor<MessageHandler>()
167+
val responseToTheWebChannel = argumentCaptor<JSONObject>()
168+
val port = mock<Port>()
169+
val expectedEngines = setOf(SyncEngine.HISTORY)
170+
171+
FxaWebChannelFeature.installedWebExt = ext
172+
173+
whenever(accountManager.supportedSyncEngines()).thenReturn(expectedEngines)
174+
whenever(sessionManager.getOrCreateEngineSession(session)).thenReturn(engineSession)
175+
whenever(port.engineSession).thenReturn(engineSession)
176+
177+
val webchannelFeature =
178+
spy(FxaWebChannelFeature(testContext, null, mock(), sessionManager, accountManager, setOf(FxaCapability.CHOOSE_WHAT_TO_SYNC)))
179+
webchannelFeature.onSessionAdded(session)
180+
verify(ext).registerContentMessageHandler(
181+
eq(engineSession),
182+
eq(FxaWebChannelFeature.WEB_CHANNEL_EXTENSION_ID),
183+
messageHandler.capture()
184+
)
185+
messageHandler.value.onPortConnected(port)
186+
187+
val requestFromTheWebChannel = JSONObject(
188+
"""{
189+
"message":{
190+
"command": "fxaccounts:fxa_status",
191+
"messageId":123
192+
}
193+
}""".trimIndent()
194+
)
195+
messageHandler.value.onPortMessage(requestFromTheWebChannel, mock())
196+
verify(port).postMessage(responseToTheWebChannel.capture())
197+
assertTrue(responseToTheWebChannel.value.getCWTSSupport()!!)
198+
}
199+
158200
// Receiving and responding a fxa-status message if sync is configured with one engine
159201
@Test
160202
fun `COMMAND_STATUS configured with one engine must be provided to the web-channel`() {
@@ -197,8 +239,9 @@ class FxaWebChannelFeatureTest {
197239
messageHandler.value.onPortMessage(requestFromTheWebChannel, mock())
198240
verify(port).postMessage(responseToTheWebChannel.capture())
199241

200-
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getCapabilities()
242+
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getSupportedEngines()
201243
assertTrue(capabilitiesFromWebChannel.size == 1)
244+
assertNull(responseToTheWebChannel.value.getCWTSSupport())
202245

203246
assertTrue(responseToTheWebChannel.value.isSignedInUserNull())
204247
}
@@ -245,11 +288,12 @@ class FxaWebChannelFeatureTest {
245288
messageHandler.value.onPortMessage(requestFromTheWebChannel, mock())
246289
verify(port).postMessage(responseToTheWebChannel.capture())
247290

248-
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getCapabilities()
291+
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getSupportedEngines()
249292
assertTrue(expectedEngines.all {
250293
capabilitiesFromWebChannel.contains(it.nativeName)
251294
})
252295

296+
assertNull(responseToTheWebChannel.value.getCWTSSupport())
253297
assertTrue(responseToTheWebChannel.value.isSignedInUserNull())
254298
}
255299

@@ -298,11 +342,12 @@ class FxaWebChannelFeatureTest {
298342
messageHandler.value.onPortMessage(requestFromTheWebChannel, mock())
299343
verify(port).postMessage(responseToTheWebChannel.capture())
300344

301-
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getCapabilities()
345+
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getSupportedEngines()
302346
assertTrue(expectedEngines.all {
303347
capabilitiesFromWebChannel.contains(it.nativeName)
304348
})
305349

350+
assertNull(responseToTheWebChannel.value.getCWTSSupport())
306351
assertTrue(responseToTheWebChannel.value.isSignedInUserNull())
307352
}
308353

@@ -349,11 +394,12 @@ class FxaWebChannelFeatureTest {
349394
messageHandler.value.onPortMessage(requestFromTheWebChannel, mock())
350395
verify(port).postMessage(responseToTheWebChannel.capture())
351396

352-
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getCapabilities()
397+
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getSupportedEngines()
353398
assertTrue(expectedEngines.all {
354399
capabilitiesFromWebChannel.contains(it.nativeName)
355400
})
356401

402+
assertNull(responseToTheWebChannel.value.getCWTSSupport())
357403
assertTrue(responseToTheWebChannel.value.isSignedInUserNull())
358404
}
359405

@@ -400,11 +446,12 @@ class FxaWebChannelFeatureTest {
400446
messageHandler.value.onPortMessage(requestFromTheWebChannel, mock())
401447
verify(port).postMessage(responseToTheWebChannel.capture())
402448

403-
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getCapabilities()
449+
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getSupportedEngines()
404450
assertTrue(expectedEngines.all {
405451
capabilitiesFromWebChannel.contains(it.nativeName)
406452
})
407453

454+
assertNull(responseToTheWebChannel.value.getCWTSSupport())
408455
assertTrue(responseToTheWebChannel.value.isSignedInUserNull())
409456
}
410457

@@ -448,8 +495,8 @@ class FxaWebChannelFeatureTest {
448495
messageHandler.value.onPortMessage(requestFromTheWebChannel, mock())
449496
verify(port).postMessage(responseToTheWebChannel.capture())
450497

451-
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getCapabilities()
452-
498+
assertNull(responseToTheWebChannel.value.getCWTSSupport())
499+
val capabilitiesFromWebChannel = responseToTheWebChannel.value.getSupportedEngines()
453500
assertTrue(capabilitiesFromWebChannel.isEmpty())
454501
}
455502

@@ -589,7 +636,7 @@ class FxaWebChannelFeatureTest {
589636
return webchannelFeature
590637
}
591638

592-
private fun JSONObject.getCapabilities(): List<String> {
639+
private fun JSONObject.getSupportedEngines(): List<String> {
593640
val engines = this.getJSONObject("message")
594641
.getJSONObject("data")
595642
.getJSONObject("capabilities")
@@ -602,6 +649,17 @@ class FxaWebChannelFeatureTest {
602649
return list
603650
}
604651

652+
private fun JSONObject.getCWTSSupport(): Boolean? {
653+
return try {
654+
this.getJSONObject("message")
655+
.getJSONObject("data")
656+
.getJSONObject("capabilities")
657+
.getBoolean("choose_what_to_sync")
658+
} catch (e: JSONException) {
659+
null
660+
}
661+
}
662+
605663
private fun JSONObject.isSignedInUserNull(): Boolean {
606664
return this.getJSONObject("message")
607665
.getJSONObject("data")

docs/changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ permalink: /changelog/
3030
* **feature-tabs**
3131
* ⚠️ **This is a breaking change**: Methods that have been accepting a parent `Session` parameter now expect the parent id (`String`).
3232

33+
* **feature-accounts**
34+
* Added ability to configure FxaWebChannelFeature with a set of `FxaCapability`. Currently there's just one: `CHOOSE_WHAT_TO_SYNC`. It defaults to `false`, so if you want "choose what to sync" selection during auth flows, please specify it.
35+
3336
# 12.0.0
3437

3538
* [Commits](https://github.com/mozilla-mobile/android-components/compare/v11.0.0...v12.0.0)

0 commit comments

Comments
 (0)