5

I am writing an application with login details (username and password).
I want to make it so that when the user closes the application and starts it again later he/she doesn't have to enter his/her user name and password again.

So here is my code so far. It doesn't seem to remember the password nor the username, unfortunately for me:

protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);

    mPrefs = getSharedPreferences(PREFS, 0);
    final CheckBox rememberMeCbx = (CheckBox)findViewById(R.id.saveLoginCheckBox);

    boolean rememberMe = mPrefs.getBoolean("rememberMe", false);



    if (android.os.Build.VERSION.SDK_INT > 9)
    {
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
    }
    mXmlRpcClient = new XMLRPCClient(mXmlRpcUri);

    // Set up the login form.
    //mUsername = getIntent().getStringExtra(EXTRA_EMAIL);
    mUsernameView = (EditText) findViewById(R.id.username);
    mUsernameView.setText(mUsername);

    mPasswordView = (EditText) findViewById(R.id.password);
    mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
                @Override
                public boolean onEditorAction(TextView textView, int id,
                        KeyEvent keyEvent) {
                    if (id == R.id.login || id == EditorInfo.IME_NULL) {
                        attemptLogin();
                        return true;
                    }
                    return false;
                }
            });

    mLoginFormView = findViewById(R.id.login_form);
    mLoginStatusView = findViewById(R.id.login_status);
    mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);

    findViewById(R.id.sign_in_button).setOnClickListener
    (
            new View.OnClickListener()
            {
                @Override
                public void onClick(View view) 
                {
                    if(rememberMeCbx.isChecked())
                    {
                        attemptLogin(); //function to check if fields are filled correctly
                        saveLoginDetails();
                    }
                    else
                    {
                        attemptLogin();
                        removeLoginDetails();
                    }

                }
            });

    if(rememberMe == true)
    {
        //get previously stored login details
        String login = mPrefs.getString("mUsername", null);
        String upass = mPrefs.getString("mPassword", null);

        if(login != null && upass != null)
        {
            //fill input boxes with stored login and pass
            EditText loginEbx = (EditText)findViewById(R.id.username);
            EditText passEbx = (EditText)findViewById(R.id.password);
            loginEbx.setText(login);
            passEbx.setText(upass);

            //set the check box to 'checked'                
            rememberMeCbx.setChecked(true);
        }
    }
}



/**
 * Represents an asynchronous login/registration task used to authenticate
 * the user.
 */
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
    @Override
    protected Boolean doInBackground(Void... params) {
        try {
            mSessionID = (String)mXmlRpcClient.call(mLoginFuncName, mUsername, mPassword);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        mAuthTask = null;
        showProgress(false);

        if (success) {
            finish();
            Intent intent = new Intent(LoginActivity.this, MainWindow.class);
            intent.putExtra("SessionID", mSessionID);
            intent.putExtra("XmlRpcUrl", mXmlRpcUrl);
            intent.putExtra("LoginFuncName", mLoginFuncName);
            intent.putExtra("LogoutFuncName", mLogoutFuncName);
            intent.putExtra("GetDevicesFuncName", mGetDevicesFuncName);
            intent.putExtra("SendPositionFuncName", mSendPositionFuncName);
            intent.putExtra("GetSavedTripFunc", mGetSavedTripFunc);             
            startActivity(intent);
        } else {
            mPasswordView
                    .setError(getString(R.string.error_incorrect_password));
            mPasswordView.requestFocus();
        }
    }


}

private void saveLoginDetails()
{
    //fill input boxes with stored login and pass
    EditText loginEbx = (EditText)findViewById(R.id.username);
    EditText passEbx = (EditText)findViewById(R.id.password);
    String login = loginEbx.getText().toString();
    String upass = passEbx.getText().toString();

    Editor e = mPrefs.edit();
    e.putBoolean("rememberMe", true);
    e.putString("login", login);
    e.putString("password", upass);
    e.commit();
}

private void removeLoginDetails()
{
    Editor e = mPrefs.edit();
    e.putBoolean("rememberMe", false);
    e.remove("login");
    e.remove("password");
    e.commit();
}

}

Can you tell me what is wrong with my code and how can I improve it so that the user name and password are saved and retrieved after the application is closed and opened again?

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
user3182266
  • 1,270
  • 4
  • 23
  • 49
  • saved data on `Preference` in activity `onPause()` and load that data on activity `onResume()` – M D Feb 11 '14 at 08:59
  • so you mean I should put the my saveLoginDetails() method in onPause() and the "if(rememberMe == true)" check in the onResume() ? – user3182266 Feb 11 '14 at 09:01
  • you should get the value of remember me from the checkBox onCheckedChangeListener , and for saving and getting login informations you should use SharedPreferences , see this tutorial to learn how to save/retreive data from preferences : http://www.android-ios-tutorials.com/54/android-shared-preferences-tutorial/ – Houcine Feb 11 '14 at 09:19

