X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/9593b580b72aaec969689eb4ca7197f8da736ab8..ff82b51e49f40155e7c340090f5ee759af2bf3ad:/src/com/owncloud/android/ui/activity/PassCodeActivity.java diff --git a/src/com/owncloud/android/ui/activity/PassCodeActivity.java b/src/com/owncloud/android/ui/activity/PassCodeActivity.java index 9da7784d..09a96307 100644 --- a/src/com/owncloud/android/ui/activity/PassCodeActivity.java +++ b/src/com/owncloud/android/ui/activity/PassCodeActivity.java @@ -1,6 +1,9 @@ /** * ownCloud Android client application * + * @author Bartek Przybylski + * @author masensio + * @author David A. Velasco * Copyright (C) 2011 Bartek Przybylski * Copyright (C) 2015 ownCloud Inc. * @@ -24,48 +27,55 @@ import java.util.Arrays; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; import android.text.Editable; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; -import android.view.View.OnFocusChangeListener; -import android.view.View.OnKeyListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.SherlockFragmentActivity; import com.owncloud.android.R; +import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.utils.DisplayUtils; -public class PassCodeActivity extends SherlockFragmentActivity { +public class PassCodeActivity extends ActionBarActivity { - - public final static String ACTION_TOGGLE = PassCodeActivity.class.getCanonicalName() + ".TOGGLE"; - public final static String ACTION_REQUEST= PassCodeActivity.class.getCanonicalName() + ".REQUEST"; - public final static String EXTRA_NEW_STATE = PassCodeActivity.class.getCanonicalName() + ".NEW_STATE"; - + private static final String TAG = PassCodeActivity.class.getSimpleName(); + + public final static String ACTION_ENABLE = PassCodeActivity.class.getCanonicalName() + + ".ENABLE"; + public final static String ACTION_DISABLE = PassCodeActivity.class.getCanonicalName() + + ".DISABLE"; + public final static String ACTION_REQUEST = PassCodeActivity.class.getCanonicalName() + + ".REQUEST"; + private Button mBCancel; private TextView mPassCodeHdr; private TextView mPassCodeHdrExplanation; - private EditText mText1; - private EditText mText2; - private EditText mText3; - private EditText mText4; - - private String [] mTempText ={"","","",""}; + private EditText[] mPassCodeEditTexts = new EditText[4]; + private String [] mPassCodeDigits = {"","","",""}; + private static String KEY_PASSCODE_DIGITS = "PASSCODE_DIGITS"; private boolean mConfirmingPassCode = false; - private boolean mPassCodeChecked = false; - private boolean mNewPasswordEntered = false; + private static String KEY_CONFIRMING_PASSCODE = "CONFIRMING_PASSCODE"; + private boolean mBChange = true; // to control that only one blocks jump - //private int mTCounter ; // Count the number of attempts an user could introduce the pass code - + + /** + * Initializes the activity. + * + * An intent with a valid ACTION is expected; if none is found, an + * {@link IllegalArgumentException} will be thrown. + * + * @param savedInstanceState Previously saved state - irrelevant in this case + */ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.passcodelock); @@ -73,198 +83,123 @@ public class PassCodeActivity extends SherlockFragmentActivity { mBCancel = (Button) findViewById(R.id.cancel); mPassCodeHdr = (TextView) findViewById(R.id.header); mPassCodeHdrExplanation = (TextView) findViewById(R.id.explanation); - mText1 = (EditText) findViewById(R.id.txt1); - mText1.requestFocus(); - getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - mText2 = (EditText) findViewById(R.id.txt2); - mText3 = (EditText) findViewById(R.id.txt3); - mText4 = (EditText) findViewById(R.id.txt4); - - SharedPreferences appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - - - // Not Pass Code defined yet. - // In a previous version settings is allow from start - if ( (appPrefs.getString("PrefPinCode1", null) == null ) ){ - setChangePassCodeView(true); - mPassCodeChecked = true; - mNewPasswordEntered = true; - - } else { + mPassCodeEditTexts[0] = (EditText) findViewById(R.id.txt0); + mPassCodeEditTexts[0].requestFocus(); + getWindow().setSoftInputMode( + android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + mPassCodeEditTexts[1] = (EditText) findViewById(R.id.txt1); + mPassCodeEditTexts[2] = (EditText) findViewById(R.id.txt2); + mPassCodeEditTexts[3] = (EditText) findViewById(R.id.txt3); + + if (ACTION_REQUEST.equals(getIntent().getAction())) { + /// this is a pass code request; the user has to input the right value + mPassCodeHdr.setText(R.string.pass_code_enter_pass_code); + mPassCodeHdrExplanation.setVisibility(View.INVISIBLE); + setCancelButtonEnabled(false); // no option to cancel - /// TODO rewrite this activity; this logic is too twisted - if (appPrefs.getBoolean("set_pincode", false)){ - // pass code activated - if (ACTION_TOGGLE.equals(getIntent().getAction())) { - // pass code has been activated yet - mPassCodeHdr.setText(R.string.pass_code_configure_your_pass_code); - mPassCodeHdrExplanation.setVisibility(View.VISIBLE); - mPassCodeChecked = true ; // No need to check it - setChangePassCodeView(true); - } else { - // pass code active - mBCancel.setVisibility(View.INVISIBLE); - mBCancel.setVisibility(View.GONE); - mPassCodeHdr.setText(R.string.pass_code_enter_pass_code); - mPassCodeHdrExplanation.setVisibility(View.INVISIBLE); - setChangePassCodeView(false); - } - - } else { - // pass code removal - mPassCodeHdr.setText(R.string.pass_code_remove_your_pass_code); - mPassCodeHdrExplanation.setVisibility(View.INVISIBLE); - mPassCodeChecked = false; - setChangePassCodeView(true); - } - + } else if (ACTION_ENABLE.equals(getIntent().getAction())) { + if (savedInstanceState != null) { + mConfirmingPassCode = savedInstanceState.getBoolean(PassCodeActivity.KEY_CONFIRMING_PASSCODE); + mPassCodeDigits = savedInstanceState.getStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS); + } + if(mConfirmingPassCode){ + //the app was in the passcodeconfirmation + requestPassCodeConfirmation(); + }else{ + /// pass code preference has just been activated in Preferences; + // will receive and confirm pass code value + mPassCodeHdr.setText(R.string.pass_code_configure_your_pass_code); + //mPassCodeHdr.setText(R.string.pass_code_enter_pass_code); + // TODO choose a header, check iOS + mPassCodeHdrExplanation.setVisibility(View.VISIBLE); + setCancelButtonEnabled(true); + } + + } else if (ACTION_DISABLE.equals(getIntent().getAction())) { + /// pass code preference has just been disabled in Preferences; + // will confirm user knows pass code, then remove it + mPassCodeHdr.setText(R.string.pass_code_remove_your_pass_code); + mPassCodeHdrExplanation.setVisibility(View.INVISIBLE); + setCancelButtonEnabled(true); + + } else { + throw new IllegalArgumentException("A valid ACTION is needed in the Intent passed to " + + TAG); } + setTextListeners(); ActionBar actionBar = getSupportActionBar(); actionBar.setIcon(DisplayUtils.getSeasonalIconId()); } - - - protected void setInitVars(){ - mConfirmingPassCode = false; - mPassCodeChecked = false; - mNewPasswordEntered = false; - } - - protected void setInitView(){ - mBCancel.setVisibility(View.INVISIBLE); - mBCancel.setVisibility(View.GONE); - mPassCodeHdr.setText(R.string.pass_code_enter_pass_code); - mPassCodeHdrExplanation.setVisibility(View.INVISIBLE); - } - - - protected void setChangePassCodeView(boolean state){ - - if(state){ - mBCancel.setVisibility(View.VISIBLE); - mBCancel.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - - SharedPreferences.Editor appPrefsE = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()).edit(); - - SharedPreferences appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - - boolean state = appPrefs.getBoolean("set_pincode", false); - appPrefsE.putBoolean("set_pincode",!state); - appPrefsE.commit(); - setInitVars(); - finish(); - } - }); - } - - } - - - - /* - * + /** + * 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 setTextListeners(){ - - /*------------------------------------------------ - * FIRST BOX - -------------------------------------------------*/ - - mText1.addTextChangedListener(new TextWatcher() { + protected void setCancelButtonEnabled(boolean enabled){ + if(enabled){ + mBCancel.setVisibility(View.VISIBLE); + mBCancel.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + revertActionAndExit(); + } + }); + } else { + mBCancel.setVisibility(View.GONE); + mBCancel.setVisibility(View.INVISIBLE); + mBCancel.setOnClickListener(null); + } + } - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - } - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } + /** + * Binds the appropiate listeners to the input boxes receiving each digit of the pass code. + */ + protected void setTextListeners() { + + /// First input field + mPassCodeEditTexts[0].addTextChangedListener(new PassCodeDigitTextWatcher(0, false)); - @Override - public void afterTextChanged(Editable s) { - if (s.length() > 0) { - if (!mConfirmingPassCode){ - mTempText[0] = mText1.getText().toString(); - - } - mText2.requestFocus(); - } - } - }); - - /*------------------------------------------------ * SECOND BOX -------------------------------------------------*/ - mText2.addTextChangedListener(new TextWatcher() { + mPassCodeEditTexts[1].addTextChangedListener(new PassCodeDigitTextWatcher(1, false)); - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - } + mPassCodeEditTexts[1].setOnKeyListener(new View.OnKeyListener() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) { // TODO WIP: event should be + // used to control what's exactly happening with DEL, not any custom field... + mPassCodeEditTexts[0].setText(""); + mPassCodeEditTexts[0].requestFocus(); + if (!mConfirmingPassCode) + mPassCodeDigits[0] = ""; + mBChange = false; - @Override - public void afterTextChanged(Editable s) { - if (s.length() > 0) { - if (!mConfirmingPassCode){ - mTempText[1] = mText2.getText().toString(); - } - - mText3.requestFocus(); + } else if (!mBChange) { + mBChange = true; } + return false; } }); - - mText2.setOnKeyListener(new OnKeyListener() { - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) { + mPassCodeEditTexts[1].setOnFocusChangeListener(new View.OnFocusChangeListener() { - mText1.setText(""); - mText1.requestFocus(); - if (!mConfirmingPassCode) - mTempText[0] = ""; - mBChange= false; - - }else if(!mBChange){ - mBChange=true; - - } - return false; - } - }); - - mText2.setOnFocusChangeListener(new OnFocusChangeListener() { - @Override public void onFocusChange(View v, boolean hasFocus) { - mText2.setCursorVisible(true); - if (mText1.getText().toString().equals("")){ - mText2.setSelected(false); - mText2.setCursorVisible(false); - mText1.requestFocus(); - mText1.setSelected(true); - mText1.setSelection(0); + /// TODO WIP: should take advantage of hasFocus to reduce processing + if (mPassCodeEditTexts[0].getText().toString().equals("")) { // TODO WIP validation + // could be done in a global way, with a single OnFocusChangeListener for all the + // input fields + mPassCodeEditTexts[0].requestFocus(); } - } }); @@ -272,314 +207,338 @@ public class PassCodeActivity extends SherlockFragmentActivity { /*------------------------------------------------ * THIRD BOX -------------------------------------------------*/ - mText3.addTextChangedListener(new TextWatcher() { - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - } + mPassCodeEditTexts[2].addTextChangedListener(new PassCodeDigitTextWatcher(2, false)); - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void afterTextChanged(Editable s) { - if (s.length() > 0) { - if (!mConfirmingPassCode){ - mTempText[2] = mText3.getText().toString(); - } - mText4.requestFocus(); - } - } - }); - - mText3.setOnKeyListener(new OnKeyListener() { + mPassCodeEditTexts[2].setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) { - mText2.requestFocus(); + mPassCodeEditTexts[1].requestFocus(); if (!mConfirmingPassCode) - mTempText[1] = ""; - mText2.setText(""); - mBChange= false; - - }else if(!mBChange){ - mBChange=true; - + mPassCodeDigits[1] = ""; + mPassCodeEditTexts[1].setText(""); + mBChange = false; + + } else if (!mBChange) { + mBChange = true; + } return false; } }); - - mText3.setOnFocusChangeListener(new OnFocusChangeListener() { - + + mPassCodeEditTexts[2].setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override public void onFocusChange(View v, boolean hasFocus) { - mText3.setCursorVisible(true); - if (mText1.getText().toString().equals("")){ - mText3.setSelected(false); - mText3.setCursorVisible(false); - mText1.requestFocus(); - mText1.setSelected(true); - mText1.setSelection(0); - }else if (mText2.getText().toString().equals("")){ - mText3.setSelected(false); - mText3.setCursorVisible(false); - mText2.requestFocus(); - mText2.setSelected(true); - mText2.setSelection(0); + if (mPassCodeEditTexts[0].getText().toString().equals("")) { + mPassCodeEditTexts[0].requestFocus(); + } else if (mPassCodeEditTexts[1].getText().toString().equals("")) { + mPassCodeEditTexts[1].requestFocus(); } - } }); - + + /*------------------------------------------------ * FOURTH BOX -------------------------------------------------*/ - mText4.addTextChangedListener(new TextWatcher() { - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void afterTextChanged(Editable s) { - if (s.length() > 0) { - - if (!mConfirmingPassCode){ - mTempText[3] = mText4.getText().toString(); - } - mText1.requestFocus(); - - if (!mPassCodeChecked){ - mPassCodeChecked = checkPassCode(); - } - - if (mPassCodeChecked) { - if (ACTION_REQUEST.equals(getIntent().getAction())) { - finish(); - - } else if (mPassCodeChecked) { - String newState = getIntent().getStringExtra(EXTRA_NEW_STATE); - - // TODO - next decision should done according to the current state of PIN in prefs (enable or not), not whatever says de client - if (newState.equals("false")) { - SharedPreferences.Editor appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()).edit(); - appPrefs.putBoolean("set_pincode", false); - appPrefs.commit(); - - setInitVars(); - passCodeEnd(false); - - } else { - - if (!mConfirmingPassCode) { - passCodeChangeRequest(); - - } else { - confirmPassCode(); - } - } - - } - } - } - } - }); + mPassCodeEditTexts[3].addTextChangedListener(new PassCodeDigitTextWatcher(3, true)); - - - mText4.setOnKeyListener(new OnKeyListener() { + mPassCodeEditTexts[3].setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DEL && mBChange) { - mText3.requestFocus(); + mPassCodeEditTexts[2].requestFocus(); if (!mConfirmingPassCode) - mTempText[2]=""; - mText3.setText(""); - mBChange= false; - - }else if(!mBChange){ - mBChange=true; + mPassCodeDigits[2] = ""; + mPassCodeEditTexts[2].setText(""); + mBChange = false; + + } else if (!mBChange) { + mBChange = true; } return false; } }); - - mText4.setOnFocusChangeListener(new OnFocusChangeListener() { - + + mPassCodeEditTexts[3].setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override public void onFocusChange(View v, boolean hasFocus) { - mText4.setCursorVisible(true); - - if (mText1.getText().toString().equals("")){ - mText4.setSelected(false); - mText4.setCursorVisible(false); - mText1.requestFocus(); - mText1.setSelected(true); - mText1.setSelection(0); - }else if (mText2.getText().toString().equals("")){ - mText4.setSelected(false); - mText4.setCursorVisible(false); - mText2.requestFocus(); - mText2.setSelected(true); - mText2.setSelection(0); - }else if (mText3.getText().toString().equals("")){ - mText4.setSelected(false); - mText4.setCursorVisible(false); - mText3.requestFocus(); - mText3.setSelected(true); - mText3.setSelection(0); + + if (mPassCodeEditTexts[0].getText().toString().equals("")) { + mPassCodeEditTexts[0].requestFocus(); + } else if (mPassCodeEditTexts[1].getText().toString().equals("")) { + mPassCodeEditTexts[1].requestFocus(); + } else if (mPassCodeEditTexts[2].getText().toString().equals("")) { + mPassCodeEditTexts[2].requestFocus(); } - + } }); - - - + } // end setTextListener - - - protected void passCodeChangeRequest(){ - - clearBoxes(); + + + /** + * Processes the pass code entered by the user just after the last digit was in. + * + * 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_REQUEST.equals(getIntent().getAction())) { + if (checkPassCode()) { + /// pass code accepted in request, user is allowed to access the app + finish(); + + } else { + showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, + View.INVISIBLE); + } + + } else if (ACTION_DISABLE.equals(getIntent().getAction())) { + if (checkPassCode()) { + /// pass code accepted when disabling, pass code is removed + SharedPreferences.Editor appPrefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()).edit(); + appPrefs.putBoolean("set_pincode", false); // TODO remove; this should be + // unnecessary, was done before entering in the activity + appPrefs.commit(); + + Toast.makeText(PassCodeActivity.this, R.string.pass_code_removed, Toast.LENGTH_LONG).show(); + finish(); + + } else { + showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, + View.INVISIBLE); + } + + } else if (ACTION_ENABLE.equals(getIntent().getAction())) { + /// enabling pass code + if (!mConfirmingPassCode) { + requestPassCodeConfirmation(); + + } else if (confirmPassCode()) { + /// confirmed: user typed the same pass code twice + savePassCodeAndExit(); + + } else { + showErrorAndRestart( + R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE + ); + } + } + } + + + private void showErrorAndRestart(int errorMessage, int headerMessage, + int explanationVisibility) { + Arrays.fill(mPassCodeDigits, null); + CharSequence errorSeq = getString(errorMessage); + Toast.makeText(this, errorSeq, Toast.LENGTH_LONG).show(); + mPassCodeHdr.setText(headerMessage); // TODO check if really needed + mPassCodeHdrExplanation.setVisibility(explanationVisibility); // TODO check if really needed + clearBoxes(); + } + + + /** + * Ask to the user for retyping the pass code just entered before saving it as the current pass + * code. + */ + protected void requestPassCodeConfirmation(){ + clearBoxes(); mPassCodeHdr.setText(R.string.pass_code_reenter_your_pass_code); mPassCodeHdrExplanation.setVisibility(View.INVISIBLE); - mConfirmingPassCode =true; - + mConfirmingPassCode = 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(){ - - SharedPreferences appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - - String pText1 = appPrefs.getString("PrefPinCode1", null); - String pText2 = appPrefs.getString("PrefPinCode2", null); - String pText3 = appPrefs.getString("PrefPinCode3", null); - String pText4 = appPrefs.getString("PrefPinCode4", null); - - if ( mTempText[0].equals(pText1) && - mTempText[1].equals(pText2) && - mTempText[2].equals(pText3) && - mTempText[3].equals(pText4) ) { - - return true; - - - }else { - Arrays.fill(mTempText, null); - CharSequence errorSeq = getString(R.string.common_error); - Toast.makeText(this, errorSeq, Toast.LENGTH_LONG).show(); - - clearBoxes(); - mPassCodeHdr.setText(R.string.pass_code_enter_pass_code); - mPassCodeHdrExplanation.setVisibility(View.INVISIBLE); - mNewPasswordEntered = true; - mConfirmingPassCode = false; - + .getDefaultSharedPreferences(getApplicationContext()); + + String savedPassCodeDigits[] = new String[4]; + savedPassCodeDigits[0] = appPrefs.getString("PrefPinCode1", null); + savedPassCodeDigits[1] = appPrefs.getString("PrefPinCode2", null); + savedPassCodeDigits[2] = appPrefs.getString("PrefPinCode3", null); + savedPassCodeDigits[3] = appPrefs.getString("PrefPinCode4", null); + + boolean result = true; + for (int i = 0; i < mPassCodeDigits.length && result; i++) { + result = result && (mPassCodeDigits[i] != null) && + mPassCodeDigits[i].equals(savedPassCodeDigits[i]); } - - - return false; + return result; } - - protected void confirmPassCode(){ - + + /** + * 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(){ mConfirmingPassCode = false; - - String rText1 = mText1.getText().toString(); - String rText2 = mText2.getText().toString(); - String rText3 = mText3.getText().toString(); - String rText4 = mText4.getText().toString(); - - if ( mTempText[0].equals(rText1) && - mTempText[1].equals(rText2) && - mTempText[2].equals(rText3) && - mTempText[3].equals(rText4) ) { - - savePassCodeAndExit(); - - } else { - Arrays.fill(mTempText, null); - CharSequence cseq = getString(R.string.pass_code_mismatch); - Toast.makeText(this, cseq, Toast.LENGTH_LONG).show(); - - mPassCodeHdr.setText(R.string.pass_code_configure_your_pass_code); - mPassCodeHdrExplanation.setVisibility(View.VISIBLE); - clearBoxes(); + + boolean result = true; + for (int i = 0; i < mPassCodeEditTexts.length && result; i++) { + result = result && + ((mPassCodeEditTexts[i].getText().toString()).equals(mPassCodeDigits[i])); } - + return result; } - - - protected void passCodeEnd(boolean state){ - CharSequence cseq; - if (state){ - cseq = getString(R.string.pass_code_stored); - }else{ - cseq = getString(R.string.pass_code_removed); + + /** + * Sets the input fields to empty strings and puts the focus on the first one. + */ + protected void clearBoxes(){ + for (int i=0; i < mPassCodeEditTexts.length; i++) { + mPassCodeEditTexts[i].setText(""); } - - Toast.makeText(this, cseq, Toast.LENGTH_LONG).show(); - finish(); + mPassCodeEditTexts[0].requestFocus(); } - - protected void savePassCodeAndExit(){ + + /** + * Overrides click on the BACK arrow to correctly cancel ACTION_ENABLE or ACTION_DISABLE, while + * preventing than ACTION_REQUEST may be worked around. + * + * @param keyCode Key code of the key that triggered the down event. + * @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_ENABLE.equals(getIntent().getAction()) || + ACTION_DISABLE.equals(getIntent().getAction())) { + revertActionAndExit(); + } + return true; + } + return super.onKeyDown(keyCode, event); + } + + /** + * Saves the pass code input by the user as the current pass code. + */ + protected void savePassCodeAndExit() { SharedPreferences.Editor appPrefs = PreferenceManager .getDefaultSharedPreferences(getApplicationContext()).edit(); - appPrefs.putString("PrefPinCode1", mTempText[0]); - appPrefs.putString("PrefPinCode2",mTempText[1]); - appPrefs.putString("PrefPinCode3", mTempText[2]); - appPrefs.putString("PrefPinCode4", mTempText[3]); - appPrefs.putBoolean("set_pincode",true); + appPrefs.putString("PrefPinCode1", mPassCodeDigits[0]); + appPrefs.putString("PrefPinCode2", mPassCodeDigits[1]); + appPrefs.putString("PrefPinCode3", mPassCodeDigits[2]); + appPrefs.putString("PrefPinCode4", mPassCodeDigits[3]); + appPrefs.putBoolean("set_pincode", true); /// TODO remove; unnecessary, + // Preferences did it before entering here appPrefs.commit(); - - passCodeEnd(true); + + Toast.makeText(this, R.string.pass_code_stored, Toast.LENGTH_LONG).show(); + finish(); } - - - protected void clearBoxes(){ - mText1.setText(""); - mText2.setText(""); - mText3.setText(""); - mText4.setText(""); - mText1.requestFocus(); + + /** + * Cancellation of ACTION_ENABLE or ACTION_DISABLE; reverts the enable or disable action done by + * {@link Preferences}, then finishes. + */ + protected void revertActionAndExit() { + SharedPreferences.Editor appPrefsE = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()).edit(); + + SharedPreferences appPrefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + boolean state = appPrefs.getBoolean("set_pincode", false); + appPrefsE.putBoolean("set_pincode", !state); + // TODO WIP: this is reverting the value of the preference because it was changed BEFORE + // entering + // TODO in this activity; was the PreferenceCheckBox in the caller who did it + appPrefsE.commit(); + finish(); } - - + @Override - public boolean onKeyDown(int keyCode, KeyEvent event){ - if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount()== 0){ - if (ACTION_TOGGLE.equals(getIntent().getAction())){ - SharedPreferences.Editor appPrefsE = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()).edit(); - - SharedPreferences appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - - boolean state = appPrefs.getBoolean("set_pincode", false); - appPrefsE.putBoolean("set_pincode",!state); - appPrefsE.commit(); - setInitVars(); - finish(); + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(PassCodeActivity.KEY_CONFIRMING_PASSCODE, mConfirmingPassCode); + outState.putStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS, mPassCodeDigits); + } + + + private class PassCodeDigitTextWatcher implements TextWatcher { + + private int mIndex = -1; + private boolean mLastOne = false; + + /** + * 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. + */ + public PassCodeDigitTextWatcher(int index, boolean lastOne) { + mIndex = index; + mLastOne = lastOne; + if (mIndex < 0) { + throw new IllegalArgumentException( + "Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() + + " constructor" + ); } - return true; } - return super.onKeyDown(keyCode, event); - } + + private int next() { + return mLastOne ? 0 : mIndex + 1; + } + + /** + * Performs several actions when the user types a digit in an input field: + * - saves the input digit to the state of the activity; this will allow retyping the + * pass code to confirm it. + * - moves the focus automatically to the next field + * - for the last field, triggers the processing of the full pass code + * + * @param s + */ + @Override + public void afterTextChanged(Editable s) { + if (s.length() > 0) { + if (!mConfirmingPassCode) { + mPassCodeDigits[mIndex] = mPassCodeEditTexts[mIndex].getText().toString(); + } + mPassCodeEditTexts[next()].requestFocus(); + + if (mLastOne) { + processFullPassCode(); + } + + } else { + Log_OC.d(TAG, "Text box " + mIndex + " was cleaned"); + } + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // nothing to do + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // nothing to do + } + + } + + }