diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
index 79021902c4..f58f0b87ae 100644
--- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
+++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt
@@ -587,6 +587,16 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
         }
     }
 
+    fun showSnackbar(message: String, @StringRes withActionTitle: Int?, action: (() -> Unit)?) {
+        coordinatorLayout?.let {
+            Snackbar.make(it, message, Snackbar.LENGTH_LONG).apply {
+                withActionTitle?.let {
+                    setAction(withActionTitle, { action?.invoke() })
+                }
+            }.show()
+        }
+    }
+
     /* ==========================================================================================
      * User Consent
      * ========================================================================================== */
diff --git a/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt b/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt
index 44fc6afa4e..f3ac8d9c47 100644
--- a/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt
@@ -19,8 +19,11 @@ package im.vector.app.core.utils
 import android.Manifest
 import android.app.Activity
 import android.content.Context
+import android.content.Intent
 import android.content.pm.PackageManager
+import android.net.Uri
 import android.os.Build
+import android.provider.Settings
 import android.widget.Toast
 import androidx.activity.result.ActivityResultLauncher
 import androidx.activity.result.contract.ActivityResultContracts
@@ -30,6 +33,8 @@ import androidx.core.app.ActivityCompat
 import androidx.core.content.ContextCompat
 import androidx.fragment.app.Fragment
 import im.vector.app.R
+import im.vector.app.core.platform.VectorBaseActivity
+import org.matrix.android.sdk.api.extensions.tryOrNull
 import timber.log.Timber
 
 // Android M permission request code management
@@ -284,6 +289,19 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
     return isPermissionGranted
 }
 
