From a40dd31543839b3e1c30a99e9ae9038de6529a2c Mon Sep 17 00:00:00 2001
From: Valere <valeref@matrix.org>
Date: Fri, 27 Mar 2020 15:17:21 +0100
Subject: [PATCH] Bootstrap bottomsheet

---
 .../im/vector/riotx/core/di/FragmentModule.kt |  14 +-
 .../vector/riotx/core/di/ScreenComponent.kt   |   2 +
 .../vector/riotx/core/di/VectorComponent.kt   |   3 +
 .../im/vector/riotx/features/MainActivity.kt  |   3 +-
 .../crypto/recover/BootstrapActions.kt        |  29 +++
 .../crypto/recover/BootstrapBottomSheet.kt    | 107 +++++++++++
 .../BootstrapConfirmPassphraseFragment.kt     | 120 +++++++++++++
 .../BootstrapEnterPassphraseFragment.kt       | 168 ++++++++++++++++++
 .../recover/BootstrapSharedViewModel.kt       | 138 ++++++++++++++
 .../crypto/recover/BootstrapViewEvents.kt     |  34 ++++
 .../verification/VerificationBottomSheet.kt   |   2 +-
 .../riotx/features/home/HomeActivity.kt       |  13 +-
 .../features/home/HomeActivitySharedAction.kt |   1 +
 .../riotx/features/login/LoginActivity.kt     |   5 +-
 .../riotx/features/login/LoginViewModel.kt    |   5 +-
 .../riotx/features/login/ReAuthHelper.kt      |  47 +++++
 .../res/layout/bottom_sheet_bootstrap.xml     | 115 ++++++++++++
 .../fragment_bootstrap_enter_passphrase.xml   |  93 ++++++++++
 vector/src/main/res/values/strings_riotX.xml  |   7 +
 19 files changed, 900 insertions(+), 6 deletions(-)
 create mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapActions.kt
 create mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapBottomSheet.kt
 create mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
 create mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
 create mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapSharedViewModel.kt
 create mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapViewEvents.kt
 create mode 100644 vector/src/main/java/im/vector/riotx/features/login/ReAuthHelper.kt
 create mode 100644 vector/src/main/res/layout/bottom_sheet_bootstrap.xml
 create mode 100644 vector/src/main/res/layout/fragment_bootstrap_enter_passphrase.xml

diff --git a/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt
index 4deaef32ab..8ec7352677 100644
--- a/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt
+++ b/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt
@@ -26,6 +26,8 @@ import im.vector.riotx.features.attachments.preview.AttachmentsPreviewFragment
 import im.vector.riotx.features.createdirect.CreateDirectRoomDirectoryUsersFragment
 import im.vector.riotx.features.createdirect.CreateDirectRoomKnownUsersFragment
 import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupSettingsFragment
+import im.vector.riotx.features.crypto.recover.BootstrapConfirmPassphraseFragment
+import im.vector.riotx.features.crypto.recover.BootstrapEnterPassphraseFragment
 import im.vector.riotx.features.crypto.verification.cancel.VerificationCancelFragment
 import im.vector.riotx.features.crypto.verification.cancel.VerificationNotMeFragment
 import im.vector.riotx.features.crypto.verification.choose.VerificationChooseMethodFragment
@@ -78,8 +80,8 @@ import im.vector.riotx.features.settings.devices.VectorSettingsDevicesFragment
 import im.vector.riotx.features.settings.devtools.AccountDataFragment
 import im.vector.riotx.features.settings.devtools.GossipingEventsPaperTrailFragment
 import im.vector.riotx.features.settings.devtools.IncomingKeyRequestListFragment
-import im.vector.riotx.features.settings.devtools.OutgoingKeyRequestListFragment
 import im.vector.riotx.features.settings.devtools.KeyRequestsFragment
+import im.vector.riotx.features.settings.devtools.OutgoingKeyRequestListFragment
 import im.vector.riotx.features.settings.ignored.VectorSettingsIgnoredUsersFragment
 import im.vector.riotx.features.settings.push.PushGatewaysFragment
 import im.vector.riotx.features.share.IncomingShareFragment
@@ -402,4 +404,14 @@ interface FragmentModule {
     @IntoMap
     @FragmentKey(GossipingEventsPaperTrailFragment::class)
     fun bindGossipingEventsPaperTrailFragment(fragment: GossipingEventsPaperTrailFragment): Fragment
+
+    @Binds
+    @IntoMap
+    @FragmentKey(BootstrapEnterPassphraseFragment::class)
+    fun bindBootstrapEnterPassphraseFragment(fragment: BootstrapEnterPassphraseFragment): Fragment
+
+    @Binds
+    @IntoMap
+    @FragmentKey(BootstrapConfirmPassphraseFragment::class)
+    fun bindBootstrapConfirmPassphraseFragment(fragment: BootstrapConfirmPassphraseFragment): Fragment
 }
diff --git a/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt
index 5cd54c6c2b..af49b00b59 100644
--- a/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt
+++ b/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt
@@ -27,6 +27,7 @@ import im.vector.riotx.features.MainActivity
 import im.vector.riotx.features.createdirect.CreateDirectRoomActivity
 import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupManageActivity
 import im.vector.riotx.features.crypto.quads.SharedSecureStorageActivity
+import im.vector.riotx.features.crypto.recover.BootstrapBottomSheet
 import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
 import im.vector.riotx.features.debug.DebugMenuActivity
 import im.vector.riotx.features.home.HomeActivity