3 Answers3

15

Try this way: defined Preferences first

private static final String PREFS_NAME = "preferences";
private static final String PREF_UNAME = "Username";
private static final String PREF_PASSWORD = "Password";

private final String DefaultUnameValue = "";
private String UnameValue;

private final String DefaultPasswordValue = "";
private String PasswordValue;

And onPause()

@Override
public void onPause() {
    super.onPause();
    savePreferences();

}

And onResume()

@Override
public void onResume() {
    super.onResume();
    loadPreferences();
     }

And here savePreferences()

private void savePreferences() {
    SharedPreferences settings = getSharedPreferences(PREFS_NAME,
            Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = settings.edit();

    // Edit and commit
    UnameValue = edt_username.getText();
    PasswordValue = edt_password.getText();
    System.out.println("onPause save name: " + UnameValue);
    System.out.println("onPause save password: " + PasswordValue);
    editor.putString(PREF_UNAME, UnameValue);
    editor.putString(PREF_PASSWORD, PasswordValue);
    editor.commit();
}

And here loadPreferences()

private void loadPreferences() {

    SharedPreferences settings = getSharedPreferences(PREFS_NAME,
            Context.MODE_PRIVATE);

    // Get value
    UnameValue = settings.getString(PREF_UNAME, DefaultUnameValue);
    PasswordValue = settings.getString(PREF_PASSWORD, DefaultPasswordValue);
    edt_username.setText(UnameValue);
    edt_password.setText(PasswordValue);
    System.out.println("onResume load name: " + UnameValue);
    System.out.println("onResume load password: " + PasswordValue);
}
M D
  • 47,665
  • 9
  • 93
  • 114
  • hmm this looks promising but I have a checkbox so I want to save the details if the checkbox is checked and not if it is not – user3182266 Feb 11 '14 at 09:07
  • @user3182266 shared preferences is the way – Raghunandan Feb 11 '14 at 09:08
  • @user3182266 then u need store checkbook state and load it and check it.that's it – M D Feb 11 '14 at 09:09
  • 3
    I would suggest to use MODE_PRIVATE when storing passwords etc. Also, no need to use .toString() method after you use getString() which returns String :) – localhost Feb 11 '14 at 09:09
  • You should not save the password in clear format for security reason. Save the authentication token instead. – sudanix Feb 11 '14 at 09:15
  • @sudanix you are right.but here the question is not related to security. user just need to saved there login info. – M D Feb 11 '14 at 09:16
  • This is not secure. – T.Dimitrov Mar 16 '18 at 21:27
  • @T.Dimitrov It looks like M D has update the question to include MODE_PRIVATE. Are there any other ways to do this more securely? – Paradox Mar 18 '18 at 16:38
  • 3
    @Paradox when you save info in shared preferences file, if your phone somehow is rooted than there will be access to those files. What i would suggest if you do not have server and can go for the access token approach where you give access token with which you recognize the user and you store it, atleast you should use encryption before putting it shared preferences. https://androidluckyguys.wordpress.com/2017/09/12/android-data-security-aes-and-rsa-encryption-and-decryption/ take a look and if you have time research the topic. Account manager is also not 100% safe. – T.Dimitrov Mar 18 '18 at 17:30
1

I high not recommend your logic ! I recommend you toAccountManager API to authenticate and store the users credentials, or write your own account manager, always use this AccountManager which only stores your auth-token.

Account Manager's data can also be accessed through a root!

For your logic at least try to to use SharedPreferences in secured way otherwise with root access we can get SharedPreferences data from the mobile!

LOG_TAG
  • 19,894
  • 12
  • 72
  • 105
  • 1
    How would you go about implementing this? – Paradox Mar 18 '18 at 16:39
  • Use scottyab:secure-preferences or just search for How to use custom Google account manager logic, many samples available! – LOG_TAG Mar 19 '18 at 11:08
  • 1
    LOG_TAG Account Manager's data can also be accessed through a root, it is not safe. You need to us encryption. – T.Dimitrov Nov 27 '18 at 14:58
  • 1
    @T.Dimitrov very true! now Room based shared preference available with encryption more performance with cache support! – LOG_TAG Nov 27 '18 at 17:13
0

OK so far I think your code is correct but you dont know where to implement it.

So there should be a point where your login is successful and you want to open another Activity in your app and for that you must be calling an Intent.

Therefore all you need to do is when you fire the Intent on successful login you can call your saveLoginDetails() method like this.

if(*successful login condition*){
    Intent intent=new Intent(CurrentActivity.this,NextActivity.class);
    saveLoginDetails();
    startActivity(intent);
}

and whenever the user logout you can implement your removeLoginDetails() method.

Hope it helps... Cheers... :)

SMR
  • 6,628
  • 2
  • 35
  • 56