diff --git a/CHANGES.md b/CHANGES.md
index c923053b24..ce507d4715 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -5,6 +5,7 @@ Features ✨:
  -
 
 Improvements 🙌:
+ - You can now join room through permalink and within room directory search
  - Add long click gesture to copy userId, user display name, room name, room topic and room alias (#1774)
 
 Bugfix 🐛:
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt
index 85632d6e83..1da65b3002 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt
@@ -25,7 +25,12 @@ import android.net.Uri
  */
 sealed class PermalinkData {
 
-    data class RoomLink(val roomIdOrAlias: String, val isRoomAlias: Boolean, val eventId: String?) : PermalinkData()
+    data class RoomLink(
+            val roomIdOrAlias: String,
+            val isRoomAlias: Boolean,
+            val eventId: String?,
+            val viaParameters: List<String>
+    ) : PermalinkData()
 
     data class UserLink(val userId: String) : PermalinkData()
 
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt
index dd6847f1e3..59e289ffd7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt
@@ -18,6 +18,7 @@
 package org.matrix.android.sdk.api.session.permalinks
 
 import android.net.Uri
+import android.net.UrlQuerySanitizer
 import org.matrix.android.sdk.api.MatrixPatterns
 
 /**
@@ -40,14 +41,13 @@ object PermalinkParser {
         if (!uri.toString().startsWith(PermalinkService.MATRIX_TO_URL_BASE)) {
             return PermalinkData.FallbackLink(uri)
         }
-
         val fragment = uri.fragment
         if (fragment.isNullOrEmpty()) {
             return PermalinkData.FallbackLink(uri)
         }
-
         val indexOfQuery = fragment.indexOf("?")
         val safeFragment = if (indexOfQuery != -1) fragment.substring(0, indexOfQuery) else fragment
+        val viaQueryParameters = fragment.getViaParameters()
 
         // we are limiting to 2 params
         val params = safeFragment
@@ -65,17 +65,29 @@ object PermalinkParser {
                 PermalinkData.RoomLink(
                         roomIdOrAlias = identifier,
                         isRoomAlias = false,
-                        eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }
+                        eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
+                        viaParameters = viaQueryParameters
                 )
             }
             MatrixPatterns.isRoomAlias(identifier) -> {
                 PermalinkData.RoomLink(
                         roomIdOrAlias = identifier,
                         isRoomAlias = true,
-                        eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }
+                        eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
+                        viaParameters = viaQueryParameters
                 )
             }
             else                                   -> PermalinkData.FallbackLink(uri)
         }
     }
+
+    private fun String.getViaParameters(): List<String> {
+        return UrlQuerySanitizer(this)
+                .parameterList
+                .filter {
+                    it.mParameter == "via"
+                }.map {
+                    it.mValue
+                }
+    }
 }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt
index aa608ef4ef..de82689303 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt
@@ -77,16 +77,15 @@ class RoomDetailActivity :
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         waitingView = waiting_view
+        val roomDetailArgs: RoomDetailArgs? = if (intent?.action == ACTION_ROOM_DETAILS_FROM_SHORTCUT) {
+            RoomDetailArgs(roomId = intent?.extras?.getString(EXTRA_ROOM_ID)!!)
+        } else {
+            intent?.extras?.getParcelable(EXTRA_ROOM_DETAIL_ARGS)
+        }
+        if (roomDetailArgs == null) return
+        currentRoomId = roomDetailArgs.roomId
+
         if (isFirstCreation()) {
-            val roomDetailArgs: RoomDetailArgs? = if (intent?.action == ACTION_ROOM_DETAILS_FROM_SHORTCUT) {
-                RoomDetailArgs(roomId = intent?.extras?.getString(EXTRA_ROOM_ID)!!)
-            } else {
-                intent?.extras?.getParcelable(EXTRA_ROOM_DETAIL_ARGS)
-            }
-
-            if (roomDetailArgs == null) return
-
-            currentRoomId = roomDetailArgs.roomId
             replaceFragment(R.id.roomDetailContainer, RoomDetailFragment::class.java, roomDetailArgs)
             replaceFragment(R.id.roomDetailDrawerContainer, BreadcrumbsFragment::class.java)
         }
diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
index 3da6a7257a..5de8796c06 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
@@ -54,6 +54,7 @@ import im.vector.app.features.pin.PinMode
 import im.vector.app.features.roomdirectory.RoomDirectoryActivity
 import im.vector.app.features.roomdirectory.createroom.CreateRoomActivity
 import im.vector.app.features.roomdirectory.roompreview.RoomPreviewActivity
+import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
 import im.vector.app.features.roommemberprofile.RoomMemberProfileActivity
 import im.vector.app.features.roommemberprofile.RoomMemberProfileArgs
 import im.vector.app.features.roomprofile.RoomProfileActivity
@@ -156,14 +157,6 @@ class DefaultNavigator @Inject constructor(
         }
     }
 
-    override fun openNotJoinedRoom(context: Context, roomIdOrAlias: String?, eventId: String?, buildTask: Boolean) {
-        if (context is VectorBaseActivity) {
-            context.notImplemented("Open not joined room")
-        } else {
-            context.toast(R.string.not_implemented)
-        }
-    }
-
     override fun openGroupDetail(groupId: String, context: Context, buildTask: Boolean) {
         if (context is VectorBaseActivity) {
             context.notImplemented("Open group detail")
@@ -186,7 +179,12 @@ class DefaultNavigator @Inject constructor(
     }
 
     override fun openRoomPreview(context: Context, publicRoom: PublicRoom, roomDirectoryData: RoomDirectoryData) {
-        val intent = RoomPreviewActivity.getIntent(context, publicRoom, roomDirectoryData)
+        val intent = RoomPreviewActivity.newIntent(context, publicRoom, roomDirectoryData)
+        context.startActivity(intent)
+    }
+
+    override fun openRoomPreview(context: Context, roomPreviewData: RoomPreviewData) {
+        val intent = RoomPreviewActivity.newIntent(context, roomPreviewData)
         context.startActivity(intent)
     }
 
diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
index ee64c5fc75..ed710a124f 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
@@ -25,6 +25,7 @@ import im.vector.app.features.home.room.detail.widget.WidgetRequestCodes
 import im.vector.app.features.media.AttachmentData
 import im.vector.app.features.pin.PinActivity
 import im.vector.app.features.pin.PinMode
+import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
 import im.vector.app.features.settings.VectorSettingsActivity
 import im.vector.app.features.share.SharedData
 import im.vector.app.features.terms.ReviewTermsActivity
@@ -50,10 +51,10 @@ interface Navigator {
 
     fun openRoomForSharingAndFinish(activity: Activity, roomId: String, sharedData: SharedData)
 
-    fun openNotJoinedRoom(context: Context, roomIdOrAlias: String?, eventId: String? = null, buildTask: Boolean = false)
-
     fun openRoomPreview(context: Context, publicRoom: PublicRoom, roomDirectoryData: RoomDirectoryData)
 
+    fun openRoomPreview(context: Context, roomPreviewData: RoomPreviewData)
+
     fun openCreateRoom(context: Context, initialName: String = "")
 
     fun openCreateDirectRoom(context: Context)
diff --git a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt
index 87d114c01b..11c55f6a73 100644
--- a/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt
+++ b/vector/src/main/java/im/vector/app/features/permalink/PermalinkHandler.kt
@@ -18,13 +18,18 @@ package im.vector.app.features.permalink
 
 import android.content.Context
 import android.net.Uri
+import im.vector.app.R
 import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.utils.toast
 import im.vector.app.features.navigation.Navigator
+import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData
 import io.reactivex.Single
 import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.schedulers.Schedulers
+import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.session.permalinks.PermalinkData
 import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
+import org.matrix.android.sdk.api.session.room.model.Membership
 import org.matrix.android.sdk.api.util.Optional
 import org.matrix.android.sdk.rx.rx
 import javax.inject.Inject
@@ -51,14 +56,37 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
         if (deepLink == null) {
             return Single.just(false)
         }
-        return when (val permalinkData = PermalinkParser.parse(deepLink)) {
+        return Single
+                .fromCallable {
+                    PermalinkParser.parse(deepLink)
+                }
+                .subscribeOn(Schedulers.computation())
+                .observeOn(AndroidSchedulers.mainThread())
+                .flatMap { permalinkData ->
+                    handlePermalink(permalinkData, context, navigationInterceptor, buildTask)
+                }
+                .onErrorReturnItem(false)
+    }
+
+    private fun handlePermalink(
+            permalinkData: PermalinkData,
+            context: Context,
+            navigationInterceptor: NavigationInterceptor?,
+            buildTask: Boolean
+    ): Single<Boolean> {
+        return when (permalinkData) {
             is PermalinkData.RoomLink     -> {
                 permalinkData.getRoomId()
                         .observeOn(AndroidSchedulers.mainThread())
                         .map {
                             val roomId = it.getOrNull()
                             if (navigationInterceptor?.navToRoom(roomId, permalinkData.eventId) != true) {
-                                openRoom(context, roomId, permalinkData.eventId, buildTask)
+                                openRoom(
+                                        context = context,
+                                        roomId = roomId,
+                                        permalinkData = permalinkData,
+                                        buildTask = buildTask
+                                )
                             }
                             true
                         }
@@ -82,22 +110,55 @@ class PermalinkHandler @Inject constructor(private val activeSessionHolder: Acti
     private fun PermalinkData.RoomLink.getRoomId(): Single<Optional<String>> {
         val session = activeSessionHolder.getSafeActiveSession()
         return if (isRoomAlias && session != null) {
-            // At the moment we are not fetching on the server as we don't handle not join room
-            session.rx().getRoomIdByAlias(roomIdOrAlias, false).subscribeOn(Schedulers.io())
+            session.rx().getRoomIdByAlias(roomIdOrAlias, true).subscribeOn(Schedulers.io())
         } else {
             Single.just(Optional.from(roomIdOrAlias))
         }
     }
 
+    private fun PermalinkData.RoomLink.getRoomAliasOrNull(): String? {
+        return if (isRoomAlias) {
+            roomIdOrAlias
+        } else {
+            null
+        }
+    }
+
     /**
      * Open room either joined, or not
      */
-    private fun openRoom(context: Context, roomId: String?, eventId: String?, buildTask: Boolean) {
+    private fun openRoom(
+            context: Context,
+            roomId: String?,
+            permalinkData: PermalinkData.RoomLink,
+            buildTask: Boolean
+    ) {
         val session = activeSessionHolder.getSafeActiveSession() ?: return
-        return if (roomId != null && session.getRoom(roomId) != null) {
-            navigator.openRoom(context, roomId, eventId, buildTask)
-        } else {
-            navigator.openNotJoinedRoom(context, roomId, eventId, buildTask)
+        if (roomId == null) {
+            context.toast(R.string.room_error_not_found)
+            return
+        }
+        val roomSummary = session.getRoomSummary(roomId)
+        val membership = roomSummary?.membership
+        val eventId = permalinkData.eventId
+        val roomAlias = permalinkData.getRoomAliasOrNull()
+        return when {
+            membership == Membership.BAN     -> context.toast(R.string.error_opening_banned_room)
+            membership?.isActive().orFalse() -> {
+                navigator.openRoom(context, roomId, eventId, buildTask)
+            }
+            else                             -> {
+                val roomPreviewData = RoomPreviewData(
+                        roomId = roomId,
+                        eventId = eventId,
+                        roomAlias = roomAlias ?: roomSummary?.canonicalAlias,
+                        roomName = roomSummary?.displayName,
+                        avatarUrl = roomSummary?.avatarUrl,
+                        buildTask = buildTask,
+                        homeServers = permalinkData.viaParameters
+                )
+                navigator.openRoomPreview(context, roomPreviewData)
+            }
         }
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsController.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsController.kt
index c60336c1af..b71b494948 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsController.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsController.kt
@@ -28,8 +28,10 @@ import im.vector.app.core.epoxy.noResultItem
 import im.vector.app.core.error.ErrorFormatter
 import im.vector.app.core.resources.StringProvider
 import im.vector.app.features.home.AvatarRenderer
+import org.matrix.android.sdk.api.MatrixPatterns
 import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
+import org.matrix.android.sdk.api.util.MatrixItem
 import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
 
@@ -42,8 +44,10 @@ class PublicRoomsController @Inject constructor(private val stringProvider: Stri
     override fun buildModels(viewState: PublicRoomsViewState) {
         val publicRooms = viewState.publicRooms
 
-        if (publicRooms.isEmpty()
-                && viewState.asyncPublicRoomsRequest is Success) {
+        val unknownRoomItem = viewState.buildUnknownRoomIfNeeded()
+
+        val noResult = publicRooms.isEmpty() && viewState.asyncPublicRoomsRequest is Success && unknownRoomItem == null
+        if (noResult) {
             // No result
             noResultItem {
                 id("noResult")
@@ -54,6 +58,8 @@ class PublicRoomsController @Inject constructor(private val stringProvider: Stri
                 buildPublicRoom(it, viewState)
             }
 
+            unknownRoomItem?.addTo(this)
+
             if ((viewState.hasMore && viewState.asyncPublicRoomsRequest is Success)
                     || viewState.asyncPublicRoomsRequest is Incomplete) {
                 loadingItem {
@@ -109,7 +115,29 @@ class PublicRoomsController @Inject constructor(private val stringProvider: Stri
         }
     }
 
+    private fun PublicRoomsViewState.buildUnknownRoomIfNeeded(): UnknownRoomItem? {
+        val roomIdOrAlias = currentFilter.trim()
+        val isAlias = MatrixPatterns.isRoomAlias(roomIdOrAlias) && !publicRooms.any { it.canonicalAlias == roomIdOrAlias }
+        val isRoomId = !isAlias && MatrixPatterns.isRoomId(roomIdOrAlias) && !publicRooms.any { it.roomId == roomIdOrAlias }
+        val roomItem = when {
+            isAlias  -> MatrixItem.RoomAliasItem(roomIdOrAlias, roomIdOrAlias)
+            isRoomId -> MatrixItem.RoomItem(roomIdOrAlias)
+            else     -> null
+        }
+        return roomItem?.let {
+            UnknownRoomItem_().apply {
+                id(roomIdOrAlias)
+                matrixItem(it)
+                avatarRenderer(this@PublicRoomsController.avatarRenderer)
+                globalListener {
+                    callback?.onUnknownRoomClicked(roomIdOrAlias)
+                }
+            }
+        }
+    }
+
     interface Callback {
+        fun onUnknownRoomClicked(roomIdOrAlias: String)
         fun onPublicRoomClicked(publicRoom: PublicRoom, joinState: JoinState)
         fun onPublicRoomJoin(publicRoom: PublicRoom)
         fun loadMore()
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt
index 57006af6f1..b180018480 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt
@@ -29,9 +29,13 @@ import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.extensions.exhaustive
 import im.vector.app.core.extensions.trackItemsVisibilityChange
 import im.vector.app.core.platform.VectorBaseFragment
-import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
+import im.vector.app.core.utils.toast
+import im.vector.app.features.permalink.NavigationInterceptor
+import im.vector.app.features.permalink.PermalinkHandler
 import io.reactivex.rxkotlin.subscribeBy
 import kotlinx.android.synthetic.main.fragment_public_rooms.*
+import org.matrix.android.sdk.api.session.Session
+import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
 import timber.log.Timber
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -41,7 +45,9 @@ import javax.inject.Inject
  * - When filtering more (when entering new chars), we could filter on result we already have, during the new server request, to avoid empty screen effect
  */
 class PublicRoomsFragment @Inject constructor(
-        private val publicRoomsController: PublicRoomsController
+        private val publicRoomsController: PublicRoomsController,
+        private val permalinkHandler: PermalinkHandler,
+        private val session: Session
 ) : VectorBaseFragment(), PublicRoomsController.Callback {
 
     private val viewModel: RoomDirectoryViewModel by activityViewModel()
@@ -112,6 +118,23 @@ class PublicRoomsFragment @Inject constructor(
         publicRoomsController.callback = this
     }
 
+    override fun onUnknownRoomClicked(roomIdOrAlias: String) {
+        val permalink = session.permalinkService().createPermalink(roomIdOrAlias)
+        permalinkHandler
+                .launch(requireContext(), permalink, object : NavigationInterceptor {
+                    override fun navToRoom(roomId: String?, eventId: String?): Boolean {
+                        requireActivity().finish()
+                        return false
+                    }
+                })
+                .subscribe { isSuccessful ->
+                    if (!isSuccessful) {
+                        requireContext().toast(R.string.room_error_not_found)
+                    }
+                }
+                .disposeOnDestroyView()
+    }
+
     override fun onPublicRoomClicked(publicRoom: PublicRoom, joinState: JoinState) {
         Timber.v("PublicRoomClicked: $publicRoom")
         withState(viewModel) { state ->
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/UnknownRoomItem.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/UnknownRoomItem.kt
new file mode 100644
index 0000000000..084f518405
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/UnknownRoomItem.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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.app.features.roomdirectory
+
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.airbnb.epoxy.EpoxyAttribute
+import com.airbnb.epoxy.EpoxyModelClass
+import im.vector.app.R
+import im.vector.app.core.epoxy.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+import im.vector.app.features.home.AvatarRenderer
+import org.matrix.android.sdk.api.util.MatrixItem
+
+@EpoxyModelClass(layout = R.layout.item_unknown_room)
+abstract class UnknownRoomItem : VectorEpoxyModel<UnknownRoomItem.Holder>() {
+
+    @EpoxyAttribute
+    lateinit var avatarRenderer: AvatarRenderer
+
+    @EpoxyAttribute
+    lateinit var matrixItem: MatrixItem
+
+    @EpoxyAttribute
+    var globalListener: (() -> Unit)? = null
+
+    override fun bind(holder: Holder) {
+        super.bind(holder)
+        holder.rootView.setOnClickListener { globalListener?.invoke() }
+        avatarRenderer.render(matrixItem, holder.avatarView)
+        holder.nameView.text = matrixItem.displayName
+    }
+
+    class Holder : VectorEpoxyHolder() {
+        val rootView by bind<ViewGroup>(R.id.itemUnknownRoomLayout)
+        val avatarView by bind<ImageView>(R.id.itemUnknownRoomAvatar)
+        val nameView by bind<TextView>(R.id.itemUnknownRoomName)
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt
index 0a25d93de2..8bbaa14ab0 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt
@@ -24,20 +24,22 @@ import im.vector.app.R
 import im.vector.app.core.extensions.addFragment
 import im.vector.app.core.platform.ToolbarConfigurable
 import im.vector.app.core.platform.VectorBaseActivity
+import kotlinx.android.parcel.Parcelize
 import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
 import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
 import org.matrix.android.sdk.api.util.MatrixItem
-import kotlinx.android.parcel.Parcelize
 
 @Parcelize
 data class RoomPreviewData(
         val roomId: String,
-        val roomName: String?,
-        val roomAlias: String?,
-        val topic: String?,
-        val worldReadable: Boolean,
-        val avatarUrl: String?,
-        val homeServer: String?
+        val eventId: String? = null,
+        val roomName: String? = null,
+        val roomAlias: String? = null,
+        val topic: String? = null,
+        val worldReadable: Boolean = false,
+        val avatarUrl: String? = null,
+        val homeServers: List<String> = emptyList(),
+        val buildTask: Boolean = false
 ) : Parcelable {
     val matrixItem: MatrixItem
         get() = MatrixItem.RoomItem(roomId, roomName ?: roomAlias, avatarUrl)
@@ -48,19 +50,24 @@ class RoomPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
     companion object {
         private const val ARG = "ARG"
 
-        fun getIntent(context: Context, publicRoom: PublicRoom, roomDirectoryData: RoomDirectoryData): Intent {
+        fun newIntent(context: Context, roomPreviewData: RoomPreviewData): Intent {
             return Intent(context, RoomPreviewActivity::class.java).apply {
-                putExtra(ARG, RoomPreviewData(
-                        roomId = publicRoom.roomId,
-                        roomName = publicRoom.name,
-                        roomAlias = publicRoom.getPrimaryAlias(),
-                        topic = publicRoom.topic,
-                        worldReadable = publicRoom.worldReadable,
-                        avatarUrl = publicRoom.avatarUrl,
-                        homeServer = roomDirectoryData.homeServer
-                ))
+                putExtra(ARG, roomPreviewData)
             }
         }
+
+        fun newIntent(context: Context, publicRoom: PublicRoom, roomDirectoryData: RoomDirectoryData): Intent {
+            val roomPreviewData = RoomPreviewData(
+                    roomId = publicRoom.roomId,
+                    roomName = publicRoom.name,
+                    roomAlias = publicRoom.getPrimaryAlias(),
+                    topic = publicRoom.topic,
+                    worldReadable = publicRoom.worldReadable,
+                    avatarUrl = publicRoom.avatarUrl,
+                    homeServers = listOfNotNull(roomDirectoryData.homeServer)
+            )
+            return newIntent(context, roomPreviewData)
+        }
     }
 
     override fun getLayoutRes() = R.layout.activity_simple
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt
index 5d13d3d9fe..108c3bacf1 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt
@@ -48,13 +48,15 @@ class RoomPreviewNoPreviewFragment @Inject constructor(
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
         setupToolbar(roomPreviewNoPreviewToolbar)
+        val titleText = roomPreviewData.roomName ?: roomPreviewData.roomAlias ?: roomPreviewData.roomId
+
         // Toolbar
         avatarRenderer.render(roomPreviewData.matrixItem, roomPreviewNoPreviewToolbarAvatar)
-        roomPreviewNoPreviewToolbarTitle.text = roomPreviewData.roomName ?: roomPreviewData.roomAlias
+        roomPreviewNoPreviewToolbarTitle.text = titleText
 
         // Screen
         avatarRenderer.render(roomPreviewData.matrixItem, roomPreviewNoPreviewAvatar)
-        roomPreviewNoPreviewName.text = roomPreviewData.roomName ?: roomPreviewData.roomAlias
+        roomPreviewNoPreviewName.text = titleText
         roomPreviewNoPreviewTopic.setTextOrHide(roomPreviewData.topic)
 
         if (roomPreviewData.worldReadable) {
@@ -98,7 +100,7 @@ class RoomPreviewNoPreviewFragment @Inject constructor(
             // Quit this screen
             requireActivity().finish()
             // Open room
-            navigator.openRoom(requireActivity(), roomPreviewData.roomId)
+            navigator.openRoom(requireActivity(), roomPreviewData.roomId, roomPreviewData.eventId, roomPreviewData.buildTask)
         }
     }
 }
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt
index 04b7c33fb2..900ba537b5 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt
@@ -106,10 +106,7 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini
             Timber.w("Try to join an already joining room. Should not happen")
             return@withState
         }
-        val viaServers = state.homeServer?.let {
-            listOf(it)
-        } ?: emptyList()
-        session.joinRoom(state.roomId, viaServers = viaServers, callback = object : MatrixCallback<Unit> {
+        session.joinRoom(state.roomId, viaServers = state.homeServers, callback = object : MatrixCallback<Unit> {
             override fun onSuccess(data: Unit) {
                 // We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data.
                 // Instead, we wait for the room to be joined
diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt
index f461225e2d..6816e54481 100644
--- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt
@@ -24,10 +24,9 @@ data class RoomPreviewViewState(
         val roomId: String = "",
         val roomAlias: String? = null,
         /**
-         * The server name (might be null)
-         * Set null when the server is the current user's home server.
+         * Can be empty when the server is the current user's home server.
          */
-        val homeServer: String? = null,
+        val homeServers: List<String> = emptyList(),
         // Current state of the room in preview
         val roomJoinState: JoinState = JoinState.NOT_JOINED,
         // Last error of join room request
@@ -37,6 +36,6 @@ data class RoomPreviewViewState(
     constructor(args: RoomPreviewData) : this(
             roomId = args.roomId,
             roomAlias = args.roomAlias,
-            homeServer = args.homeServer
+            homeServers = args.homeServers
     )
 }
diff --git a/vector/src/main/res/layout/item_unknown_room.xml b/vector/src/main/res/layout/item_unknown_room.xml
new file mode 100644
index 0000000000..a097767e63
--- /dev/null
+++ b/vector/src/main/res/layout/item_unknown_room.xml
@@ -0,0 +1,52 @@
+<?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:id="@+id/itemUnknownRoomLayout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?riotx_background"
+    android:clickable="true"
+    android:focusable="true"
+    android:foreground="?attr/selectableItemBackground"
+    android:minHeight="64dp">
+
+    <ImageView
+        android:id="@+id/itemUnknownRoomAvatar"
+        android:layout_width="56dp"
+        android:layout_height="56dp"
+        android:layout_marginStart="8dp"
+        app:layout_constraintBottom_toTopOf="@+id/itemPublicRoomBottomSeparator"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:src="@tools:sample/avatars" />
+
+    <TextView
+        android:id="@+id/itemUnknownRoomName"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="17dp"
+        android:layout_marginEnd="8dp"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:textColor="?riotx_text_primary"
+        android:textSize="15sp"
+        android:textStyle="bold"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@id/itemUnknownRoomAvatar"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_chainStyle="packed"
+        tools:text="@sample/matrix.json/data/roomName" />
+
+    <View
+        android:id="@+id/itemPublicRoomBottomSeparator"
+        android:layout_width="0dp"
+        android:layout_height="1dp"
+        android:background="?riotx_header_panel_border_mobile"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index 0b9cbab57a..7506a4d502 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -2539,4 +2539,6 @@
     <string name="settings_security_pin_code_title">Enable PIN</string>
     <string name="settings_security_pin_code_summary">If you want to reset your PIN, tap Forgot PIN to logout and reset.</string>
     <string name="auth_pin_confirm_to_disable_title">Confirm PIN to disable PIN</string>
+    <string name="error_opening_banned_room">Can\'t open a room where you are banned from.</string>
+    <string name="room_error_not_found">Can\'t find this room. Make sure it exists.</string>
 </resources>