Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
Closes #2593: FxA automatic sign-in integration
Browse files Browse the repository at this point in the history
  • Loading branch information
Grisha Kruglov authored and grigoryk committed Aug 2, 2019
1 parent 2108641 commit ae33234
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 125 deletions.
39 changes: 28 additions & 11 deletions app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package org.mozilla.fenix.home

import android.animation.Animator
import android.content.Context
import android.content.DialogInterface
import android.content.res.Resources
import android.graphics.drawable.BitmapDrawable
Expand Down Expand Up @@ -158,7 +159,7 @@ class HomeFragment : Fragment(), AccountObserver {
): View? {
val view = inflater.inflate(R.layout.fragment_home, container, false)

val mode = currentMode()
val mode = currentMode(view.context)

sessionControlComponent = SessionControlComponent(
view.homeLayout,
Expand Down Expand Up @@ -300,7 +301,7 @@ class HomeFragment : Fragment(), AccountObserver {
getManagedEmitter<SessionControlChange>().onNext(
SessionControlChange.Change(
tabs = getListOfSessions().toTabs(),
mode = currentMode(),
mode = currentMode(context!!),
collections = requireComponents.core.tabCollectionStorage.cachedTabCollections
)
)
Expand All @@ -325,7 +326,7 @@ class HomeFragment : Fragment(), AccountObserver {
is OnboardingAction.Finish -> {
onboarding.finish()

val mode = currentMode()
val mode = currentMode(context!!)
getManagedEmitter<SessionControlChange>().onNext(SessionControlChange.ModeChange(mode))
}
}
Expand Down Expand Up @@ -705,12 +706,18 @@ class HomeFragment : Fragment(), AccountObserver {
nav(R.id.homeFragment, directions)
}

private fun currentMode(): Mode = if (!onboarding.userHasBeenOnboarded()) {
val account = requireComponents.backgroundServices.accountManager.authenticatedAccount()
if (account == null) {
Mode.Onboarding(OnboardingState.SignedOut)
private fun currentMode(context: Context): Mode = if (!onboarding.userHasBeenOnboarded()) {
val accountManager = requireComponents.backgroundServices.accountManager
val account = accountManager.authenticatedAccount()
if (account != null) {
Mode.Onboarding(OnboardingState.SignedIn)
} else {
Mode.Onboarding(OnboardingState.ManuallySignedIn)
val availableAccounts = accountManager.shareableAccounts(context)
if (availableAccounts.isEmpty()) {
Mode.Onboarding(OnboardingState.SignedOutNoAutoSignIn)
} else {
Mode.Onboarding(OnboardingState.SignedOutCanAutoSignIn(availableAccounts[0]))
}
}
} else if ((activity as HomeActivity).browsingModeManager.isPrivate) {
Mode.Private
Expand All @@ -719,12 +726,22 @@ class HomeFragment : Fragment(), AccountObserver {
}

private fun emitAccountChanges() {
val mode = currentMode()
getManagedEmitter<SessionControlChange>().onNext(SessionControlChange.ModeChange(mode))
context?.let {
val mode = currentMode(it)
getManagedEmitter<SessionControlChange>().onNext(SessionControlChange.ModeChange(mode))
}
}

override fun onAuthenticated(account: OAuthAccount) {
view?.let {
FenixSnackbar.make(it, Snackbar.LENGTH_SHORT).setText(
it.context.getString(R.string.onboarding_firefox_account_sync_is_on)
).show()
}
emitAccountChanges()
}

override fun onAuthenticationProblems() = emitAccountChanges()
override fun onAuthenticated(account: OAuthAccount) = emitAccountChanges()
override fun onLoggedOut() = emitAccountChanges()
override fun onProfileUpdated(profile: Profile) = emitAccountChanges()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.SaveTabGroupViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingAutomaticSignInViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFirefoxAccountViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingManualSignInViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingPrivacyNoticeViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingPrivateBrowsingViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingSectionHeaderViewHolder
Expand Down Expand Up @@ -67,9 +68,12 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {
) : AdapterItem(OnboardingSectionHeaderViewHolder.LAYOUT_ID) {
override fun sameAs(other: AdapterItem) = other is OnboardingSectionHeader && labelBuilder == other.labelBuilder
}
data class OnboardingFirefoxAccount(
data class OnboardingManualSignIn(
val state: OnboardingState
) : AdapterItem(OnboardingFirefoxAccountViewHolder.LAYOUT_ID)
) : AdapterItem(OnboardingManualSignInViewHolder.LAYOUT_ID)
data class OnboardingAutomaticSignIn(
val state: OnboardingState
) : AdapterItem(OnboardingAutomaticSignInViewHolder.LAYOUT_ID)
object OnboardingThemePicker : AdapterItem(OnboardingThemePickerViewHolder.LAYOUT_ID)
object OnboardingTrackingProtection : AdapterItem(OnboardingTrackingProtectionViewHolder.LAYOUT_ID)
object OnboardingPrivateBrowsing : AdapterItem(OnboardingPrivateBrowsingViewHolder.LAYOUT_ID)
Expand Down Expand Up @@ -108,7 +112,8 @@ class SessionControlAdapter(
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, actionEmitter)
OnboardingHeaderViewHolder.LAYOUT_ID -> OnboardingHeaderViewHolder(view)
OnboardingSectionHeaderViewHolder.LAYOUT_ID -> OnboardingSectionHeaderViewHolder(view)
OnboardingFirefoxAccountViewHolder.LAYOUT_ID -> OnboardingFirefoxAccountViewHolder(view)
OnboardingAutomaticSignInViewHolder.LAYOUT_ID -> OnboardingAutomaticSignInViewHolder(view)
OnboardingManualSignInViewHolder.LAYOUT_ID -> OnboardingManualSignInViewHolder(view)
OnboardingThemePickerViewHolder.LAYOUT_ID -> OnboardingThemePickerViewHolder(view)
OnboardingTrackingProtectionViewHolder.LAYOUT_ID -> OnboardingTrackingProtectionViewHolder(view)
OnboardingPrivateBrowsingViewHolder.LAYOUT_ID -> OnboardingPrivateBrowsingViewHolder(view)
Expand Down Expand Up @@ -145,8 +150,13 @@ class SessionControlAdapter(
is OnboardingSectionHeaderViewHolder -> holder.bind(
(item as AdapterItem.OnboardingSectionHeader).labelBuilder
)
is OnboardingFirefoxAccountViewHolder -> holder.bind(
(item as AdapterItem.OnboardingFirefoxAccount).state == OnboardingState.AutoSignedIn
is OnboardingManualSignInViewHolder -> holder.bind()
is OnboardingAutomaticSignInViewHolder -> holder.bind(
(
(
item as AdapterItem.OnboardingAutomaticSignIn
).state as OnboardingState.SignedOutCanAutoSignIn
).withAccount
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observer
import kotlinx.android.parcel.Parcelize
import mozilla.components.browser.session.Session
import mozilla.components.service.fxa.sharing.ShareableAccount
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.mvi.ViewState
import org.mozilla.fenix.mvi.Change
Expand Down Expand Up @@ -69,13 +70,13 @@ fun List<Tab>.toSessionBundle(context: Context): MutableList<Session> {
/**
* Describes various onboarding states.
*/
enum class OnboardingState {
// Signed out, no account carried over from Fennec.
SignedOut,
// Auto-signed in, via a Fennec account.
AutoSignedIn,
// Manually signed in while in onboarding.
ManuallySignedIn
sealed class OnboardingState {
// Signed out, without an option to auto-login using a shared FxA account.
object SignedOutNoAutoSignIn : OnboardingState()
// Signed out, with an option to auto-login into a shared FxA account.
data class SignedOutCanAutoSignIn(val withAccount: ShareableAccount) : OnboardingState()
// Signed in.
object SignedIn : OnboardingState()
}

sealed class Mode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,17 @@ private fun onboardingAdapterItems(onboardingState: OnboardingState): List<Adapt

// Customize FxA items based on where we are with the account state:
items.addAll(when (onboardingState) {
OnboardingState.SignedOut -> {
OnboardingState.SignedOutNoAutoSignIn -> {
listOf(
AdapterItem.OnboardingFirefoxAccount(onboardingState)
AdapterItem.OnboardingManualSignIn(onboardingState)
)
}
OnboardingState.AutoSignedIn -> {
is OnboardingState.SignedOutCanAutoSignIn -> {
listOf(
AdapterItem.OnboardingFirefoxAccount(onboardingState)
AdapterItem.OnboardingAutomaticSignIn(onboardingState)
)
}
else -> listOf()
OnboardingState.SignedIn -> listOf()
})

items.addAll(listOf(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* 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.fenix.home.sessioncontrol.viewholders.onboarding

import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.onboarding_automatic_signin.view.turn_on_sync_button
import kotlinx.android.synthetic.main.onboarding_automatic_signin.view.header_text
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.service.fxa.sharing.ShareableAccount
import org.mozilla.fenix.R
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.ext.components

class OnboardingAutomaticSignInViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
private lateinit var shareableAccount: ShareableAccount

init {
view.turn_on_sync_button.setOnClickListener {
it.turn_on_sync_button.text = it.context.getString(
R.string.onboarding_firefox_account_signing_in
)
it.turn_on_sync_button.isEnabled = false

CoroutineScope(Dispatchers.Main).launch {
val result = view.context.components.backgroundServices.accountManager
.signInWithShareableAccountAsync(shareableAccount).await()
if (result) {
// Success.
} else {
// Failed to sign-in (either network problem, or bad credentials). Allow to try again.
it.turn_on_sync_button.text = it.context.getString(
R.string.onboarding_firefox_account_auto_signin_confirm
)
it.turn_on_sync_button.isEnabled = true
FenixSnackbar.make(it, Snackbar.LENGTH_SHORT).setText(
it.context.getString(R.string.onboarding_firefox_account_automatic_signin_failed)
).show()
}
}
}
}

fun bind(account: ShareableAccount) {
shareableAccount = account
view.header_text.text = view.context.getString(
R.string.onboarding_firefox_account_auto_signin_header_2, account.email
)
}

companion object {
const val LAYOUT_ID = R.layout.onboarding_automatic_signin
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* 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.fenix.home.sessioncontrol.viewholders.onboarding

import android.view.View
import androidx.navigation.Navigation
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.onboarding_manual_signin.view.*
import org.mozilla.fenix.R
import org.mozilla.fenix.home.HomeFragmentDirections

class OnboardingManualSignInViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
init {
view.turn_on_sync_button.setOnClickListener {
val directions = HomeFragmentDirections.actionHomeFragmentToTurnOnSyncFragment()
Navigation.findNavController(view).navigate(directions)
}
}

fun bind() {
val appName = view.context.getString(R.string.app_name)
view.header_text.text = view.context.getString(R.string.onboarding_firefox_account_header, appName)
}

companion object {
const val LAYOUT_ID = R.layout.onboarding_manual_signin
}
}
43 changes: 43 additions & 0 deletions app/src/main/res/layout/onboarding_automatic_signin.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/OnboardingCardDark"
android:id="@+id/onboarding_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/header_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="14dp"
tools:text="@string/onboarding_firefox_account_auto_signin_header_2"
android:drawableStart="@drawable/ic_onboarding_avatar_anonymous"
android:drawablePadding="12dp"
android:textAppearance="@style/Header16TextStyle"
android:textColor="@color/onboarding_card_primary_text_dark" />

<Button
android:id="@+id/turn_on_sync_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@drawable/button_background"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:padding="10dp"
android:text="@string/onboarding_firefox_account_auto_signin_confirm"
android:textAllCaps="false"
android:textColor="?neutral"
android:textSize="14sp"
android:textStyle="bold"
app:backgroundTint="@color/onboarding_card_button_background_dark" />

</LinearLayout>
Loading

0 comments on commit ae33234

Please sign in to comment.