@@ -128,6 +129,7 @@ interface ScreenComponent {
     fun inject(bottomSheet: VerificationBottomSheet)
     fun inject(bottomSheet: DeviceVerificationInfoBottomSheet)
     fun inject(bottomSheet: DeviceListBottomSheet)
+    fun inject(bottomSheet: BootstrapBottomSheet)
 
     /* ==========================================================================================
      * Others
diff --git a/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt b/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt
index 2652f58b04..6f864c7f5b 100644
--- a/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt
+++ b/vector/src/main/java/im/vector/riotx/core/di/VectorComponent.kt
@@ -39,6 +39,7 @@ import im.vector.riotx.features.home.AvatarRenderer
 import im.vector.riotx.features.home.HomeRoomListDataSource
 import im.vector.riotx.features.html.EventHtmlRenderer
 import im.vector.riotx.features.html.VectorHtmlCompressor
+import im.vector.riotx.features.login.ReAuthHelper
 import im.vector.riotx.features.navigation.Navigator
 import im.vector.riotx.features.notifications.NotifiableEventResolver
 import im.vector.riotx.features.notifications.NotificationBroadcastReceiver
@@ -131,6 +132,8 @@ interface VectorComponent {
 
     fun alertManager() : PopupAlertManager
 
+    fun reAuthHelper() : ReAuthHelper
+
     @Component.Factory
     interface Factory {
         fun create(@BindsInstance context: Context): VectorComponent
diff --git a/vector/src/main/java/im/vector/riotx/features/MainActivity.kt b/vector/src/main/java/im/vector/riotx/features/MainActivity.kt
index bc5a1aff95..c894e0739c 100644
--- a/vector/src/main/java/im/vector/riotx/features/MainActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/features/MainActivity.kt
@@ -195,7 +195,8 @@ class MainActivity : VectorBaseActivity() {
                 // We have a session.
                 // Check it can be opened
                 if (sessionHolder.getActiveSession().isOpenable) {
-                    HomeActivity.newIntent(this)
+                    // DO NOT COMMIT
+                    HomeActivity.newIntent(this, accountCreation = true)
                 } else {
                     // The token is still invalid
                     SoftLogoutActivity.newIntent(this)
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapActions.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapActions.kt
new file mode 100644
index 0000000000..177a72dff1
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapActions.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * 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 im.vector.riotx.features.crypto.recover
+
+import im.vector.riotx.core.platform.VectorViewModelAction
+
+sealed class BootstrapActions : VectorViewModelAction {
+
+    object GoBack : BootstrapActions()
+    data class GoToConfirmPassphrase(val passphrase: String) : BootstrapActions()
+    object TogglePasswordVisibility : BootstrapActions()
+    data class UpdateCandidatePassphrase(val pass: String) : BootstrapActions()
+    data class UpdateConfirmCandidatePassphrase(val pass: String) : BootstrapActions()
+
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapBottomSheet.kt
new file mode 100644
index 0000000000..27b6d79d7a
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapBottomSheet.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * 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 im.vector.riotx.features.crypto.recover
+
+import android.app.Dialog
+import android.os.Bundle
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import androidx.fragment.app.Fragment
+import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.withState
+import im.vector.riotx.R
+import im.vector.riotx.core.di.ScreenComponent
+import im.vector.riotx.core.extensions.commitTransaction
+import im.vector.riotx.core.platform.VectorBaseBottomSheetDialogFragment
+import kotlinx.android.synthetic.main.bottom_sheet_bootstrap.*
+import javax.inject.Inject
+import kotlin.reflect.KClass
+
+class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment() {
+
+    override val showExpanded = true
+
+    @Inject
+    lateinit var bootstrapViewModelFactory: BootstrapSharedViewModel.Factory
+
+    private val viewModel by fragmentViewModel(BootstrapSharedViewModel::class)
+
+    override fun injectWith(injector: ScreenComponent) {
+        injector.inject(this)
+    }
+
+    override fun getLayoutResId() = R.layout.bottom_sheet_bootstrap
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        viewModel.observeViewEvents {
+            when (it) {
+                is BootstrapViewEvents.Dismiss -> dismiss()
+            }
+        }
+    }
+
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+        val rootView = super.onCreateView(inflater, container, savedInstanceState)
+        dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
+        return rootView
+    }
+
+    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+        return super.onCreateDialog(savedInstanceState).apply {
+            setOnKeyListener { _, keyCode, keyEvent ->
+                if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.action == KeyEvent.ACTION_UP) {
+                    viewModel.handle(BootstrapActions.GoBack)
+                    true
+                } else {
+                    false
+                }
+            }
+        }
+    }
+
+    override fun invalidate() = withState(viewModel) { state ->
+
+        when (state.step) {
+            is BootstrapStep.SetupPassphrase   -> {
+                bootstrapTitleText.text = getString(R.string.recovery_passphrase)
+                showFragment(BootstrapEnterPassphraseFragment::class, Bundle())
+            }
+            is BootstrapStep.ConfirmPassphrase -> {
+                bootstrapTitleText.text = getString(R.string.passphrase_confirm_passphrase)
+                showFragment(BootstrapConfirmPassphraseFragment::class, Bundle())
+            }
+            is BootstrapStep.Initializing      -> TODO()
+        }
+        super.invalidate()
+    }
+
+    private fun showFragment(fragmentClass: KClass<out Fragment>, bundle: Bundle) {
+        if (childFragmentManager.findFragmentByTag(fragmentClass.simpleName) == null) {
+            childFragmentManager.commitTransaction {
+                replace(R.id.bottomSheetFragmentContainer,
+                        fragmentClass.java,
+                        bundle,
+                        fragmentClass.simpleName
+                )
+            }
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
new file mode 100644
index 0000000000..df793f56b1
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapConfirmPassphraseFragment.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * 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 im.vector.riotx.features.crypto.recover
+
+import android.os.Bundle
+import android.view.View
+import android.view.inputmethod.EditorInfo
+import androidx.core.text.toSpannable
+import androidx.core.view.isGone
+import com.airbnb.mvrx.parentFragmentViewModel
+import com.airbnb.mvrx.withState
+import com.jakewharton.rxbinding3.view.clicks
+import com.jakewharton.rxbinding3.widget.editorActionEvents
+import com.jakewharton.rxbinding3.widget.textChanges
+import im.vector.riotx.R
+import im.vector.riotx.core.extensions.showPassword
+import im.vector.riotx.core.platform.VectorBaseFragment
+import im.vector.riotx.core.resources.ColorProvider
+import im.vector.riotx.core.utils.colorizeMatchingText
+import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+
+class BootstrapConfirmPassphraseFragment @Inject constructor(
+        private val colorProvider: ColorProvider
+) : VectorBaseFragment() {
+
+    override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_passphrase
+
+    val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        ssss_passphrase_security_progress.isGone = true
+
+        val recPassPhrase = getString(R.string.recovery_passphrase)
+        bootstrapDescriptionText.text = getString(R.string.bootstrap_info_confirm_text, recPassPhrase)
+                .toSpannable()
+                .colorizeMatchingText(recPassPhrase, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
+
+        ssss_passphrase_enter_edittext.hint = getString(R.string.passphrase_confirm_passphrase)
+
+        ssss_passphrase_enter_edittext.editorActionEvents()
+                .debounce(300, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe {
+                    if (it.actionId == EditorInfo.IME_ACTION_DONE) {
+                        submit()
+                    }
+                }
+                .disposeOnDestroyView()
+
+        ssss_passphrase_enter_edittext.textChanges()
+                .subscribe {
+                    // ssss_passphrase_enter_til.error = null
+                    sharedViewModel.handle(BootstrapActions.UpdateConfirmCandidatePassphrase(it?.toString() ?: ""))
+//                    ssss_passphrase_submit.isEnabled = it.isNotBlank()
+                }
+                .disposeOnDestroyView()
+
+        sharedViewModel.observeViewEvents {
+            //            when (it) {
+//                is SharedSecureStorageViewEvent.InlineError -> {
+//                    ssss_passphrase_enter_til.error = it.message
+//                }
+//            }
+        }
+
+        ssss_view_show_password.clicks()
+                .debounce(300, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe {
+                    sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility)
+                }
+                .disposeOnDestroyView()
+    }
+
+    private fun submit() = withState(sharedViewModel) { state ->
+        if (state.step !is BootstrapStep.ConfirmPassphrase) {
+            return@withState
+        }
+
+//        val score = state.passphraseStrength.invoke()?.score
+//        val passphrase = ssss_passphrase_enter_edittext.text?.toString()
+//        if (passphrase.isNullOrBlank()) {
+//            ssss_passphrase_enter_til.error = getString(R.string.passphrase_empty_error_message)
+//        } else if (score != 4) {
+//            ssss_passphrase_enter_til.error = getString(R.string.passphrase_passphrase_too_weak)
+//        } else {
+//            sharedViewModel.handle(BootstrapActions.GoToConfirmPassphrase(passphrase))
+//        }
+    }
+
+    override fun invalidate() = withState(sharedViewModel) { state ->
+        super.invalidate()
+
+        if (state.step is BootstrapStep.ConfirmPassphrase) {
+            val isPasswordVisible = state.step.isPasswordVisible
+            ssss_passphrase_enter_edittext.showPassword(isPasswordVisible)
+            ssss_view_show_password.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)
+        }
+
+    }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
new file mode 100644
index 0000000000..2d2370d997
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapEnterPassphraseFragment.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * 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 im.vector.riotx.features.crypto.recover
+
+import android.os.Bundle
+import android.view.View
+import android.view.inputmethod.EditorInfo
+import androidx.core.text.toSpannable
+import com.airbnb.mvrx.parentFragmentViewModel
+import com.airbnb.mvrx.withState
+import com.jakewharton.rxbinding3.view.clicks
+import com.jakewharton.rxbinding3.widget.editorActionEvents
+import com.jakewharton.rxbinding3.widget.textChanges
+import im.vector.riotx.R
+import im.vector.riotx.core.extensions.showPassword
+import im.vector.riotx.core.platform.VectorBaseFragment
+import im.vector.riotx.core.resources.ColorProvider
+import im.vector.riotx.core.utils.colorizeMatchingText
+import im.vector.riotx.features.settings.VectorLocale
+import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.*
+import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.ssss_passphrase_enter_edittext
+import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.ssss_passphrase_enter_til
+import kotlinx.android.synthetic.main.fragment_bootstrap_enter_passphrase.ssss_view_show_password
+import kotlinx.android.synthetic.main.fragment_ssss_access_from_passphrase.*
+import timber.log.Timber
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+
+class BootstrapEnterPassphraseFragment @Inject constructor(
+        private val colorProvider: ColorProvider
+) : VectorBaseFragment() {
+
+    override fun getLayoutResId() = R.layout.fragment_bootstrap_enter_passphrase
+
+    val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel()
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+
+        val recPassPhrase = getString(R.string.recovery_passphrase)
+        bootstrapDescriptionText.text = getString(R.string.bootstrap_info_text, recPassPhrase)
+                .toSpannable()
+                .colorizeMatchingText(recPassPhrase, colorProvider.getColorFromAttribute(android.R.attr.textColorLink))
+
+        ssss_passphrase_enter_edittext.hint = getString(R.string.passphrase_enter_passphrase)
+        withState(sharedViewModel) {
+            // set initial value (usefull when coming back)
+            ssss_passphrase_enter_edittext.setText(it.passphrase ?: "")
+        }
+        ssss_passphrase_enter_edittext.editorActionEvents()
+                .debounce(300, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe {
+                    if (it.actionId == EditorInfo.IME_ACTION_DONE) {
+                        submit()
+                    }
+                }
+                .disposeOnDestroyView()
+
+        ssss_passphrase_enter_edittext.textChanges()
+                .subscribe {
+                    // ssss_passphrase_enter_til.error = null
+                    sharedViewModel.handle(BootstrapActions.UpdateCandidatePassphrase(it?.toString() ?: ""))
+//                    ssss_passphrase_submit.isEnabled = it.isNotBlank()
+                }
+                .disposeOnDestroyView()
+
+        sharedViewModel.observeViewEvents {
+            //            when (it) {
+//                is SharedSecureStorageViewEvent.InlineError -> {
+//                    ssss_passphrase_enter_til.error = it.message
+//                }
+//            }
+        }
+
+//        ssss_passphrase_submit.clicks()
+//                .debounce(300, TimeUnit.MILLISECONDS)
+//                .observeOn(AndroidSchedulers.mainThread())
+//                .subscribe {
+//                    submit()
+//                }
+//                .disposeOnDestroyView()
+
+//        ssss_passphrase_cancel.clicks()
+//                .debounce(300, TimeUnit.MILLISECONDS)
+//                .observeOn(AndroidSchedulers.mainThread())
+//                .subscribe {
+//                    sharedViewModel.handle(SharedSecureStorageAction.Cancel)
+//                }
+//                .disposeOnDestroyView()
+
+        ssss_view_show_password.clicks()
+                .debounce(300, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe {
+                    sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility)
+                }
+                .disposeOnDestroyView()
+    }
+
+    private fun submit() = withState(sharedViewModel) { state ->
+        if (state.step !is BootstrapStep.SetupPassphrase) {
+            return@withState
+        }
+
+        val score = state.passphraseStrength.invoke()?.score
+        val passphrase = ssss_passphrase_enter_edittext.text?.toString()
+        if (passphrase.isNullOrBlank()) {
+            ssss_passphrase_enter_til.error = getString(R.string.passphrase_empty_error_message)
+        } else if (score != 4) {
+            ssss_passphrase_enter_til.error = getString(R.string.passphrase_passphrase_too_weak)
+        } else {
+            sharedViewModel.handle(BootstrapActions.GoToConfirmPassphrase(passphrase))
+        }
+    }
+
+    override fun invalidate() = withState(sharedViewModel) { state ->
+        super.invalidate()
+
+        if (state.step is BootstrapStep.SetupPassphrase) {
+            val isPasswordVisible = state.step.isPasswordVisible
+            ssss_passphrase_enter_edittext.showPassword(isPasswordVisible)
+            ssss_view_show_password.setImageResource(if (isPasswordVisible) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)
+
+            state.passphraseStrength.invoke()?.let { strength ->
+                val score = strength.score
+                ssss_passphrase_security_progress.strength = score
+
+                Timber.e("## Strength info: $strength")
+                Timber.e("## Strength info score: $score")
+                Timber.e("## Strength info getWarning: ${strength.feedback?.getWarning(VectorLocale.applicationLocale)}")
+                Timber.e("## Strength info getSuggestions: ${strength.feedback?.getSuggestions(VectorLocale.applicationLocale)}")
+                Timber.e("## Strength info getFirstSuggestions: ${strength.feedback?.getSuggestions(VectorLocale.applicationLocale)?.firstOrNull()}")
+                if (score in 1..3) {
+                    val hint =
+                            strength.feedback?.getWarning(VectorLocale.applicationLocale)?.takeIf { it.isNotBlank() }
+                                    ?: strength.feedback?.getSuggestions(VectorLocale.applicationLocale)?.firstOrNull()
+                    Timber.e("## Strength info: $hint")
+                    Timber.e("## Strength currentValue : ${ssss_passphrase_enter_til.error}")
+                    if (hint != null && hint != ssss_passphrase_enter_til.error.toString()) {
+                        ssss_passphrase_enter_til.error = hint
+                    }
+                } else {
+                    ssss_passphrase_enter_til.error = null
+                }
+            }
+
+        }
+
+
+    }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapSharedViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapSharedViewModel.kt
new file mode 100644
index 0000000000..4b363242ab
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapSharedViewModel.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * 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 im.vector.riotx.features.crypto.recover
+
+import com.airbnb.mvrx.Async
+import com.airbnb.mvrx.FragmentViewModelContext
+import com.airbnb.mvrx.MvRxState
+import com.airbnb.mvrx.MvRxViewModelFactory
+import com.airbnb.mvrx.Success
+import com.airbnb.mvrx.Uninitialized
+import com.airbnb.mvrx.ViewModelContext
+import com.nulabinc.zxcvbn.Strength
+import com.nulabinc.zxcvbn.Zxcvbn
+import com.squareup.inject.assisted.Assisted
+import com.squareup.inject.assisted.AssistedInject
+import im.vector.matrix.android.api.session.Session
+import im.vector.riotx.core.extensions.exhaustive
+import im.vector.riotx.core.platform.VectorViewModel
+import im.vector.riotx.features.login.ReAuthHelper
+
+data class BootstrapViewState(
+        val step: BootstrapStep = BootstrapStep.SetupPassphrase(false),
+        val passphrase: String? = null,
+        val crossSigningInitialization: Async<Unit> = Uninitialized,
+        val passphraseStrength: Async<Strength> = Uninitialized
+) : MvRxState
+
+sealed class BootstrapStep {
+    data class SetupPassphrase(val isPasswordVisible: Boolean) : BootstrapStep()
+    data class ConfirmPassphrase(val isPasswordVisible: Boolean) : BootstrapStep()
+    object Initializing : BootstrapStep()
+}
+
+class BootstrapSharedViewModel @AssistedInject constructor(
+        @Assisted initialState: BootstrapViewState,
+        private val session: Session,
+        private val reAuthHelper: ReAuthHelper
+) : VectorViewModel<BootstrapViewState, BootstrapActions, BootstrapViewEvents>(initialState) {
+
+    private val zxcvbn = Zxcvbn()
+
+    @AssistedInject.Factory
+    interface Factory {
+        fun create(initialState: BootstrapViewState): BootstrapSharedViewModel
+    }
+
+    override fun handle(action: BootstrapActions) = withState { state ->
+        when (action) {
+            is BootstrapActions.GoBack                -> queryBack()
+            BootstrapActions.TogglePasswordVisibility -> {
+                when (state.step) {
+                    is BootstrapStep.SetupPassphrase   -> {
+                        setState {
+                            copy(step = state.step.copy(isPasswordVisible = !state.step.isPasswordVisible))
+                        }
+                    }
+                    is BootstrapStep.ConfirmPassphrase -> {
+                        setState {
+                            copy(step = state.step.copy(isPasswordVisible = !state.step.isPasswordVisible))
+                        }
+                    }
+                    else                               -> {
+                    }
+                }
+            }
+            is BootstrapActions.UpdateCandidatePassphrase -> {
+                val strength = zxcvbn.measure(action.pass)
+                setState {
+                    copy(
+                            passphrase = action.pass,
+                            passphraseStrength = Success(strength)
+                    )
+                }
+            }
+            is BootstrapActions.GoToConfirmPassphrase -> {
+                setState {
+                    copy(
+                            passphrase = action.passphrase,
+                            step = BootstrapStep.ConfirmPassphrase(
+                                    isPasswordVisible = (state.step as? BootstrapStep.SetupPassphrase)?.isPasswordVisible ?: false
+                            )
+                    )
+                }
+            }
+            is BootstrapActions.UpdateConfirmCandidatePassphrase -> {
+
+            }
+        }.exhaustive
+    }
+
+    // =======================================
+    // Fragment interaction
+    // =======================================
+
+    private fun queryBack() = withState { state ->
+        when (state.step) {
+            is BootstrapStep.SetupPassphrase -> {
+
+            }
+            is BootstrapStep.ConfirmPassphrase -> {
+                setState {
+                    copy(
+                            step = BootstrapStep.SetupPassphrase(
+                                    isPasswordVisible = (state.step as? BootstrapStep.ConfirmPassphrase)?.isPasswordVisible ?: false
+                            )
+                    )
+                }
+            }
+
+        }
+    }
+
+    // ======================================
+    // Companion, view model assisted creation
+    // ======================================
+
+    companion object : MvRxViewModelFactory<BootstrapSharedViewModel, BootstrapViewState> {
+
+        override fun create(viewModelContext: ViewModelContext, state: BootstrapViewState): BootstrapSharedViewModel? {
+            val fragment: BootstrapBottomSheet = (viewModelContext as FragmentViewModelContext).fragment()
+            return fragment.bootstrapViewModelFactory.create(state)
+        }
+    }
+}
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapViewEvents.kt
new file mode 100644
index 0000000000..56cb9456af
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapViewEvents.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * 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 im.vector.riotx.features.crypto.recover
+
+import im.vector.riotx.core.platform.VectorViewEvents
+
+sealed class BootstrapViewEvents : VectorViewEvents {
+    object Dismiss : BootstrapViewEvents()
+//    data class Failure(val throwable: Throwable) : DevicesViewEvents()
+//
+//    object RequestPassword : DevicesViewEvents()
+//
+//    data class PromptRenameDevice(val deviceInfo: DeviceInfo) : DevicesViewEvents()
+//
+//    data class ShowVerifyDevice(
+//            val userId: String,
+//            val transactionId: String?
+//    ) : DevicesViewEvents()
+}
+
diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt
index 5b7adbdb91..2c29357113 100644
--- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt
+++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheet.kt
@@ -130,7 +130,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
         }
     }
 
-    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+       override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
         return super.onCreateDialog(savedInstanceState).apply {
             setOnKeyListener { _, keyCode, keyEvent ->
                 if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.action == KeyEvent.ACTION_UP) {
diff --git a/vector/src/main/java/im/vector/riotx/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/riotx/features/home/HomeActivity.kt
index b814fd9410..9cdb40e0d9 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/HomeActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/HomeActivity.kt
@@ -40,7 +40,9 @@ import im.vector.riotx.core.extensions.replaceFragment
 import im.vector.riotx.core.platform.ToolbarConfigurable
 import im.vector.riotx.core.platform.VectorBaseActivity
 import im.vector.riotx.core.pushers.PushersManager
+import im.vector.riotx.features.crypto.recover.BootstrapBottomSheet
 import im.vector.riotx.features.disclaimer.showDisclaimerDialog
+import im.vector.riotx.features.login.LoginAction
 import im.vector.riotx.features.notifications.NotificationDrawerManager
 import im.vector.riotx.features.popup.PopupAlertManager
 import im.vector.riotx.features.popup.VerificationVectorAlert
@@ -95,6 +97,9 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
                             drawerLayout.closeDrawer(GravityCompat.START)
                             replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java)
                         }
+                        is HomeActivitySharedAction.PromptForSecurityBootstrap -> {
+                            BootstrapBottomSheet().apply { isCancelable = false }.show(supportFragmentManager, "BootstrapBottomSheet")
+                        }
                     }
                 }
                 .disposeOnDestroy()
@@ -103,6 +108,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
             notificationDrawerManager.clearAllEvents()
             intent.removeExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION)
         }
+        if (intent.getBooleanExtra(EXTRA_ACCOUNT_CREATION, false)) {
+            sharedActionViewModel.post(HomeActivitySharedAction.PromptForSecurityBootstrap)
+            intent.removeExtra(EXTRA_ACCOUNT_CREATION)
+        }
 
         activeSessionHolder.getSafeActiveSession()?.getInitialSyncProgressStatus()?.observe(this, Observer { status ->
             if (status == null) {
@@ -246,11 +255,13 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
 
     companion object {
         private const val EXTRA_CLEAR_EXISTING_NOTIFICATION = "EXTRA_CLEAR_EXISTING_NOTIFICATION"
+        private const val EXTRA_ACCOUNT_CREATION = "EXTRA_ACCOUNT_CREATION"
 
-        fun newIntent(context: Context, clearNotification: Boolean = false): Intent {
+        fun newIntent(context: Context, clearNotification: Boolean = false, accountCreation: Boolean = false): Intent {
             return Intent(context, HomeActivity::class.java)
                     .apply {
                         putExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION, clearNotification)
+                        putExtra(EXTRA_ACCOUNT_CREATION, accountCreation)
                     }
         }
     }
diff --git a/vector/src/main/java/im/vector/riotx/features/home/HomeActivitySharedAction.kt b/vector/src/main/java/im/vector/riotx/features/home/HomeActivitySharedAction.kt
index 493a14512d..902ea93588 100644
--- a/vector/src/main/java/im/vector/riotx/features/home/HomeActivitySharedAction.kt
+++ b/vector/src/main/java/im/vector/riotx/features/home/HomeActivitySharedAction.kt
@@ -24,4 +24,5 @@ import im.vector.riotx.core.platform.VectorSharedAction
 sealed class HomeActivitySharedAction : VectorSharedAction {
     object OpenDrawer : HomeActivitySharedAction()
     object OpenGroup : HomeActivitySharedAction()
+    object PromptForSecurityBootstrap : HomeActivitySharedAction()
 }
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
index 908a9c6370..9146e6a1eb 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt
@@ -217,7 +217,10 @@ open class LoginActivity : VectorBaseActivity(), ToolbarConfigurable {
 
     private fun updateWithState(loginViewState: LoginViewState) {
         if (loginViewState.isUserLogged()) {
-            val intent = HomeActivity.newIntent(this)
+            val intent = HomeActivity.newIntent(
+                    this,
+                    accountCreation = true //loginViewState.signMode == SignMode.SignUp
+            )
             startActivity(intent)
             finish()
             return
diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
index b38b1d3ee2..80b04fe062 100644
--- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
+++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt
@@ -38,6 +38,7 @@ import im.vector.matrix.android.api.auth.registration.Stage
 import im.vector.matrix.android.api.session.Session
 import im.vector.matrix.android.api.util.Cancelable
 import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
+import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
 import im.vector.riotx.core.di.ActiveSessionHolder
 import im.vector.riotx.core.extensions.configureAndStart
 import im.vector.riotx.core.platform.VectorViewModel
@@ -56,7 +57,8 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
                                                  private val activeSessionHolder: ActiveSessionHolder,
                                                  private val pushRuleTriggerListener: PushRuleTriggerListener,
                                                  private val homeServerConnectionConfigFactory: HomeServerConnectionConfigFactory,
-                                                 private val sessionListener: SessionListener)
+                                                 private val sessionListener: SessionListener,
+                                                 private val reAuthHelper: ReAuthHelper)
     : VectorViewModel<LoginViewState, LoginAction, LoginViewEvents>(initialState) {
 
     @AssistedInject.Factory
@@ -240,6 +242,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
 
     private fun handleRegisterWith(action: LoginAction.LoginOrRegister) {
         setState { copy(asyncRegistration = Loading()) }
+        reAuthHelper.rememberAuth(UserPasswordAuth(user = action.username, password = action.password))
         currentTask = registrationWizard?.createAccount(
                 action.username,
                 action.password,
diff --git a/vector/src/main/java/im/vector/riotx/features/login/ReAuthHelper.kt b/vector/src/main/java/im/vector/riotx/features/login/ReAuthHelper.kt
new file mode 100644
index 0000000000..a08ea051e2
--- /dev/null
+++ b/vector/src/main/java/im/vector/riotx/features/login/ReAuthHelper.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 New Vector Ltd
+ *
+ * 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 im.vector.riotx.features.login
+
+import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth
+import java.util.Timer
+import java.util.TimerTask
+import javax.inject.Inject
+import javax.inject.Singleton
+
+const val THREE_MINUTES = 3 * 60_000L
+
+@Singleton
+class ReAuthHelper @Inject constructor() {
+
+    private var timer: Timer? = null
+
+    private var rememberedInfo: UserPasswordAuth? = null
+
+    private var clearTask = object : TimerTask() {
+        override fun run() {
+            rememberedInfo = null
+        }
+    }
+
+    fun rememberAuth(password: UserPasswordAuth?) {
+        timer?.cancel()
+        rememberedInfo = password
+        timer = Timer().also {
+            it.schedule(clearTask, THREE_MINUTES)
+        }
+    }
+}
diff --git a/vector/src/main/res/layout/bottom_sheet_bootstrap.xml b/vector/src/main/res/layout/bottom_sheet_bootstrap.xml
new file mode 100644
index 0000000000..dd194bcb86
--- /dev/null
+++ b/vector/src/main/res/layout/bottom_sheet_bootstrap.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<androidx.core.widget.NestedScrollView 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"
+    android:id="@+id/bottomSheetScrollView"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:animateLayoutChanges="true"
+    android:fadeScrollbars="false"
+    android:scrollbars="vertical">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="16dp">
+
+        <ImageView
+            android:id="@+id/bootstrapIcon"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:adjustViewBounds="true"
+            android:contentDescription="@string/avatar"
+            android:scaleType="centerCrop"
+            android:src="@drawable/ic_shield_black"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+
+        <TextView
+            android:id="@+id/bootstrapTitleText"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="8dp"
+            android:layout_weight="1"
+            android:ellipsize="end"
+            android:maxLines="2"
+            android:textColor="?riotx_text_primary"
+            android:textSize="20sp"
+            android:textStyle="bold"
+            app:layout_constraintBottom_toBottomOf="@+id/bootstrapIcon"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toEndOf="@+id/bootstrapIcon"
+            app:layout_constraintTop_toTopOf="@+id/bootstrapIcon"
+            tools:text="@string/recovery_passphrase" />
+
+        <androidx.fragment.app.FragmentContainerView
+            android:id="@+id/bottomSheetFragmentContainer"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/bootstrapTitleText" />
+
+        <!--        <TextView-->
+        <!--            android:id="@+id/bootstrapDescriptionText"-->
+        <!--            android:layout_width="match_parent"-->
+        <!--            android:layout_height="wrap_content"-->
+        <!--            android:layout_marginTop="24dp"-->
+        <!--            android:text="@string/bootstrap_info_text"-->
+        <!--            android:textColor="?riotx_text_primary"-->
+        <!--            android:textSize="14sp"-->
+        <!--            app:layout_constraintTop_toBottomOf="@+id/bootstrapTitleText" />-->
+
+        <!--        <com.google.android.material.textfield.TextInputLayout-->
+        <!--            android:id="@+id/ssss_passphrase_enter_til"-->
+        <!--            style="@style/VectorTextInputLayout"-->
+        <!--            android:layout_width="0dp"-->
+        <!--            android:layout_height="wrap_content"-->
+        <!--            android:layout_marginTop="16dp"-->
+        <!--            app:errorEnabled="true"-->
+        <!--            app:layout_constraintEnd_toStartOf="@id/ssss_view_show_password"-->
+        <!--            app:layout_constraintStart_toStartOf="parent"-->
+        <!--            app:layout_constraintTop_toBottomOf="@id/bootstrapDescriptionText">-->
+
+        <!--            <com.google.android.material.textfield.TextInputEditText-->
+        <!--                android:id="@+id/ssss_passphrase_enter_edittext"-->
+        <!--                android:layout_width="match_parent"-->
+        <!--                android:layout_height="wrap_content"-->
+        <!--                android:hint="@string/passphrase_enter_passphrase"-->
+        <!--                android:imeOptions="actionDone"-->
+        <!--                android:maxLines="3"-->
+        <!--                android:singleLine="false"-->
+        <!--                android:textColor="?android:textColorPrimary"-->
+        <!--                tools:inputType="textPassword" />-->
+
+        <!--        </com.google.android.material.textfield.TextInputLayout>-->
+
+        <!--        <ImageView-->
+        <!--            android:id="@+id/ssss_view_show_password"-->
+        <!--            android:layout_width="@dimen/layout_touch_size"-->
+        <!--            android:layout_height="@dimen/layout_touch_size"-->
+        <!--            android:layout_marginTop="8dp"-->
+        <!--            android:background="?attr/selectableItemBackground"-->
+        <!--            android:scaleType="center"-->
+        <!--            android:src="@drawable/ic_eye_black"-->
+        <!--            android:tint="?colorAccent"-->
+        <!--            app:layout_constraintEnd_toEndOf="parent"-->
+        <!--            app:layout_constraintStart_toEndOf="@+id/ssss_passphrase_enter_til"-->
+        <!--            app:layout_constraintTop_toTopOf="@+id/ssss_passphrase_enter_til" />-->
+
+
+        <!--        <TextView-->
+        <!--            android:layout_width="match_parent"-->
+        <!--            android:layout_height="wrap_content"-->
+        <!--            android:layout_marginTop="8dp"-->
+        <!--            android:drawableStart="@drawable/e2e_warning"-->
+        <!--            android:drawablePadding="4dp"-->
+        <!--            android:text="@string/bootstrap_dont_reuse_pwd"-->
+        <!--            app:layout_constraintBottom_toBottomOf="parent"-->
+        <!--            app:layout_constraintTop_toBottomOf="@id/ssss_passphrase_enter_til" />-->
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</androidx.core.widget.NestedScrollView>
diff --git a/vector/src/main/res/layout/fragment_bootstrap_enter_passphrase.xml b/vector/src/main/res/layout/fragment_bootstrap_enter_passphrase.xml
new file mode 100644
index 0000000000..804325cbe0
--- /dev/null
+++ b/vector/src/main/res/layout/fragment_bootstrap_enter_passphrase.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<androidx.constraintlayout.widget.ConstraintLayout 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"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    tools:padding="16dp">
+
+    <TextView
+        android:id="@+id/bootstrapDescriptionText"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:text="@string/bootstrap_info_text"
+        android:textColor="?riotx_text_primary"
+        android:textSize="14sp"
+        app:layout_constraintBottom_toTopOf="@id/ssss_passphrase_enter_til"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <com.google.android.material.textfield.TextInputLayout
+        android:id="@+id/ssss_passphrase_enter_til"
+        style="@style/VectorTextInputLayout"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        app:errorEnabled="true"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/ssss_view_show_password"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/bootstrapDescriptionText">
+
+        <com.google.android.material.textfield.TextInputEditText
+            android:id="@+id/ssss_passphrase_enter_edittext"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            tools:hint="@string/passphrase_enter_passphrase"
+            android:imeOptions="actionDone"
+            android:maxLines="3"
+            android:singleLine="false"
+            android:textColor="?android:textColorPrimary"
+            tools:inputType="textPassword" />
+
+        <!-- This is inside the TIL, if not the keyboard will hide it when in bottomsheet -->
+
+        <im.vector.riotx.core.ui.views.PasswordStrengthBar
+            android:id="@+id/ssss_passphrase_security_progress"
+            android:layout_width="match_parent"
+            android:layout_marginBottom="2dp"
+            android:layout_marginTop="2dp"
+            android:layout_height="4dp" />
+
+        <TextView
+            android:id="@+id/bootstrapWarningInfo"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:layout_marginBottom="8dp"
+            android:textSize="12sp"
+            android:gravity="center_vertical"
+            android:drawableStart="@drawable/ic_alert_triangle"
+            android:drawableTint="@color/riotx_destructive_accent"
+            android:drawablePadding="4dp"
+            android:text="@string/bootstrap_dont_reuse_pwd" />
+
+    </com.google.android.material.textfield.TextInputLayout>
+
+    <ImageView
+        android:id="@+id/ssss_view_show_password"
+        android:layout_width="@dimen/layout_touch_size"
+        android:layout_height="@dimen/layout_touch_size"
+        android:layout_marginTop="8dp"
+        android:background="?attr/selectableItemBackground"
+        android:scaleType="center"
+        android:src="@drawable/ic_eye_black"
+        android:tint="?colorAccent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/ssss_passphrase_enter_til"
+        app:layout_constraintTop_toTopOf="@+id/ssss_passphrase_enter_til" />
+
+
+    <!--    <TextView-->
+    <!--        android:id="@+id/bootstrapWarningInfo"-->
+    <!--        android:layout_width="match_parent"-->
+    <!--        android:layout_height="wrap_content"-->
+    <!--        android:layout_marginTop="8dp"-->
+    <!--        android:drawableStart="@drawable/e2e_warning"-->
+    <!--        android:drawablePadding="4dp"-->
+    <!--        android:text="@string/bootstrap_dont_reuse_pwd"-->
+    <!--        app:layout_constraintBottom_toBottomOf="parent"-->
+    <!--        app:layout_constraintTop_toBottomOf="@id/ssss_passphrase_enter_til" />-->
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml
index ccb4bfa9be..b9fd1fa018 100644
--- a/vector/src/main/res/values/strings_riotX.xml
+++ b/vector/src/main/res/values/strings_riotX.xml
@@ -32,6 +32,13 @@
     <string name="verify_cancelled_notice">Verify your devices from Settings.</string>
     <string name="verification_cancelled">Verification Cancelled</string>
 
+    <string name="recovery_passphrase">Recovery Passphrase</string>
+
+    <!-- %s will be replaced by recovery_passphrase -->
+    <string name="bootstrap_info_text">Secure &amp; unlock information with a %s so only you can access encrypted messages and secure information.</string>
+    <!-- %s will be replaced by recovery_passphrase -->
+    <string name="bootstrap_info_confirm_text">Enter your %s again to confirm it.</string>
+    <string name="bootstrap_dont_reuse_pwd">Don’t re-use your account password.</string>
     <!-- END Strings added by Valere -->