Răsfoiți Sursa

Merge pull request #13414 from nextcloud/bugfix/pass-code-activity-fix-keyboard-appereance

BugFix - Resolve Keyboard Not Showing After Lock and Re-enable Password Entry After Delay
Alper Öztürk 8 luni în urmă
părinte
comite
faa3ec6d99

+ 59 - 53
app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.kt

@@ -19,6 +19,7 @@ import android.view.WindowManager
 import android.view.inputmethod.InputMethodManager
 import androidx.annotation.VisibleForTesting
 import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
 import com.google.android.material.snackbar.Snackbar
 import com.nextcloud.android.common.ui.theme.utils.ColorRole
 import com.nextcloud.client.di.Injectable
@@ -28,7 +29,11 @@ import com.owncloud.android.authentication.PassCodeManager
 import com.owncloud.android.databinding.PasscodelockBinding
 import com.owncloud.android.lib.common.utils.Log_OC
 import com.owncloud.android.ui.components.PassCodeEditText
+import com.owncloud.android.ui.components.showKeyboard
 import com.owncloud.android.utils.theme.ViewThemeUtils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 import javax.inject.Inject
 
 @Suppress("TooManyFunctions", "MagicNumber")
@@ -51,17 +56,14 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
         const val PREFERENCE_PASSCODE_D4 = "PrefPinCode4"
     }
 
-    @JvmField
     @Inject
-    var preferences: AppPreferences? = null
+    lateinit var preferences: AppPreferences
 
-    @JvmField
     @Inject
-    var passCodeManager: PassCodeManager? = null
+    lateinit var passCodeManager: PassCodeManager
 
-    @JvmField
     @Inject
-    var viewThemeUtils: ViewThemeUtils? = null
+    lateinit var viewThemeUtils: ViewThemeUtils
 
     @get:VisibleForTesting
     lateinit var binding: PasscodelockBinding
@@ -85,8 +87,8 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
     }
 
     private fun applyTint() {
-        viewThemeUtils?.platform?.colorViewBackground(binding.cardViewContent, ColorRole.SURFACE_VARIANT)
-        viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(binding.cancel)
+        viewThemeUtils.platform.colorViewBackground(binding.cardViewContent, ColorRole.SURFACE_VARIANT)
+        viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(binding.cancel)
     }
 
     private fun setupPasscodeEditTexts() {
@@ -96,10 +98,16 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
         passCodeEditTexts[3] = binding.txt3
 
         passCodeEditTexts.forEach {
-            it?.let { viewThemeUtils?.platform?.colorEditText(it) }
+            it?.let { editText ->
+                viewThemeUtils.platform.colorEditText(editText)
+            }
         }
 
         passCodeEditTexts[0]?.requestFocus()
+
+        binding.cardViewContent.setOnClickListener {
+            binding.txt0.showKeyboard()
+        }
     }
 
     private fun setSoftInputMode() {
@@ -140,14 +148,17 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
     }
 
     private fun setCancelButtonEnabled(enabled: Boolean) {
-        binding.cancel.visibility = if (enabled) {
-            View.VISIBLE
-        } else {
-            View.INVISIBLE
-        }
-        binding.cancel.setOnClickListener {
-            if (enabled) {
-                finish()
+        binding.cancel.run {
+            visibility = if (enabled) {
+                View.VISIBLE
+            } else {
+                View.INVISIBLE
+            }
+
+            setOnClickListener {
+                if (enabled) {
+                    finish()
+                }
             }
         }
     }
@@ -193,6 +204,7 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
             } else if (!changed) {
                 changed = true
             }
+
             false
         }
     }
@@ -207,24 +219,24 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
     private fun processFullPassCode() {
         if (ACTION_CHECK == intent.action) {
             if (checkPassCode()) {
-                preferences?.resetPinWrongAttempts()
+                preferences.resetPinWrongAttempts()
 
                 // / pass code accepted in request, user is allowed to access the app
-                passCodeManager?.updateLockTimestamp()
-                hideSoftKeyboard()
+                passCodeManager.updateLockTimestamp()
+                hideKeyboard()
                 finish()
             } else {
-                preferences?.increasePinWrongAttempts()
+                preferences.increasePinWrongAttempts()
                 showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE)
             }
         } else if (ACTION_CHECK_WITH_RESULT == intent.action) {
             if (checkPassCode()) {
-                passCodeManager?.updateLockTimestamp()
+                passCodeManager.updateLockTimestamp()
 
                 val resultIntent = Intent()
                 resultIntent.putExtra(KEY_CHECK_RESULT, true)
                 setResult(RESULT_OK, resultIntent)
-                hideSoftKeyboard()
+                hideKeyboard()
                 finish()
             } else {
                 showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE)
@@ -246,7 +258,7 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
         }
     }
 
