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: Features:
- - Handle M_CONSENT_NOT_GIVEN error (#64)
Improvements: Improvements:
- Reduce default release build log level, and lab option to enable more logs. - 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.jakewharton.timber:timber:4.7.1'
implementation 'com.facebook.stetho:stetho-okhttp3:1.5.0' 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' debugImplementation 'com.airbnb.okreplay:okreplay:1.4.0'
releaseImplementation 'com.airbnb.okreplay:noop:1.4.0' releaseImplementation 'com.airbnb.okreplay:noop:1.4.0'
androidTestImplementation 'com.airbnb.okreplay:espresso: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.JsonDataException
import com.squareup.moshi.Moshi 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.Failure
import im.vector.matrix.android.api.failure.MatrixError import im.vector.matrix.android.api.failure.MatrixError
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.di.MoshiProvider
import okhttp3.ResponseBody import okhttp3.ResponseBody
import org.greenrobot.eventbus.EventBus
import retrofit2.Call import retrofit2.Call
import timber.log.Timber import timber.log.Timber
import java.io.IOException import java.io.IOException
@ -65,6 +67,11 @@ internal class Request<DATA> {
val matrixError = matrixErrorAdapter.fromJson(errorBodyStr) val matrixError = matrixErrorAdapter.fromJson(errorBodyStr)
if (matrixError != null) { 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) return Failure.ServerError(matrixError, httpCode)
} }
} catch (ex: JsonDataException) { } catch (ex: JsonDataException) {

View File

@ -280,6 +280,9 @@ dependencies {
implementation "ru.noties.markwon:html:$markwon_version" implementation "ru.noties.markwon:html:$markwon_version"
implementation 'me.saket:better-link-movement-method:2.2.0' implementation 'me.saket:better-link-movement-method:2.2.0'
// Bus
implementation 'org.greenrobot:eventbus:3.1.1'
// Passphrase strength helper // Passphrase strength helper
implementation 'com.nulab-inc:zxcvbn:1.2.5' 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.home.room.detail.RoomDetailActivity" />
<activity android:name=".features.debug.DebugMenuActivity" /> <activity android:name=".features.debug.DebugMenuActivity" />
<activity android:name=".features.home.createdirect.CreateDirectRoomActivity" /> <activity android:name=".features.home.createdirect.CreateDirectRoomActivity" />
<activity android:name=".features.webview.VectorWebViewActivity" />
<!-- Services --> <!-- Services -->

View File

@ -349,6 +349,11 @@ SOFTWARE.
<br/> <br/>
Copyright 2018 The diff-match-patch Authors. https://github.com/google/diff-match-patch Copyright 2018 The diff-match-patch Authors. https://github.com/google/diff-match-patch
</li> </li>
<li>
<b>EventBus</b>
<br/>
Copyright (C) 2012-2017 Markus Junginger, greenrobot (http://greenrobot.org)
</li>
</ul> </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 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() { private fun unlock() {
isDialogDisplayed = false isDialogDisplayed = false

View File

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

View File

@ -36,11 +36,14 @@ import butterknife.Unbinder
import com.airbnb.mvrx.BaseMvRxActivity import com.airbnb.mvrx.BaseMvRxActivity
import com.bumptech.glide.util.Util import com.bumptech.glide.util.Util
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import im.vector.matrix.android.api.failure.ConsentNotGivenError
import im.vector.riotx.BuildConfig import im.vector.riotx.BuildConfig
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.di.* import im.vector.riotx.core.di.*
import im.vector.riotx.core.dialogs.DialogLocker
import im.vector.riotx.core.utils.toast import im.vector.riotx.core.utils.toast
import im.vector.riotx.features.configuration.VectorConfiguration 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.navigation.Navigator
import im.vector.riotx.features.rageshake.BugReportActivity import im.vector.riotx.features.rageshake.BugReportActivity
import im.vector.riotx.features.rageshake.BugReporter 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 im.vector.riotx.receivers.DebugReceiver
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable 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 timber.log.Timber
import kotlin.system.measureTimeMillis 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 * Temporary method
* ========================================================================================== */ * ========================================================================================== */
@ -402,5 +433,4 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasScreenInjector {
toast(getString(R.string.not_implemented)) 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">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="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> </resources>