Handle M_CONSENT_NOT_GIVEN error (#64)

This commit is contained in:
Benoit Marty 2019-09-13 18:21:56 +02:00
parent 137dcab734
commit 3e6b65e174
21 changed files with 689 additions and 6 deletions

View File

@ -2,7 +2,7 @@ Changes in RiotX 0.5.0 (2019-XX-XX)
===================================================
Features:
-
- Handle M_CONSENT_NOT_GIVEN error (#64)
Improvements:
- Reduce default release build log level, and lab option to enable more logs.

View File

@ -139,6 +139,9 @@ dependencies {
implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'com.facebook.stetho:stetho-okhttp3:1.5.0'
// Bus
implementation 'org.greenrobot:eventbus:3.1.1'
debugImplementation 'com.airbnb.okreplay:okreplay:1.4.0'
releaseImplementation 'com.airbnb.okreplay:noop:1.4.0'
androidTestImplementation 'com.airbnb.okreplay:espresso:1.4.0'

View File

@ -0,0 +1,22 @@
/*
* 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.matrix.android.api.failure
// This data class will be sent to the bus
data class ConsentNotGivenError(
val consentUri: String
)

View File

@ -18,10 +18,12 @@ package im.vector.matrix.android.internal.network
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.Moshi
import im.vector.matrix.android.api.failure.ConsentNotGivenError
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.failure.MatrixError
import im.vector.matrix.android.internal.di.MoshiProvider
import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import retrofit2.Call
import timber.log.Timber
import java.io.IOException
@ -65,6 +67,11 @@ internal class Request<DATA> {
val matrixError = matrixErrorAdapter.fromJson(errorBodyStr)
if (matrixError != null) {
if (matrixError.code == MatrixError.M_CONSENT_NOT_GIVEN && !matrixError.consentUri.isNullOrBlank()) {
// Also send this error to the bus, for a global management
EventBus.getDefault().post(ConsentNotGivenError(matrixError.consentUri))
}
return Failure.ServerError(matrixError, httpCode)
}
} catch (ex: JsonDataException) {

View File

@ -280,6 +280,9 @@ dependencies {
implementation "ru.noties.markwon:html:$markwon_version"
implementation 'me.saket:better-link-movement-method:2.2.0'
// Bus
implementation 'org.greenrobot:eventbus:3.1.1'
// Passphrase strength helper
implementation 'com.nulab-inc:zxcvbn:1.2.5'

View File

@ -65,6 +65,7 @@
<activity android:name=".features.home.room.detail.RoomDetailActivity" />
<activity android:name=".features.debug.DebugMenuActivity" />
<activity android:name=".features.home.createdirect.CreateDirectRoomActivity" />
<activity android:name=".features.webview.VectorWebViewActivity" />
<!-- Services -->

View File

@ -349,6 +349,11 @@ SOFTWARE.
<br/>
Copyright 2018 The diff-match-patch Authors. https://github.com/google/diff-match-patch
</li>
<li>
<b>EventBus</b>
<br/>
Copyright (C) 2012-2017 Markus Junginger, greenrobot (http://greenrobot.org)
</li>
</ul>

View File

@ -26,9 +26,9 @@ private const val KEY_DIALOG_IS_DISPLAYED = "DialogLocker.KEY_DIALOG_IS_DISPLAYE
/**
* Class to avoid displaying twice the same dialog
*/
class DialogLocker() : Restorable {
class DialogLocker(savedInstanceState: Bundle?) : Restorable {
private var isDialogDisplayed: Boolean = false
private var isDialogDisplayed = savedInstanceState?.getBoolean(KEY_DIALOG_IS_DISPLAYED, false) == true
private fun unlock() {
isDialogDisplayed = false

View File

@ -17,6 +17,7 @@
package im.vector.riotx.core.error
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.failure.MatrixError
import im.vector.riotx.R
import im.vector.riotx.core.resources.StringProvider
import javax.inject.Inject
@ -34,8 +35,13 @@ class ErrorFormatter @Inject constructor(val stringProvider: StringProvider) {
null -> null
is Failure.NetworkConnection -> stringProvider.getString(R.string.error_no_network)
is Failure.ServerError -> {
throwable.error.message.takeIf { it.isNotEmpty() }
?: throwable.error.code.takeIf { it.isNotEmpty() }
if (throwable.error.code == MatrixError.M_CONSENT_NOT_GIVEN) {
// Special case for terms and conditions
stringProvider.getString(R.string.error_terms_not_accepted)
} else {
throwable.error.message.takeIf { it.isNotEmpty() }
?: throwable.error.code.takeIf { it.isNotEmpty() }
}
}
else -> throwable.localizedMessage
}

View File

@ -36,11 +36,14 @@ import butterknife.Unbinder
import com.airbnb.mvrx.BaseMvRxActivity
import com.bumptech.glide.util.Util
import com.google.android.material.snackbar.Snackbar
import im.vector.matrix.android.api.failure.ConsentNotGivenError
import im.vector.riotx.BuildConfig
import im.vector.riotx.R
import im.vector.riotx.core.di.*
import im.vector.riotx.core.dialogs.DialogLocker
import im.vector.riotx.core.utils.toast
import im.vector.riotx.features.configuration.VectorConfiguration
import im.vector.riotx.features.consent.ConsentNotGivenHelper
import im.vector.riotx.features.navigation.Navigator
import im.vector.riotx.features.rageshake.BugReportActivity
import im.vector.riotx.features.rageshake.BugReporter
@ -50,6 +53,9 @@ import im.vector.riotx.features.themes.ThemeUtils
import im.vector.riotx.receivers.DebugReceiver
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import timber.log.Timber
import kotlin.system.measureTimeMillis
@ -391,6 +397,31 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasScreenInjector {
}
}
/* ==========================================================================================
* User Consent
* ========================================================================================== */
private val consentNotGivenHelper by lazy {
ConsentNotGivenHelper(this, DialogLocker(savedInstanceState))
.apply { restorables.add(this) }
}
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onConsentNotGivenError(consentNotGivenError: ConsentNotGivenError) {
consentNotGivenHelper.displayDialog(consentNotGivenError.consentUri,
screenComponent.session().sessionParams.homeServerConnectionConfig.homeServerUri.host ?: "")
}
/* ==========================================================================================
* Temporary method
* ========================================================================================== */
@ -402,5 +433,4 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasScreenInjector {
toast(getString(R.string.not_implemented))
}
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2018 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.core.utils
import java.lang.ref.WeakReference
import kotlin.reflect.KProperty
fun <T> weak(value: T) = WeakReferenceDelegate(value)
class WeakReferenceDelegate<T>(value: T) {
private var weakReference: WeakReference<T> = WeakReference(value)
operator fun getValue(thisRef: Any, property: KProperty<*>): T? = weakReference.get()
operator fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
weakReference = WeakReference(value)
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 2018 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.consent
import android.app.Activity
import androidx.appcompat.app.AlertDialog
import im.vector.riotx.R
import im.vector.riotx.core.dialogs.DialogLocker
import im.vector.riotx.core.platform.Restorable
import im.vector.riotx.features.webview.VectorWebViewActivity
import im.vector.riotx.features.webview.WebViewMode
class ConsentNotGivenHelper(private val activity: Activity,
private val dialogLocker: DialogLocker) :
Restorable by dialogLocker {
/* ==========================================================================================
* Public methods
* ========================================================================================== */
/**
* Display the consent dialog, if not already displayed
*/
fun displayDialog(consentUri: String, homeServerHost: String) {
dialogLocker.displayDialog {
AlertDialog.Builder(activity)
.setTitle(R.string.settings_app_term_conditions)
.setMessage(activity.getString(R.string.dialog_user_consent_content, homeServerHost))
.setPositiveButton(R.string.dialog_user_consent_submit) { _, _ ->
openWebViewActivity(consentUri)
}
}
}
/* ==========================================================================================
* Private
* ========================================================================================== */
private fun openWebViewActivity(consentUri: String) {
val intent = VectorWebViewActivity.getIntent(activity, consentUri, activity.getString(R.string.settings_app_term_conditions), WebViewMode.CONSENT)
activity.startActivity(intent)
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright 2018 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.webview
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.core.utils.weak
import timber.log.Timber
private const val SUCCESS_URL_SUFFIX = "/_matrix/consent"
private const val RIOT_BOT_ID = "@riot-bot:matrix.org"
/**
* This class is the Consent implementation of WebViewEventListener.
* It is used to manage the consent agreement flow.
*/
class ConsentWebViewEventListener(activity: VectorBaseActivity,
private val session: Session,
private val delegate: WebViewEventListener)
: WebViewEventListener by delegate {
private val safeActivity: VectorBaseActivity? by weak(activity)
override fun onPageFinished(url: String) {
delegate.onPageFinished(url)
if (url.endsWith(SUCCESS_URL_SUFFIX)) {
createRiotBotRoomIfNeeded()
}
}
/**
* This methods try to create the RiotBot room when the user gives his agreement
*/
private fun createRiotBotRoomIfNeeded() {
safeActivity?.let {
/* We do not create a Room with RiotBot in RiotX for the moment
val joinedRooms = session.dataHandler.store.rooms.filter {
it.isJoined
}
if (joinedRooms.isEmpty()) {
it.showWaitingView()
// Ensure we can create a Room with riot-bot. Error can be a MatrixError: "Federation denied with matrix.org.", or any other error.
session.profileApiClient
.displayname(RIOT_BOT_ID, object : MatrixCallback<String>(createRiotBotRoomCallback) {
override fun onSuccess(info: String?) {
// Ok, the Home Server knows riot-Bot, so create a Room with him
session.createDirectMessageRoom(RIOT_BOT_ID, createRiotBotRoomCallback)
}
})
} else {
*/
it.finish()
/*
}
*/
}
}
/**
* APICallback instance
*/
private val createRiotBotRoomCallback = object : MatrixCallback<String> {
override fun onSuccess(data: String) {
Timber.d("## On success : succeed to invite riot-bot")
safeActivity?.finish()
}
override fun onFailure(failure: Throwable) {
Timber.e("## On error : failed to invite riot-bot $failure")
safeActivity?.finish()
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2018 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.webview
import timber.log.Timber
/**
* This class is the default implementation of WebViewEventListener.
* It can be used with delegation pattern
*/
class DefaultWebViewEventListener : WebViewEventListener {
override fun pageWillStart(url: String) {
Timber.v("On page will start: $url")
}
override fun onPageStarted(url: String) {
Timber.d("On page started: $url")
}
override fun onPageFinished(url: String) {
Timber.d("On page finished: $url")
}
override fun onPageError(url: String, errorCode: Int, description: String) {
Timber.e("On received error: $url - errorCode: $errorCode - message: $description")
}
override fun shouldOverrideUrlLoading(url: String): Boolean {
Timber.v("Should override url: $url")
return false
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright 2018 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.webview
import android.content.Context
import android.content.Intent
import android.os.Build
import android.webkit.WebChromeClient
import android.webkit.WebView
import androidx.annotation.CallSuper
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseActivity
import kotlinx.android.synthetic.main.activity_vector_web_view.*
import javax.inject.Inject
/**
* This class is responsible for managing a WebView
* It does also have a loading view and a toolbar
* It relies on the VectorWebViewClient
* This class shouldn't be extended. To add new behaviors, you might create a new WebViewMode and a new WebViewEventListener
*/
class VectorWebViewActivity : VectorBaseActivity() {
override fun getLayoutRes() = R.layout.activity_vector_web_view
@Inject lateinit var session: Session
@CallSuper
override fun injectWith(injector: ScreenComponent) {
session = injector.session()
}
override fun initUiAndData() {
configureToolbar(webview_toolbar)
waitingView = findViewById(R.id.simple_webview_loader)
simple_webview.settings.apply {
// Enable Javascript
javaScriptEnabled = true
// Use WideViewport and Zoom out if there is no viewport defined
useWideViewPort = true
loadWithOverviewMode = true
// Enable pinch to zoom without the zoom buttons
builtInZoomControls = true
// Allow use of Local Storage
domStorageEnabled = true
allowFileAccessFromFileURLs = true
allowUniversalAccessFromFileURLs = true
displayZoomControls = false
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val cookieManager = android.webkit.CookieManager.getInstance()
cookieManager.setAcceptThirdPartyCookies(simple_webview, true)
}
val url = intent.extras.getString(EXTRA_URL)
val title = intent.extras.getString(EXTRA_TITLE, USE_TITLE_FROM_WEB_PAGE)
if (title != USE_TITLE_FROM_WEB_PAGE) {
setTitle(title)
}
val webViewMode = intent.extras.getSerializable(EXTRA_MODE) as WebViewMode
val eventListener = webViewMode.eventListener(this, session)
simple_webview.webViewClient = VectorWebViewClient(eventListener)
simple_webview.webChromeClient = object : WebChromeClient() {
override fun onReceivedTitle(view: WebView, title: String) {
if (title == USE_TITLE_FROM_WEB_PAGE) {
setTitle(title)
}
}
}
simple_webview.loadUrl(url)
}
/* ==========================================================================================
* UI event
* ========================================================================================== */
override fun onBackPressed() {
if (simple_webview.canGoBack()) {
simple_webview.goBack()
} else {
super.onBackPressed()
}
}
/* ==========================================================================================
* Companion
* ========================================================================================== */
companion object {
private const val EXTRA_URL = "EXTRA_URL"
private const val EXTRA_TITLE = "EXTRA_TITLE"
private const val EXTRA_MODE = "EXTRA_MODE"
private const val USE_TITLE_FROM_WEB_PAGE = ""
fun getIntent(context: Context,
url: String,
title: String = USE_TITLE_FROM_WEB_PAGE,
mode: WebViewMode = WebViewMode.DEFAULT): Intent {
return Intent(context, VectorWebViewActivity::class.java)
.apply {
putExtra(EXTRA_URL, url)
putExtra(EXTRA_TITLE, title)
putExtra(EXTRA_MODE, mode)
}
}
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright 2018 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.webview
import android.annotation.TargetApi
import android.graphics.Bitmap
import android.os.Build
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
/**
* This class inherits from WebViewClient. It has to be used with a WebView.
* It's responsible for dispatching events to the WebViewEventListener
*/
class VectorWebViewClient(private val eventListener: WebViewEventListener) : WebViewClient() {
private var mInError: Boolean = false
@TargetApi(Build.VERSION_CODES.N)
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
return shouldOverrideUrl(request.url.toString())
}
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
return shouldOverrideUrl(url)
}
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
mInError = false
eventListener.onPageStarted(url)
}
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
if (!mInError) {
eventListener.onPageFinished(url)
}
}
override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) {
super.onReceivedError(view, errorCode, description, failingUrl)
if (!mInError) {
mInError = true
eventListener.onPageError(failingUrl, errorCode, description)
}
}
@TargetApi(Build.VERSION_CODES.N)
override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceError) {
super.onReceivedError(view, request, error)
if (!mInError) {
mInError = true
eventListener.onPageError(request.url.toString(), error.errorCode, error.description.toString())
}
}
private fun shouldOverrideUrl(url: String): Boolean {
mInError = false
val shouldOverrideUrlLoading = eventListener.shouldOverrideUrlLoading(url)
if (!shouldOverrideUrlLoading) {
eventListener.pageWillStart(url)
}
return shouldOverrideUrlLoading
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2018 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.webview
interface WebViewEventListener {
/**
* Triggered when a webview page is about to be started.
*
* @param url The url about to be rendered.
*/
fun pageWillStart(url: String)
/**
* Triggered when a loading webview page has started.
*
* @param url The rendering url.
*/
fun onPageStarted(url: String)
/**
* Triggered when a loading webview page has finished loading but has not been rendered yet.
*
* @param url The finished url.
*/
fun onPageFinished(url: String)
/**
* Triggered when an error occurred while loading a page.
*
* @param url The url that failed.
* @param errorCode The error code.
* @param description The error description.
*/
fun onPageError(url: String, errorCode: Int, description: String)
/**
* Triggered when a webview load an url
*
* @param url The url about to be rendered.
* @return true if the method needs to manage some custom handling
*/
fun shouldOverrideUrlLoading(url: String): Boolean
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2018 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.webview
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.core.platform.VectorBaseActivity
interface WebViewEventListenerFactory {
/**
* @return an instance of WebViewEventListener
*/
fun eventListener(activity: VectorBaseActivity, session: Session): WebViewEventListener
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2018 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.webview
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.core.platform.VectorBaseActivity
/**
* This enum indicates the WebView mode. It's responsible for creating a WebViewEventListener
*/
enum class WebViewMode : WebViewEventListenerFactory {
DEFAULT {
override fun eventListener(activity: VectorBaseActivity, session: Session): WebViewEventListener {
return DefaultWebViewEventListener()
}
},
CONSENT {
override fun eventListener(activity: VectorBaseActivity, session: Session): WebViewEventListener {
return ConsentWebViewEventListener(activity, session, DefaultWebViewEventListener())
}
};
}

View File

@ -0,0 +1,36 @@
<?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="match_parent"
tools:context="im.vector.riotx.features.webview.VectorWebViewActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/webview_toolbar"
style="@style/VectorToolbarStyle"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
app:layout_constraintTop_toTopOf="parent"
tools:title="Title of the web page" />
<WebView
android:id="@+id/simple_webview"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/webview_toolbar" />
<ProgressBar
android:id="@+id/simple_webview_loader"
style="@style/Widget.AppCompat.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -5,4 +5,7 @@
<string name="labs_allow_extended_logging">Enable verbose logs.</string>
<string name="labs_allow_extended_logging_summary">Verbose logs will help developers by providing more logs when you send a RageShake. Even when enabled, the application does not log message contents or any other private data.</string>
<string name="error_terms_not_accepted">Please retry once you have accepted the terms and conditions of your homeserver.</string>
</resources>