-    private fun hideSoftKeyboard() {
+    private fun hideKeyboard() {
         currentFocus?.let {
             val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
             inputMethodManager.hideSoftInputFromWindow(
@@ -275,7 +287,7 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
     }
 
     private fun checkPassCode(): Boolean {
-        val savedPassCodeDigits = preferences?.passCode
+        val savedPassCodeDigits = preferences.passCode
         return passCodeDigits.zip(savedPassCodeDigits.orEmpty()) { input, saved ->
             input == saved
         }.all { it }
@@ -320,14 +332,14 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
             passCodeDigits[0] + passCodeDigits[1] + passCodeDigits[2] + passCodeDigits[3]
         )
         setResult(RESULT_OK, resultIntent)
-        passCodeManager?.updateLockTimestamp()
+        passCodeManager.updateLockTimestamp()
         finish()
     }
 
     private fun showDelay() {
-        val delay = preferences?.pinBruteForceDelay() ?: 0
+        val delayValue = preferences.pinBruteForceDelay()
 
-        if (delay <= 0) {
+        if (delayValue <= 0) {
             return
         }
 
@@ -338,29 +350,28 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
         binding.txt2.isEnabled = false
         binding.txt3.isEnabled = false
 
-        Thread(object : Runnable {
-            override fun run() {
-                try {
-                    Thread.sleep(delay * 1000L)
-
-                    runOnUiThread {
-                        binding.explanation.visibility = View.INVISIBLE
-                        binding.txt0.isEnabled = true
-                        binding.txt1.isEnabled = true
-                        binding.txt2.isEnabled = true
-                        binding.txt3.isEnabled = true
-                    }
-                } catch (e: InterruptedException) {
-                    Log_OC.e(this, "Could not delay password input prompt")
-                }
+        lifecycleScope.launch(Dispatchers.IO) {
+            delay(delayValue * 1000L)
+
+            launch(Dispatchers.Main) {
+                binding.explanation.visibility = View.INVISIBLE
+                binding.txt0.isEnabled = true
+                binding.txt1.isEnabled = true
+                binding.txt2.isEnabled = true
+                binding.txt3.isEnabled = true
+
+                binding.txt0.requestFocus()
+                binding.txt0.showKeyboard()
             }
-        }).start()
+        }
     }
 
     public override fun onSaveInstanceState(outState: Bundle) {
         super.onSaveInstanceState(outState)
-        outState.putBoolean(KEY_CONFIRMING_PASSCODE, confirmingPassCode)
-        outState.putStringArray(KEY_PASSCODE_DIGITS, passCodeDigits)
+        outState.run {
+            putBoolean(KEY_CONFIRMING_PASSCODE, confirmingPassCode)
+            putStringArray(KEY_PASSCODE_DIGITS, passCodeDigits)
+        }
     }
 
     private inner class PassCodeDigitTextWatcher(index: Int, lastOne: Boolean) : TextWatcher {
@@ -408,12 +419,7 @@ class PassCodeActivity : AppCompatActivity(), Injectable {
             }
         }
 
-        @Suppress("EmptyFunctionBlock")
-        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-        }
-
-        @Suppress("EmptyFunctionBlock")
-        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-        }
+        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
+        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) = Unit
     }
 }

+ 10 - 1
app/src/main/java/com/owncloud/android/ui/components/PassCodeEditText.kt

@@ -13,6 +13,7 @@ import android.util.AttributeSet
 import android.view.KeyEvent
 import android.view.MotionEvent
 import android.view.View
+import android.view.inputmethod.InputMethodManager
 import androidx.appcompat.widget.AppCompatEditText
 
 @SuppressLint("ClickableViewAccessibility")
@@ -25,7 +26,10 @@ class PassCodeEditText(context: Context, attrs: AttributeSet?) : AppCompatEditTe
     private fun disableFocusChangeViaTap() {
         setSelectAllOnFocus(false)
         setTextIsSelectable(false)
-        setOnTouchListener { _: View?, _: MotionEvent? -> true }
+        setOnTouchListener { _: View?, _: MotionEvent? ->
+            showKeyboard()
+            true
+        }
     }
 
     override fun onKeyPreIme(keyCode: Int, event: KeyEvent): Boolean {
@@ -37,3 +41,8 @@ class PassCodeEditText(context: Context, attrs: AttributeSet?) : AppCompatEditTe
         return super.dispatchKeyEvent(event)
     }
 }
+
+fun PassCodeEditText.showKeyboard() {
+    val imm = this.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+    imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
+}