+fun VectorBaseActivity.onPermissionDeniedSnackbar(@StringRes rationaleMessage: Int) {
+    showSnackbar(getString(rationaleMessage), R.string.settings) {
+        tryOrNull {
+            startActivity(
+                    Intent().apply {
+                        action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
+                        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                        data = Uri.fromParts("package", this@onPermissionDeniedSnackbar.packageName, null)
+                    })
+        }
+    }
+}
+
 /**
  * Helper method used in [.checkPermissions] to populate the list of the
  * permissions to be granted (permissionsListToBeGrantedOut) and the list of the permissions already denied (permissionAlreadyDeniedListOut).
diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
index 95351afec8..b4c278116b 100644
--- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt
@@ -22,7 +22,6 @@ import android.content.Context
 import android.content.Intent
 import android.os.Bundle
 import android.view.View
-import android.widget.Toast
 import androidx.appcompat.app.AlertDialog
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.Fail
@@ -43,6 +42,7 @@ import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
 import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_READ_CONTACTS
 import im.vector.app.core.utils.allGranted
 import im.vector.app.core.utils.checkPermissions
+import im.vector.app.core.utils.onPermissionDeniedSnackbar
 import im.vector.app.features.contactsbook.ContactsBookFragment
 import im.vector.app.features.contactsbook.ContactsBookViewModel
 import im.vector.app.features.userdirectory.UserListFragment
@@ -132,9 +132,10 @@ class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fac
                 addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java)
             }
         } else {
-            Toast.makeText(baseContext, R.string.missing_permissions_error, Toast.LENGTH_SHORT).show()
             if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) {
-                finish()
+                onPermissionDeniedSnackbar(R.string.permissions_denied_qr_code)
+            } else if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) {
+                onPermissionDeniedSnackbar(R.string.permissions_denied_add_contact)
             }
         }
     }
diff --git a/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt b/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt
index 60354db9c6..782d7e1c04 100644
--- a/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/usercode/ScanUserCodeFragment.kt
@@ -16,10 +16,13 @@
 
 package im.vector.app.features.usercode
 
+import android.Manifest
 import android.app.Activity
+import android.content.pm.PackageManager
 import android.os.Bundle
 import android.view.View
 import android.widget.Toast
+import androidx.core.content.ContextCompat
 import com.airbnb.mvrx.activityViewModel
 import com.google.zxing.Result
 import com.google.zxing.ResultMetadataType
@@ -60,6 +63,9 @@ class ScanUserCodeFragment @Inject constructor()
     private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted ->
         if (allGranted) {
             startCamera()
+        } else {
+            // For now just go back
+            sharedViewModel.handle(UserCodeActions.SwitchMode(UserCodeState.Mode.SHOW))
         }
     }
 
@@ -90,12 +96,18 @@ class ScanUserCodeFragment @Inject constructor()
         }
     }
 
+    override fun onStart() {
+        super.onStart()
+        if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
+            startCamera()
+        }
+    }
+
     override fun onResume() {
         super.onResume()
         // Register ourselves as a handler for scan results.
         userCodeScannerView.setResultHandler(this)
-        // Start camera on resume
-        if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
+        if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)) {
             startCamera()
         }
     }
diff --git a/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt b/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt
index e812ca31bb..532557af84 100644
--- a/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/usercode/ShowUserCodeFragment.kt
@@ -23,6 +23,10 @@ import com.airbnb.mvrx.withState
 import im.vector.app.R
 import im.vector.app.core.extensions.setTextOrHide
 import im.vector.app.core.platform.VectorBaseFragment
+import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
+import im.vector.app.core.utils.checkPermissions
+import im.vector.app.core.utils.registerForPermissionsResult
+import im.vector.app.core.utils.startSharePlainTextIntent
 import im.vector.app.features.home.AvatarRenderer
 import kotlinx.android.synthetic.main.fragment_user_code_show.*
 import javax.inject.Inject
@@ -35,13 +39,38 @@ class ShowUserCodeFragment @Inject constructor(
 
     val sharedViewModel: UserCodeSharedViewModel by activityViewModel()
 
+    private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted ->
+        if (allGranted) {
+            doOpenQRCodeScanner()
+        } else {
+            sharedViewModel.handle(UserCodeActions.CameraPermissionNotGranted)
+        }
+    }
+
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         showUserCodeClose.debouncedClicks {
             sharedViewModel.handle(UserCodeActions.DismissAction)
         }
         showUserCodeScanButton.debouncedClicks {
-            doOpenQRCodeScanner()
+            if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
+                doOpenQRCodeScanner()
+            }
+        }
+        shareByText.debouncedClicks {
+            sharedViewModel.handle(UserCodeActions.ShareByText)
+        }
+
+        sharedViewModel.observeViewEvents {
+            if (it is UserCodeShareViewEvents.SharePlainText) {
+                startSharePlainTextIntent(
+                        fragment = this,
+                        activityResultLauncher = null,
+                        chooserTitle = it.title,
+                        text = it.text,
+                        extraTitle = it.richPlainText
+                )
+            }
         }
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt
index 0611e0f8c3..3411fe3d7f 100644
--- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt
+++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActions.kt
@@ -24,4 +24,6 @@ sealed class UserCodeActions : VectorViewModelAction {
     data class SwitchMode(val mode: UserCodeState.Mode) : UserCodeActions()
     data class DecodedQRCode(val code: String) : UserCodeActions()
     data class StartChattingWithUser(val matrixItem: MatrixItem) : UserCodeActions()
+    object CameraPermissionNotGranted : UserCodeActions()
+    object ShareByText : UserCodeActions()
 }
diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt
index 0e7efa5b92..149caaba8f 100644
--- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt
@@ -32,6 +32,7 @@ import im.vector.app.core.di.ScreenComponent
 import im.vector.app.core.extensions.commitTransaction
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.platform.VectorBaseActivity
+import im.vector.app.core.utils.onPermissionDeniedSnackbar
 import im.vector.app.features.matrixto.MatrixToBottomSheet
 import kotlinx.android.parcel.Parcelize
 import kotlinx.android.synthetic.main.activity_simple.*
@@ -78,13 +79,15 @@ class UserCodeActivity
 
         sharedViewModel.observeViewEvents {
             when (it) {
-                is UserCodeShareViewEvents.InviteFriend   -> TODO()
-                UserCodeShareViewEvents.Dismiss           -> ActivityCompat.finishAfterTransition(this)
-                UserCodeShareViewEvents.ShowWaitingScreen -> simpleActivityWaitingView.isVisible = true
-                UserCodeShareViewEvents.HideWaitingScreen -> simpleActivityWaitingView.isVisible = false
-                is UserCodeShareViewEvents.ToastMessage   -> Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
-                is UserCodeShareViewEvents.NavigateToRoom -> navigator.openRoom(this, it.roomId)
-            }.exhaustive
+                UserCodeShareViewEvents.Dismiss                    -> ActivityCompat.finishAfterTransition(this)
+                UserCodeShareViewEvents.ShowWaitingScreen          -> simpleActivityWaitingView.isVisible = true
+                UserCodeShareViewEvents.HideWaitingScreen          -> simpleActivityWaitingView.isVisible = false
+                is UserCodeShareViewEvents.ToastMessage            -> Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
+                is UserCodeShareViewEvents.NavigateToRoom          -> navigator.openRoom(this, it.roomId)
+                UserCodeShareViewEvents.CameraPermissionNotGranted -> onPermissionDeniedSnackbar(R.string.permissions_denied_qr_code)
+                else                                               -> {
+                }
+            }
         }
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt
index 26fcffadd2..67a1ab8a6c 100644
--- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt
+++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeShareViewEvents.kt
@@ -19,10 +19,11 @@ package im.vector.app.features.usercode
 import im.vector.app.core.platform.VectorViewEvents
 
 sealed class UserCodeShareViewEvents : VectorViewEvents {
-    data class InviteFriend(val permalink: String) : UserCodeShareViewEvents()
     object Dismiss : UserCodeShareViewEvents()
     object ShowWaitingScreen : UserCodeShareViewEvents()
     object HideWaitingScreen : UserCodeShareViewEvents()
     data class ToastMessage(val message: String) : UserCodeShareViewEvents()
     data class NavigateToRoom(val roomId: String) : UserCodeShareViewEvents()
+    object CameraPermissionNotGranted : UserCodeShareViewEvents()
+    data class SharePlainText(val text: String, val title: String, val richPlainText: String) : UserCodeShareViewEvents()
 }
diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt
index 1d1283c269..b456f24972 100644
--- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeSharedViewModel.kt
@@ -71,12 +71,6 @@ class UserCodeSharedViewModel @AssistedInject constructor(
         }
     }
 
-    private fun handleInviteFriend() {
-        session.permalinkService().createPermalink(initialState.userId)?.let { permalink ->
-            _viewEvents.post(UserCodeShareViewEvents.InviteFriend(permalink))
-        }
-    }
-
     @AssistedInject.Factory
     interface Factory {
         fun create(initialState: UserCodeState, args: UserCodeActivity.Args): UserCodeSharedViewModel
@@ -84,10 +78,23 @@ class UserCodeSharedViewModel @AssistedInject constructor(
 
     override fun handle(action: UserCodeActions) {
         when (action) {
-            UserCodeActions.DismissAction            -> _viewEvents.post(UserCodeShareViewEvents.Dismiss)
-            is UserCodeActions.SwitchMode            -> setState { copy(mode = action.mode) }
-            is UserCodeActions.DecodedQRCode         -> handleQrCodeDecoded(action)
-            is UserCodeActions.StartChattingWithUser -> handleStartChatting(action)
+            UserCodeActions.DismissAction              -> _viewEvents.post(UserCodeShareViewEvents.Dismiss)
+            is UserCodeActions.SwitchMode              -> setState { copy(mode = action.mode) }
+            is UserCodeActions.DecodedQRCode           -> handleQrCodeDecoded(action)
+            is UserCodeActions.StartChattingWithUser   -> handleStartChatting(action)
+            UserCodeActions.CameraPermissionNotGranted -> _viewEvents.post(UserCodeShareViewEvents.CameraPermissionNotGranted)
+            UserCodeActions.ShareByText                -> handleShareByText()
+        }
+    }
+
+    private fun handleShareByText() {
+        session.permalinkService().createPermalink(session.myUserId)?.let { permalink ->
+            val text = stringProvider.getString(R.string.invite_friends_text, permalink)
+            _viewEvents.post(UserCodeShareViewEvents.SharePlainText(
+                    text,
+                    stringProvider.getString(R.string.invite_friends),
+                    stringProvider.getString(R.string.invite_friends_rich_title)
+            ))
         }
     }
 
diff --git a/vector/src/main/res/layout/activity.xml b/vector/src/main/res/layout/activity.xml
index b5203cd589..9e56d9e605 100644
--- a/vector/src/main/res/layout/activity.xml
+++ b/vector/src/main/res/layout/activity.xml
@@ -1,26 +1,32 @@
 <?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/vector_coordinator_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <androidx.appcompat.widget.Toolbar
-        android:id="@+id/toolbar"
-        style="@style/VectorToolbarStyle"
+    <androidx.constraintlayout.widget.ConstraintLayout
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:elevation="4dp"
-        app:layout_constraintTop_toTopOf="parent" />
+        android:layout_height="match_parent">
 
-    <androidx.fragment.app.FragmentContainerView
-        android:id="@+id/container"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/toolbar" />
+        <androidx.appcompat.widget.Toolbar
+            android:id="@+id/toolbar"
+            style="@style/VectorToolbarStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:elevation="4dp"
+            app:layout_constraintTop_toTopOf="parent" />
 
-    <include layout="@layout/merge_overlay_waiting_view"/>
+        <androidx.fragment.app.FragmentContainerView
+            android:id="@+id/container"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/toolbar" />
 
-</androidx.constraintlayout.widget.ConstraintLayout>
+        <include layout="@layout/merge_overlay_waiting_view" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/vector/src/main/res/layout/fragment_user_code_show.xml b/vector/src/main/res/layout/fragment_user_code_show.xml
index 92c40b1eb2..ca65c64f19 100644
--- a/vector/src/main/res/layout/fragment_user_code_show.xml
+++ b/vector/src/main/res/layout/fragment_user_code_show.xml
@@ -49,6 +49,19 @@
                     app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintHorizontal_bias="0.0"
                     app:layout_constraintStart_toEndOf="@+id/showUserCodeClose"
+                    app:layout_constraintEnd_toStartOf="@id/shareByText"
+                    app:layout_constraintTop_toTopOf="parent" />
+
+                <ImageView
+                    android:id="@+id/shareByText"
+                    android:layout_width="@dimen/layout_touch_size"
+                    android:layout_height="@dimen/layout_touch_size"
+                    android:scaleType="center"
+                    android:src="@drawable/ic_share"
+                    app:tint="@color/riotx_accent"
+                    android:layout_marginEnd="@dimen/layout_horizontal_margin"
+                    app:layout_constraintBottom_toBottomOf="parent"
+                    app:layout_constraintEnd_toEndOf="parent"
                     app:layout_constraintTop_toTopOf="parent" />
 
             </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index b6f2e15ab2..d32dd86a19 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -425,6 +425,8 @@
     <string name="permissions_msg_contacts_warning_other_androids">Element can check your address book to find other Matrix users based on their email and phone numbers.\n\nDo you agree to share your address book for this purpose?</string>
 
     <string name="permissions_action_not_performed_missing_permissions">Sorry. Action not performed, due to missing permissions</string>
+    <string name="permissions_denied_qr_code">To scan a QR code, allow Camera permission to take a picture</string>
+    <string name="permissions_denied_add_contact">To check your address book, allow Contact permission.</string>
 
     <!-- medias slider string -->
     <string name="media_slider_saved">Saved</string>
diff --git a/vector/src/main/res/values/style_snackbar.xml b/vector/src/main/res/values/style_snackbar.xml
index 7e0dbc0e0b..5f1412e0b4 100644
--- a/vector/src/main/res/values/style_snackbar.xml
+++ b/vector/src/main/res/values/style_snackbar.xml
@@ -5,7 +5,9 @@
         <item name="android:background">@color/notification_accent_color</item>
     </style>
 
-    <style name="VectorSnackBarButton" parent="@style/Widget.MaterialComponents.Button" />
+    <style name="VectorSnackBarButton" parent="@style/Widget.MaterialComponents.Button">
+        <item name="android:textColor">@color/white</item>
+    </style>
 
     <style name="VectorSnackBarText" parent="@style/Widget.MaterialComponents.Snackbar.TextView">
         <item name="android:textColor">@color/white</item>