|
@@ -21,319 +21,281 @@
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
*
|
|
|
*/
|
|
|
-package com.owncloud.android.ui.activity;
|
|
|
-
|
|
|
-import android.annotation.SuppressLint;
|
|
|
-import android.content.Intent;
|
|
|
-import android.os.Bundle;
|
|
|
-import android.text.Editable;
|
|
|
-import android.text.TextUtils;
|
|
|
-import android.text.TextWatcher;
|
|
|
-import android.view.KeyEvent;
|
|
|
-import android.view.View;
|
|
|
-import android.view.Window;
|
|
|
-import android.view.inputmethod.InputMethodManager;
|
|
|
-import android.widget.EditText;
|
|
|
-
|
|
|
-import com.google.android.material.snackbar.Snackbar;
|
|
|
-import com.nextcloud.client.di.Injectable;
|
|
|
-import com.nextcloud.client.preferences.AppPreferences;
|
|
|
-import com.owncloud.android.R;
|
|
|
-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.utils.theme.ViewThemeUtils;
|
|
|
-
|
|
|
-import java.util.Arrays;
|
|
|
-
|
|
|
-import javax.inject.Inject;
|
|
|
-
|
|
|
-import androidx.annotation.NonNull;
|
|
|
-import androidx.annotation.VisibleForTesting;
|
|
|
-import androidx.appcompat.app.AppCompatActivity;
|
|
|
-
|
|
|
-public class PassCodeActivity extends AppCompatActivity implements Injectable {
|
|
|
-
|
|
|
- private static final String TAG = PassCodeActivity.class.getSimpleName();
|
|
|
- private static final String KEY_PASSCODE_DIGITS = "PASSCODE_DIGITS";
|
|
|
- private static final String KEY_CONFIRMING_PASSCODE = "CONFIRMING_PASSCODE";
|
|
|
-
|
|
|
- public final static String ACTION_REQUEST_WITH_RESULT = "ACTION_REQUEST_WITH_RESULT";
|
|
|
- public final static String ACTION_CHECK_WITH_RESULT = "ACTION_CHECK_WITH_RESULT";
|
|
|
- public final static String ACTION_CHECK = "ACTION_CHECK";
|
|
|
- public final static String KEY_PASSCODE = "KEY_PASSCODE";
|
|
|
- public final static String KEY_CHECK_RESULT = "KEY_CHECK_RESULT";
|
|
|
-
|
|
|
- public final static String PREFERENCE_PASSCODE_D = "PrefPinCode";
|
|
|
- public final static String PREFERENCE_PASSCODE_D1 = "PrefPinCode1";
|
|
|
- public final static String PREFERENCE_PASSCODE_D2 = "PrefPinCode2";
|
|
|
- public final static String PREFERENCE_PASSCODE_D3 = "PrefPinCode3";
|
|
|
- public final static String PREFERENCE_PASSCODE_D4 = "PrefPinCode4";
|
|
|
-
|
|
|
- @Inject AppPreferences preferences;
|
|
|
- @Inject PassCodeManager passCodeManager;
|
|
|
- @Inject ViewThemeUtils viewThemeUtils;
|
|
|
- private PasscodelockBinding binding;
|
|
|
- private final PassCodeEditText[] passCodeEditTexts = new PassCodeEditText[4];
|
|
|
- private String[] passCodeDigits = {"", "", "", ""};
|
|
|
- private boolean confirmingPassCode;
|
|
|
- private boolean changed = true; // to control that only one blocks jump
|
|
|
+package com.owncloud.android.ui.activity
|
|
|
+
|
|
|
+import android.content.Intent
|
|
|
+import android.os.Bundle
|
|
|
+import android.text.Editable
|
|
|
+import android.text.TextUtils
|
|
|
+import android.text.TextWatcher
|
|
|
+import android.view.KeyEvent
|
|
|
+import android.view.View
|
|
|
+import android.view.WindowManager
|
|
|
+import android.view.inputmethod.InputMethodManager
|
|
|
+import androidx.annotation.VisibleForTesting
|
|
|
+import androidx.appcompat.app.AppCompatActivity
|
|
|
+import com.google.android.material.snackbar.Snackbar
|
|
|
+import com.nextcloud.client.di.Injectable
|
|
|
+import com.nextcloud.client.preferences.AppPreferences
|
|
|
+import com.owncloud.android.R
|
|
|
+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.utils.theme.ViewThemeUtils
|
|
|
+import java.util.Arrays
|
|
|
+import javax.inject.Inject
|
|
|
+
|
|
|
+class PassCodeActivity : AppCompatActivity(), Injectable {
|
|
|
+ @JvmField
|
|
|
+ @Inject
|
|
|
+ var preferences: AppPreferences? = null
|
|
|
+
|
|
|
+ @JvmField
|
|
|
+ @Inject
|
|
|
+ var passCodeManager: PassCodeManager? = null
|
|
|
+
|
|
|
+ @JvmField
|
|
|
+ @Inject
|
|
|
+ var viewThemeUtils: ViewThemeUtils? = null
|
|
|
+
|
|
|
+ @get:VisibleForTesting
|
|
|
+ lateinit var binding: PasscodelockBinding
|
|
|
+ private set
|
|
|
+
|
|
|
+ private val passCodeEditTexts = arrayOfNulls<PassCodeEditText>(4)
|
|
|
+ private var passCodeDigits: Array<String?>? = arrayOf("", "", "", "")
|
|
|
+ private var confirmingPassCode = false
|
|
|
+ private var changed = true // to control that only one blocks jump
|
|
|
|
|
|
/**
|
|
|
* Initializes the activity.
|
|
|
- * <p>
|
|
|
- * An intent with a valid ACTION is expected; if none is found, an {@link IllegalArgumentException} will be thrown.
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * An intent with a valid ACTION is expected; if none is found, an [IllegalArgumentException] will be thrown.
|
|
|
*
|
|
|
* @param savedInstanceState Previously saved state - irrelevant in this case
|
|
|
*/
|
|
|
- protected void onCreate(Bundle savedInstanceState) {
|
|
|
- super.onCreate(savedInstanceState);
|
|
|
- binding = PasscodelockBinding.inflate(getLayoutInflater());
|
|
|
- setContentView(binding.getRoot());
|
|
|
-
|
|
|
- viewThemeUtils.platform.colorTextButtons(binding.cancel);
|
|
|
-
|
|
|
- passCodeEditTexts[0] = binding.txt0;
|
|
|
- passCodeEditTexts[1] = binding.txt1;
|
|
|
- passCodeEditTexts[2] = binding.txt2;
|
|
|
- passCodeEditTexts[3] = binding.txt3;
|
|
|
+ override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
+ super.onCreate(savedInstanceState)
|
|
|
+ binding = PasscodelockBinding.inflate(layoutInflater)
|
|
|
+ setContentView(binding.root)
|
|
|
|
|
|
- for (EditText passCodeEditText : passCodeEditTexts) {
|
|
|
- viewThemeUtils.platform.colorEditText(passCodeEditText);
|
|
|
- }
|
|
|
+ viewThemeUtils?.platform?.colorTextButtons(binding.cancel)
|
|
|
|
|
|
- passCodeEditTexts[0].requestFocus();
|
|
|
+ setupPasscodeEditTexts()
|
|
|
+ setSoftInputMode()
|
|
|
+ setupUI(savedInstanceState)
|
|
|
+ setTextListeners()
|
|
|
+ }
|
|
|
|
|
|
- Window window = getWindow();
|
|
|
- if (window != null) {
|
|
|
- window.setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
|
|
- }
|
|
|
+ private fun setSoftInputMode() {
|
|
|
+ window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
|
|
|
+ }
|
|
|
|
|
|
- if (ACTION_CHECK.equals(getIntent().getAction())) {
|
|
|
+ private fun setupUI(savedInstanceState: Bundle?) {
|
|
|
+ if (ACTION_CHECK == intent.action) {
|
|
|
/// this is a pass code request; the user has to input the right value
|
|
|
- binding.header.setText(R.string.pass_code_enter_pass_code);
|
|
|
- binding.explanation.setVisibility(View.INVISIBLE);
|
|
|
- setCancelButtonEnabled(false); // no option to cancel
|
|
|
-
|
|
|
- showDelay();
|
|
|
-
|
|
|
- } else if (ACTION_REQUEST_WITH_RESULT.equals(getIntent().getAction())) {
|
|
|
+ binding.header.setText(R.string.pass_code_enter_pass_code)
|
|
|
+ binding.explanation.visibility = View.INVISIBLE
|
|
|
+ setCancelButtonEnabled(false) // no option to cancel
|
|
|
+ showDelay()
|
|
|
+ } else if (ACTION_REQUEST_WITH_RESULT == intent.action) {
|
|
|
if (savedInstanceState != null) {
|
|
|
- confirmingPassCode = savedInstanceState.getBoolean(PassCodeActivity.KEY_CONFIRMING_PASSCODE);
|
|
|
- passCodeDigits = savedInstanceState.getStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS);
|
|
|
+ confirmingPassCode = savedInstanceState.getBoolean(KEY_CONFIRMING_PASSCODE)
|
|
|
+ passCodeDigits = savedInstanceState.getStringArray(KEY_PASSCODE_DIGITS)
|
|
|
}
|
|
|
if (confirmingPassCode) {
|
|
|
// the app was in the passcode confirmation
|
|
|
- requestPassCodeConfirmation();
|
|
|
+ requestPassCodeConfirmation()
|
|
|
} else {
|
|
|
// pass code preference has just been activated in SettingsActivity;
|
|
|
// will receive and confirm pass code value
|
|
|
- binding.header.setText(R.string.pass_code_configure_your_pass_code);
|
|
|
-
|
|
|
- binding.explanation.setVisibility(View.VISIBLE);
|
|
|
+ binding.header.setText(R.string.pass_code_configure_your_pass_code)
|
|
|
+ binding.explanation.visibility = View.VISIBLE
|
|
|
}
|
|
|
- setCancelButtonEnabled(true);
|
|
|
-
|
|
|
- } else if (ACTION_CHECK_WITH_RESULT.equals(getIntent().getAction())) {
|
|
|
+ setCancelButtonEnabled(true)
|
|
|
+ } else if (ACTION_CHECK_WITH_RESULT == intent.action) {
|
|
|
// pass code preference has just been disabled in SettingsActivity;
|
|
|
// will confirm user knows pass code, then remove it
|
|
|
- binding.header.setText(R.string.pass_code_remove_your_pass_code);
|
|
|
- binding.explanation.setVisibility(View.INVISIBLE);
|
|
|
- setCancelButtonEnabled(true);
|
|
|
-
|
|
|
+ binding.header.setText(R.string.pass_code_remove_your_pass_code)
|
|
|
+ binding.explanation.visibility = View.INVISIBLE
|
|
|
+ setCancelButtonEnabled(true)
|
|
|
} else {
|
|
|
- throw new IllegalArgumentException("A valid ACTION is needed in the Intent passed to " + TAG);
|
|
|
+ throw IllegalArgumentException("A valid ACTION is needed in the Intent passed to $TAG")
|
|
|
}
|
|
|
-
|
|
|
- setTextListeners();
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Enables or disables the cancel button to allow the user interrupt the ACTION requested to the activity.
|
|
|
- *
|
|
|
- * @param enabled 'True' makes the cancel button available, 'false' hides it.
|
|
|
- */
|
|
|
- protected void setCancelButtonEnabled(boolean enabled) {
|
|
|
- if (enabled) {
|
|
|
- binding.cancel.setVisibility(View.VISIBLE);
|
|
|
- binding.cancel.setOnClickListener(v -> finish());
|
|
|
- } else {
|
|
|
- binding.cancel.setVisibility(View.INVISIBLE);
|
|
|
- binding.cancel.setOnClickListener(null);
|
|
|
+ private fun setupPasscodeEditTexts() {
|
|
|
+ passCodeEditTexts[0] = binding.txt0
|
|
|
+ passCodeEditTexts[1] = binding.txt1
|
|
|
+ passCodeEditTexts[2] = binding.txt2
|
|
|
+ passCodeEditTexts[3] = binding.txt3
|
|
|
+
|
|
|
+ for (passCodeEditText in passCodeEditTexts) {
|
|
|
+ viewThemeUtils?.platform?.colorEditText(passCodeEditText!!)
|
|
|
}
|
|
|
+
|
|
|
+ passCodeEditTexts[0]?.requestFocus()
|
|
|
}
|
|
|
|
|
|
- @VisibleForTesting
|
|
|
- public PasscodelockBinding getBinding() {
|
|
|
- return binding;
|
|
|
+ private fun setCancelButtonEnabled(enabled: Boolean) {
|
|
|
+ binding.cancel.visibility = if (enabled) { View.VISIBLE } else { View.INVISIBLE }
|
|
|
+ binding.cancel.setOnClickListener {
|
|
|
+ if (enabled) {
|
|
|
+ finish()
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Binds the appropriate listeners to the input boxes receiving each digit of the pass code.
|
|
|
- */
|
|
|
- protected void setTextListeners() {
|
|
|
- for (int i = 0; i < passCodeEditTexts.length; i++) {
|
|
|
- final PassCodeEditText editText = passCodeEditTexts[i];
|
|
|
- boolean isLast = (i == 3);
|
|
|
+ private fun setTextListeners() {
|
|
|
+ for (i in passCodeEditTexts.indices) {
|
|
|
+ val editText = passCodeEditTexts[i]
|
|
|
+ val isLast = (i == 3)
|
|
|
+
|
|
|
+ editText?.addTextChangedListener(PassCodeDigitTextWatcher(i, isLast))
|
|
|
|
|
|
- editText.addTextChangedListener(new PassCodeDigitTextWatcher(i, isLast));
|
|
|
if (i > 0) {
|
|
|
- setOnKeyListener(i);
|
|
|
+ setOnKeyListener(i)
|
|
|
}
|
|
|
|
|
|
- int finalIndex = i;
|
|
|
- editText.setOnFocusChangeListener((v, hasFocus) -> onPassCodeEditTextFocusChange(finalIndex));
|
|
|
+ editText?.onFocusChangeListener = View.OnFocusChangeListener { _: View?, _: Boolean ->
|
|
|
+ onPassCodeEditTextFocusChange(i)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void onPassCodeEditTextFocusChange(final int passCodeIndex) {
|
|
|
- for (int i = 0; i < passCodeIndex; i++) {
|
|
|
- if (TextUtils.isEmpty(passCodeEditTexts[i].getText())) {
|
|
|
- passCodeEditTexts[i].requestFocus();
|
|
|
- break;
|
|
|
+ private fun onPassCodeEditTextFocusChange(passCodeIndex: Int) {
|
|
|
+ for (i in 0 until passCodeIndex) {
|
|
|
+ if (TextUtils.isEmpty(passCodeEditTexts[i]?.text)) {
|
|
|
+ passCodeEditTexts[i]?.requestFocus()
|
|
|
+ break
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void setOnKeyListener(final int passCodeIndex) {
|
|
|
- passCodeEditTexts[passCodeIndex].setOnKeyListener((v, keyCode, event) -> {
|
|
|
+ private fun setOnKeyListener(passCodeIndex: Int) {
|
|
|
+ passCodeEditTexts[passCodeIndex]?.setOnKeyListener { _: View?, keyCode: Int, _: KeyEvent? ->
|
|
|
if (keyCode == KeyEvent.KEYCODE_DEL && changed) {
|
|
|
- passCodeEditTexts[passCodeIndex - 1].requestFocus();
|
|
|
+ passCodeEditTexts[passCodeIndex - 1]?.requestFocus()
|
|
|
+
|
|
|
if (!confirmingPassCode) {
|
|
|
- passCodeDigits[passCodeIndex - 1] = "";
|
|
|
+ passCodeDigits?.set(passCodeIndex - 1, "")
|
|
|
}
|
|
|
- passCodeEditTexts[passCodeIndex - 1].setText("");
|
|
|
- changed = false;
|
|
|
|
|
|
+ passCodeEditTexts[passCodeIndex - 1]?.setText("")
|
|
|
+
|
|
|
+ changed = false
|
|
|
} else if (!changed) {
|
|
|
- changed = true;
|
|
|
+ changed = true
|
|
|
}
|
|
|
- return false;
|
|
|
- });
|
|
|
+ false
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Processes the pass code entered by the user just after the last digit was in.
|
|
|
- * <p>
|
|
|
+ *
|
|
|
+ *
|
|
|
* Takes into account the action requested to the activity, the currently saved pass code and the previously typed
|
|
|
* pass code, if any.
|
|
|
*/
|
|
|
- private void processFullPassCode() {
|
|
|
- if (ACTION_CHECK.equals(getIntent().getAction())) {
|
|
|
+ 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();
|
|
|
- finish();
|
|
|
-
|
|
|
+ passCodeManager?.updateLockTimestamp()
|
|
|
+ hideSoftKeyboard()
|
|
|
+ finish()
|
|
|
} else {
|
|
|
- preferences.increasePinWrongAttempts();
|
|
|
-
|
|
|
- showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE);
|
|
|
+ preferences?.increasePinWrongAttempts()
|
|
|
+ showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE)
|
|
|
}
|
|
|
-
|
|
|
- } else if (ACTION_CHECK_WITH_RESULT.equals(getIntent().getAction())) {
|
|
|
+ } else if (ACTION_CHECK_WITH_RESULT == intent.action) {
|
|
|
if (checkPassCode()) {
|
|
|
- passCodeManager.updateLockTimestamp();
|
|
|
- Intent resultIntent = new Intent();
|
|
|
- resultIntent.putExtra(KEY_CHECK_RESULT, true);
|
|
|
- setResult(RESULT_OK, resultIntent);
|
|
|
- hideSoftKeyboard();
|
|
|
- finish();
|
|
|
+ passCodeManager?.updateLockTimestamp()
|
|
|
+
|
|
|
+ val resultIntent = Intent()
|
|
|
+ resultIntent.putExtra(KEY_CHECK_RESULT, true)
|
|
|
+ setResult(RESULT_OK, resultIntent)
|
|
|
+ hideSoftKeyboard()
|
|
|
+ finish()
|
|
|
} else {
|
|
|
- showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE);
|
|
|
+ showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE)
|
|
|
}
|
|
|
-
|
|
|
- } else if (ACTION_REQUEST_WITH_RESULT.equals(getIntent().getAction())) {
|
|
|
+ } else if (ACTION_REQUEST_WITH_RESULT == intent.action) {
|
|
|
/// enabling pass code
|
|
|
if (!confirmingPassCode) {
|
|
|
- requestPassCodeConfirmation();
|
|
|
-
|
|
|
+ requestPassCodeConfirmation()
|
|
|
} else if (confirmPassCode()) {
|
|
|
/// confirmed: user typed the same pass code twice
|
|
|
- savePassCodeAndExit();
|
|
|
-
|
|
|
+ savePassCodeAndExit()
|
|
|
} else {
|
|
|
- showErrorAndRestart(
|
|
|
- R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE
|
|
|
- );
|
|
|
+ showErrorAndRestart(R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void hideSoftKeyboard() {
|
|
|
- View focusedView = getCurrentFocus();
|
|
|
+ private fun hideSoftKeyboard() {
|
|
|
+ val focusedView = currentFocus
|
|
|
if (focusedView != null) {
|
|
|
- InputMethodManager inputMethodManager =
|
|
|
- (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
|
|
+ val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
|
|
inputMethodManager.hideSoftInputFromWindow(
|
|
|
- focusedView.getWindowToken(),
|
|
|
- 0);
|
|
|
+ focusedView.windowToken,
|
|
|
+ 0
|
|
|
+ )
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void showErrorAndRestart(int errorMessage, int headerMessage, int explanationVisibility) {
|
|
|
- Arrays.fill(passCodeDigits, null);
|
|
|
- Snackbar.make(findViewById(android.R.id.content), getString(errorMessage), Snackbar.LENGTH_LONG).show();
|
|
|
- binding.header.setText(headerMessage); // TODO check if really needed
|
|
|
- binding.explanation.setVisibility(explanationVisibility); // TODO check if really needed
|
|
|
- clearBoxes();
|
|
|
+ private fun showErrorAndRestart(errorMessage: Int, headerMessage: Int, explanationVisibility: Int) {
|
|
|
+ passCodeDigits?.let { Arrays.fill(it, null) }
|
|
|
|
|
|
- showDelay();
|
|
|
+ Snackbar.make(findViewById(android.R.id.content), getString(errorMessage), Snackbar.LENGTH_LONG).show()
|
|
|
+ binding.header.setText(headerMessage) // TODO check if really needed
|
|
|
+ binding.explanation.visibility = explanationVisibility // TODO check if really needed
|
|
|
+ clearBoxes()
|
|
|
+ showDelay()
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* Ask to the user for retyping the pass code just entered before saving it as the current pass code.
|
|
|
*/
|
|
|
- protected void requestPassCodeConfirmation() {
|
|
|
- clearBoxes();
|
|
|
- binding.header.setText(R.string.pass_code_reenter_your_pass_code);
|
|
|
- binding.explanation.setVisibility(View.INVISIBLE);
|
|
|
- confirmingPassCode = true;
|
|
|
+ private fun requestPassCodeConfirmation() {
|
|
|
+ clearBoxes()
|
|
|
+ binding.header.setText(R.string.pass_code_reenter_your_pass_code)
|
|
|
+ binding.explanation.visibility = View.INVISIBLE
|
|
|
+ confirmingPassCode = true
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Compares pass code entered by the user with the value currently saved in the app.
|
|
|
- *
|
|
|
- * @return 'True' if entered pass code equals to the saved one.
|
|
|
- */
|
|
|
- protected boolean checkPassCode() {
|
|
|
- String[] savedPassCodeDigits = preferences.getPassCode();
|
|
|
-
|
|
|
- boolean result = true;
|
|
|
- for (int i = 0; i < passCodeDigits.length && result; i++) {
|
|
|
- result = passCodeDigits[i] != null && passCodeDigits[i].equals(savedPassCodeDigits[i]);
|
|
|
+ private fun checkPassCode(): Boolean {
|
|
|
+ val savedPassCodeDigits = preferences!!.passCode
|
|
|
+ var result = true
|
|
|
+ var i = 0
|
|
|
+ while (i < passCodeDigits!!.size && result) {
|
|
|
+ result = passCodeDigits!![i] != null && passCodeDigits!![i] == savedPassCodeDigits[i]
|
|
|
+ i++
|
|
|
}
|
|
|
- return result;
|
|
|
+ return result
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Compares pass code retyped by the user in the input fields with the value entered just before.
|
|
|
- *
|
|
|
- * @return 'True' if retyped pass code equals to the entered before.
|
|
|
- */
|
|
|
- protected boolean confirmPassCode() {
|
|
|
- confirmingPassCode = false;
|
|
|
-
|
|
|
- boolean result = true;
|
|
|
- for (int i = 0; i < passCodeEditTexts.length && result; i++) {
|
|
|
- result = passCodeEditTexts[i].getText().toString().equals(passCodeDigits[i]);
|
|
|
+ private fun confirmPassCode(): Boolean {
|
|
|
+ confirmingPassCode = false
|
|
|
+ var result = true
|
|
|
+ var i = 0
|
|
|
+ while (i < passCodeEditTexts.size && result) {
|
|
|
+ result = passCodeEditTexts[i]?.text.toString() == passCodeDigits!![i]
|
|
|
+ i++
|
|
|
}
|
|
|
- return result;
|
|
|
+ return result
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Sets the input fields to empty strings and puts the focus on the first one.
|
|
|
- */
|
|
|
- protected void clearBoxes() {
|
|
|
- for (EditText mPassCodeEditText : passCodeEditTexts) {
|
|
|
- mPassCodeEditText.setText("");
|
|
|
+ private fun clearBoxes() {
|
|
|
+ for (mPassCodeEditText in passCodeEditTexts) {
|
|
|
+ mPassCodeEditText?.setText("")
|
|
|
}
|
|
|
- passCodeEditTexts[0].requestFocus();
|
|
|
+ passCodeEditTexts[0]?.requestFocus()
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -344,100 +306,86 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable {
|
|
|
* @param event Event triggered.
|
|
|
* @return 'True' when the key event was processed by this method.
|
|
|
*/
|
|
|
- @Override
|
|
|
- public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
|
- if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
|
|
|
- if (ACTION_CHECK.equals(getIntent().getAction())) {
|
|
|
- moveTaskToBack(true);
|
|
|
- finishAndRemoveTask();
|
|
|
- } else if (ACTION_REQUEST_WITH_RESULT.equals(getIntent().getAction()) ||
|
|
|
- ACTION_CHECK_WITH_RESULT.equals(getIntent().getAction())) {
|
|
|
- finish();
|
|
|
- }// else, do nothing, but report that the key was consumed to stay alive
|
|
|
- return true;
|
|
|
+ override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
|
|
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.repeatCount == 0) {
|
|
|
+ if (ACTION_CHECK == intent.action) {
|
|
|
+ moveTaskToBack(true)
|
|
|
+ finishAndRemoveTask()
|
|
|
+ } else if (ACTION_REQUEST_WITH_RESULT == intent.action || ACTION_CHECK_WITH_RESULT == intent.action) {
|
|
|
+ finish()
|
|
|
+ } // else, do nothing, but report that the key was consumed to stay alive
|
|
|
+ return true
|
|
|
}
|
|
|
- return super.onKeyDown(keyCode, event);
|
|
|
+ return super.onKeyDown(keyCode, event)
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Saves the pass code input by the user as the current pass code.
|
|
|
- */
|
|
|
- protected void savePassCodeAndExit() {
|
|
|
- Intent resultIntent = new Intent();
|
|
|
- resultIntent.putExtra(KEY_PASSCODE,
|
|
|
- passCodeDigits[0] + passCodeDigits[1] + passCodeDigits[2] + passCodeDigits[3]);
|
|
|
-
|
|
|
- setResult(RESULT_OK, resultIntent);
|
|
|
+ private fun savePassCodeAndExit() {
|
|
|
+ val resultIntent = Intent()
|
|
|
+ resultIntent.putExtra(
|
|
|
+ KEY_PASSCODE,
|
|
|
+ passCodeDigits!![0] + passCodeDigits!![1] + passCodeDigits!![2] + passCodeDigits!![3]
|
|
|
+ )
|
|
|
+ setResult(RESULT_OK, resultIntent)
|
|
|
+ passCodeManager?.updateLockTimestamp()
|
|
|
+ finish()
|
|
|
+ }
|
|
|
|
|
|
- passCodeManager.updateLockTimestamp();
|
|
|
+ private fun showDelay() {
|
|
|
+ val delay = preferences?.pinBruteForceDelay() ?: 0
|
|
|
|
|
|
- finish();
|
|
|
- }
|
|
|
+ if (delay <= 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- private void showDelay() {
|
|
|
- int delay = preferences.pinBruteForceDelay();
|
|
|
-
|
|
|
- if (delay > 0) {
|
|
|
- binding.explanation.setText(R.string.brute_force_delay);
|
|
|
- binding.explanation.setVisibility(View.VISIBLE);
|
|
|
- binding.txt0.setEnabled(false);
|
|
|
- binding.txt1.setEnabled(false);
|
|
|
- binding.txt2.setEnabled(false);
|
|
|
- binding.txt3.setEnabled(false);
|
|
|
-
|
|
|
- new Thread(new Runnable() {
|
|
|
- @Override
|
|
|
- public void run() {
|
|
|
- try {
|
|
|
- Thread.sleep(delay * 1000L);
|
|
|
-
|
|
|
- runOnUiThread(() -> {
|
|
|
- binding.explanation.setVisibility(View.INVISIBLE);
|
|
|
- binding.txt0.setEnabled(true);
|
|
|
- binding.txt1.setEnabled(true);
|
|
|
- binding.txt2.setEnabled(true);
|
|
|
- binding.txt3.setEnabled(true);
|
|
|
- });
|
|
|
- } catch (InterruptedException e) {
|
|
|
- Log_OC.e(this, "Could not delay password input prompt");
|
|
|
+ binding.explanation.setText(R.string.brute_force_delay)
|
|
|
+ binding.explanation.visibility = View.VISIBLE
|
|
|
+ binding.txt0.isEnabled = false
|
|
|
+ binding.txt1.isEnabled = false
|
|
|
+ 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")
|
|
|
}
|
|
|
- }).start();
|
|
|
- }
|
|
|
+ }
|
|
|
+
|
|
|
+ }).start()
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void onSaveInstanceState(@NonNull Bundle outState) {
|
|
|
- super.onSaveInstanceState(outState);
|
|
|
- outState.putBoolean(PassCodeActivity.KEY_CONFIRMING_PASSCODE, confirmingPassCode);
|
|
|
- outState.putStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS, passCodeDigits);
|
|
|
+ public override fun onSaveInstanceState(outState: Bundle) {
|
|
|
+ super.onSaveInstanceState(outState)
|
|
|
+ outState.putBoolean(KEY_CONFIRMING_PASSCODE, confirmingPassCode)
|
|
|
+ outState.putStringArray(KEY_PASSCODE_DIGITS, passCodeDigits)
|
|
|
}
|
|
|
|
|
|
- private class PassCodeDigitTextWatcher implements TextWatcher {
|
|
|
+ private inner class PassCodeDigitTextWatcher(index: Int, lastOne: Boolean) : TextWatcher {
|
|
|
+ private var mIndex = -1
|
|
|
+ private val mLastOne: Boolean
|
|
|
|
|
|
- private int mIndex = -1;
|
|
|
- private boolean mLastOne;
|
|
|
+ init {
|
|
|
+ mIndex = index
|
|
|
+ mLastOne = lastOne
|
|
|
|
|
|
- /**
|
|
|
- * Constructor
|
|
|
- *
|
|
|
- * @param index Position in the pass code of the input field that will be bound to this watcher.
|
|
|
- * @param lastOne 'True' means that watcher corresponds to the last position of the pass code.
|
|
|
- */
|
|
|
- PassCodeDigitTextWatcher(int index, boolean lastOne) {
|
|
|
- mIndex = index;
|
|
|
- mLastOne = lastOne;
|
|
|
-
|
|
|
- if (mIndex < 0) {
|
|
|
- throw new IllegalArgumentException(
|
|
|
- "Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() +
|
|
|
- " constructor"
|
|
|
- );
|
|
|
+ require(mIndex >= 0) {
|
|
|
+ "Invalid index in " + PassCodeDigitTextWatcher::class.java.simpleName +
|
|
|
+ " constructor"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private int next() {
|
|
|
- return mLastOne ? 0 : mIndex + 1;
|
|
|
+ private operator fun next(): Int {
|
|
|
+ return if (mLastOne) 0 else mIndex + 1
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -447,33 +395,43 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable {
|
|
|
*
|
|
|
* @param s Changed text
|
|
|
*/
|
|
|
- @Override
|
|
|
- public void afterTextChanged(Editable s) {
|
|
|
- if (s.length() > 0) {
|
|
|
+ override fun afterTextChanged(s: Editable) {
|
|
|
+ if (s.isNotEmpty()) {
|
|
|
if (!confirmingPassCode) {
|
|
|
- Editable passCodeText = passCodeEditTexts[mIndex].getText();
|
|
|
+ val passCodeText = passCodeEditTexts[mIndex]?.text
|
|
|
|
|
|
if (passCodeText != null) {
|
|
|
- passCodeDigits[mIndex] = passCodeText.toString();
|
|
|
+ passCodeDigits!![mIndex] = passCodeText.toString()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (mLastOne) {
|
|
|
- processFullPassCode();
|
|
|
+ processFullPassCode()
|
|
|
} else {
|
|
|
- passCodeEditTexts[next()].requestFocus();
|
|
|
+ passCodeEditTexts[next()]?.requestFocus()
|
|
|
}
|
|
|
-
|
|
|
} else {
|
|
|
- Log_OC.d(TAG, "Text box " + mIndex + " was cleaned");
|
|
|
+ Log_OC.d(TAG, "Text box $mIndex was cleaned")
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
|
|
-
|
|
|
- @Override
|
|
|
- public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
|
|
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
|
|
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
|
|
|
}
|
|
|
|
|
|
-}
|
|
|
+ companion object {
|
|
|
+ private val TAG = PassCodeActivity::class.java.simpleName
|
|
|
+ private const val KEY_PASSCODE_DIGITS = "PASSCODE_DIGITS"
|
|
|
+ private const val KEY_CONFIRMING_PASSCODE = "CONFIRMING_PASSCODE"
|
|
|
+ const val ACTION_REQUEST_WITH_RESULT = "ACTION_REQUEST_WITH_RESULT"
|
|
|
+ const val ACTION_CHECK_WITH_RESULT = "ACTION_CHECK_WITH_RESULT"
|
|
|
+ const val ACTION_CHECK = "ACTION_CHECK"
|
|
|
+ const val KEY_PASSCODE = "KEY_PASSCODE"
|
|
|
+ const val KEY_CHECK_RESULT = "KEY_CHECK_RESULT"
|
|
|
+ const val PREFERENCE_PASSCODE_D = "PrefPinCode"
|
|
|
+ const val PREFERENCE_PASSCODE_D1 = "PrefPinCode1"
|
|
|
+ const val PREFERENCE_PASSCODE_D2 = "PrefPinCode2"
|
|
|
+ const val PREFERENCE_PASSCODE_D3 = "PrefPinCode3"
|
|
|
+ const val PREFERENCE_PASSCODE_D4 = "PrefPinCode4"
|
|
|
+ }
|
|
|
+}
|