show hint when blocked cause of obscured while entering the license

Need to manually handle this in case of dialogs as otherwise the onFilterTouchEventForSecurity method of the ViewGroup isn't called when filterTouchesWhenObscured is set to true in the BaseDialog and in contrast to if set in an Activity
This commit is contained in:
Julian Raufelder 2021-06-02 15:20:18 +02:00
parent 9a65f62ae5
commit 68bb87c04b
No known key found for this signature in database
GPG Key ID: 17EE71F6634E381D
7 changed files with 126 additions and 53 deletions

@ -6,13 +6,14 @@ import org.cryptomator.domain.usecases.LicenseCheck
import org.cryptomator.domain.usecases.NoOpResultHandler
import org.cryptomator.presentation.exception.ExceptionHandlers
import org.cryptomator.presentation.ui.activity.view.UpdateLicenseView
import org.cryptomator.presentation.ui.dialog.AppIsObscuredInfoDialog
import org.cryptomator.util.SharedPreferencesHandler
import javax.inject.Inject
import timber.log.Timber
class LicenseCheckPresenter @Inject internal constructor(
exceptionHandlers: ExceptionHandlers, //
private val doLicenseCheckUsecase: DoLicenseCheckUseCase, //
private val doLicenseCheckUseCase: DoLicenseCheckUseCase, //
private val sharedPreferencesHandler: SharedPreferencesHandler
) : Presenter<UpdateLicenseView>(exceptionHandlers) {
@ -20,18 +21,22 @@ class LicenseCheckPresenter @Inject internal constructor(
data?.let {
val license = it.fragment ?: it.lastPathSegment ?: ""
view?.showOrUpdateLicenseDialog(license)
doLicenseCheckUsecase
doLicenseCheckUseCase
.withLicense(license)
.run(CheckLicenseStatusSubscriber())
}
}
fun validateDialogAware(license: String?) {
doLicenseCheckUsecase
doLicenseCheckUseCase
.withLicense(license)
.run(CheckLicenseStatusSubscriber())
}
fun onFilteredTouchEventForSecurity() {
view?.showDialog(AppIsObscuredInfoDialog.newInstance())
}
private inner class CheckLicenseStatusSubscriber : NoOpResultHandler<LicenseCheck>() {
override fun onSuccess(licenseCheck: LicenseCheck) {
@ -49,6 +54,6 @@ class LicenseCheckPresenter @Inject internal constructor(
}
init {
unsubscribeOnDestroy(doLicenseCheckUsecase)
unsubscribeOnDestroy(doLicenseCheckUseCase)
}
}

@ -10,11 +10,13 @@ import org.cryptomator.presentation.presenter.LicenseCheckPresenter
import org.cryptomator.presentation.ui.activity.view.UpdateLicenseView
import org.cryptomator.presentation.ui.dialog.LicenseConfirmationDialog
import org.cryptomator.presentation.ui.dialog.UpdateLicenseDialog
import org.cryptomator.presentation.ui.layout.ObscuredAwareCoordinatorLayout
import javax.inject.Inject
import kotlin.system.exitProcess
import kotlinx.android.synthetic.main.activity_layout_obscure_aware.activityRootView
import kotlinx.android.synthetic.main.toolbar_layout.toolbar
@Activity
@Activity(layout = R.layout.activity_layout_obscure_aware)
class LicenseCheckActivity : BaseActivity(), UpdateLicenseDialog.Callback, LicenseConfirmationDialog.Callback, UpdateLicenseView {
@Inject
@ -23,11 +25,19 @@ class LicenseCheckActivity : BaseActivity(), UpdateLicenseDialog.Callback, Licen
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupToolbar()
activityRootView.setOnFilteredTouchEventForSecurityListener(object : ObscuredAwareCoordinatorLayout.Listener {
override fun onFilteredTouchEventForSecurity() {
licenseCheckPresenter.onFilteredTouchEventForSecurity()
}
})
validate(intent)
}
override fun setupView() {
setupToolbar()
}
override fun checkLicenseClicked(license: String?) {
licenseCheckPresenter.validateDialogAware(license)
}
@ -51,6 +61,11 @@ class LicenseCheckActivity : BaseActivity(), UpdateLicenseDialog.Callback, Licen
exitProcess(0)
}
override fun appObscuredClosingEnterLicenseDialog() {
closeDialog()
licenseCheckPresenter.onFilteredTouchEventForSecurity()
}
private fun setupToolbar() {
toolbar.title = getString(R.string.app_name).uppercase()
setSupportActionBar(toolbar)

@ -82,9 +82,7 @@ abstract class BaseDialog<Callback> : DialogFragment() {
get() = requireContext().resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
fun onErrorResponse(view: View?) {
if (view != null) {
view.isFocusableInTouchMode = true
}
view?.let { it.isFocusableInTouchMode = true }
allowClosingDialog(true)
enableButtons(true)
}

@ -16,10 +16,10 @@ class LicenseConfirmationDialog : BaseDialog<LicenseConfirmationDialog.Callback>
}
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
builder //
return builder //
.setTitle(getString(R.string.dialog_license_confirmation_title)) //
.setNeutralButton(getText(R.string.dialog_license_confirmation_ok_btn)) { _: DialogInterface, _: Int -> callback?.licenseConfirmationClicked() }
return builder.create()
.setNeutralButton(getText(R.string.dialog_license_confirmation_ok_btn)) { _: DialogInterface, _: Int -> callback?.licenseConfirmationClicked() } //
.create()
}
public override fun setupView() {

@ -7,6 +7,9 @@ import android.widget.Button
import androidx.appcompat.app.AlertDialog
import org.cryptomator.generator.Dialog
import org.cryptomator.presentation.R
import org.cryptomator.presentation.ui.layout.ObscuredAwareDialogCoordinatorLayout
import org.cryptomator.util.SharedPreferencesHandler
import kotlinx.android.synthetic.main.dialog_enter_license.dssialogRootView
import kotlinx.android.synthetic.main.dialog_enter_license.et_license
@Dialog(R.layout.dialog_enter_license)
@ -19,6 +22,7 @@ class UpdateLicenseDialog : BaseProgressErrorDialog<UpdateLicenseDialog.Callback
fun checkLicenseClicked(license: String?)
fun onCheckLicenseCanceled()
fun appObscuredClosingEnterLicenseDialog()
}
override fun onStart() {
@ -35,6 +39,15 @@ class UpdateLicenseDialog : BaseProgressErrorDialog<UpdateLicenseDialog.Callback
et_license.nextFocusForwardId = button.id
}
}
/* need to manually handle this in case of dialogs as otherwise the onFilterTouchEventForSecurity method of the ViewGroup
isn't called when filterTouchesWhenObscured is set to true in the BaseDialog and in contrast to if set in an Activity */
dialog?.window?.decorView?.filterTouchesWhenObscured = false
dssialogRootView.setOnFilteredTouchEventForSecurityListener(object : ObscuredAwareDialogCoordinatorLayout.Listener {
override fun onFilteredTouchEventForSecurity() {
callback?.appObscuredClosingEnterLicenseDialog()
}
}, SharedPreferencesHandler(requireContext()).disableAppWhenObscured())
}
public override fun setupDialog(builder: AlertDialog.Builder): android.app.Dialog {
@ -47,9 +60,7 @@ class UpdateLicenseDialog : BaseProgressErrorDialog<UpdateLicenseDialog.Callback
public override fun setupView() {
val license = requireArguments().getSerializable(LICENSE_ARG) as String?
if (license != null) {
et_license.setText(license)
}
license?.let { et_license.setText(it) }
et_license.requestFocus()
registerOnEditorDoneActionAndPerformButtonClick(et_license) { checkLicenseButton }
}

@ -0,0 +1,38 @@
package org.cryptomator.presentation.ui.layout
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import androidx.coordinatorlayout.widget.CoordinatorLayout
class ObscuredAwareDialogCoordinatorLayout : CoordinatorLayout {
private var listener: Listener? = null
private var active: Boolean = true
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
fun setOnFilteredTouchEventForSecurityListener(listener: Listener, active: Boolean) {
this.listener = listener
this.active = active
}
override fun onFilterTouchEventForSecurity(event: MotionEvent): Boolean {
return if (active and ((event.flags and MotionEvent.FLAG_WINDOW_IS_OBSCURED) == MotionEvent.FLAG_WINDOW_IS_OBSCURED)) {
listener?.onFilteredTouchEventForSecurity()
false
} else {
true
}
}
interface Listener {
fun onFilteredTouchEventForSecurity()
}
}

@ -1,51 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<org.cryptomator.presentation.ui.layout.ObscuredAwareDialogCoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dssialogRootView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_vertical_margin">
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_message"
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:text="@string/dialog_enter_license_content" />
android:layout_height="match_parent"
android:padding="@dimen/activity_vertical_margin">
<LinearLayout
android:id="@+id/ll_folder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_message"
android:orientation="horizontal">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_license_key" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_license"
<TextView
android:id="@+id/tv_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionDone|flagNoPersonalizedLearning"
android:inputType="text" />
</LinearLayout>
android:layout_marginBottom="5dp"
android:text="@string/dialog_enter_license_content" />
<include
layout="@layout/view_dialog_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/til_password" />
<LinearLayout
android:id="@+id/ll_license"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_message"
android:orientation="horizontal">
<include
layout="@layout/view_dialog_error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/ll_folder" />
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_license_key" />
</RelativeLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_license"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionDone|flagNoPersonalizedLearning"
android:inputType="text" />
</LinearLayout>
<include
layout="@layout/view_dialog_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/til_password" />
<include
layout="@layout/view_dialog_error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/ll_license" />
</RelativeLayout>
</androidx.core.widget.NestedScrollView>
</org.cryptomator.presentation.ui.layout.ObscuredAwareDialogCoordinatorLayout>