I'm trying to create a secure login with android but I have no way of testing it's functionality as the registration feature doesn't work. I have ensured I'm properly connected to the DB and I currently do not receive any errors.
functions.php
This file contains functions for checking whether the user exists not, functions for generating password salt and hashes. I made use of random salt generator so that a unique salt and hash is generated for each user.
<?php
$random_salt_length = 32;
function userExists($username){
$query = "SELECT username FROM member WHERE username = ?";
global $con;
if($stmt = $con->prepare($query)){
$stmt->bind_param("s",$username);
$stmt->execute();
$stmt->store_result();
$stmt->fetch();
if($stmt->num_rows == 1){
$stmt->close();
return true;
}
$stmt->close();
}
return false;
}
function getSalt(){
global $random_salt_length;
return bin2hex(openssl_random_pseudo_bytes($random_salt_length));
}
function concatPasswordWithSalt($password,$salt){
global $random_salt_length;
if($random_salt_length % 2 == 0){
$mid = $random_salt_length / 2;
}
else{
$mid = ($random_salt_length - 1) / 2;
}
return
substr($salt,0,$mid - 1).$password.substr($salt,$mid,$random_salt_length - 1);
}
?>
register.php
<?php
$response = array();
include 'db/db_connect.php';
include 'functions.php';
//Get the input request parameters
$inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE); //convert JSON into array
//Check for Mandatory parameters
if(isset($input['username']) && isset($input['password']) && isset($input['full_name'])){
$username = $input['username'];
$password = $input['password'];
$fullName = $input['full_name'];
//Check if user already exist
if(!userExists($username)){
//Get a unique Salt
$salt = getSalt();
//Generate a unique password Hash
$passwordHash = password_hash(concatPasswordWithSalt($password,$salt),PASSWORD_DEFAULT);
//Query to register new user
$insertQuery = "INSERT INTO member(username, full_name, password_hash, salt) VALUES (?,?,?,?)";
if($stmt = $con->prepare($insertQuery)){
$stmt->bind_param("ssss",$username,$fullName,$passwordHash,$salt);
$stmt->execute();
$response["status"] = 0;
$response["message"] = "User created";
$stmt->close();
}
}
else{
$response["status"] = 1;
$response["message"] = "User exists";
}
}
else{
$response["status"] = 2;
$response["message"] = "Missing mandatory parameters";
}
echo json_encode($response);
?>
registerActivity
public class RegisterActivity extends AppCompatActivity {
private static final String KEY_STATUS = "status";
private static final String KEY_MESSAGE = "message";
private static final String KEY_FULL_NAME = "full_name";
private static final String KEY_USERNAME = "username";
private static final String KEY_PASSWORD = "password";
private static final String KEY_EMPTY = "";
private EditText etUsername;
private EditText etPassword;
private EditText etConfirmPassword;
private EditText etFullName;
private String username;
private String password;
private String confirmPassword;
private String fullName;
private ProgressDialog pDialog;
private String register_url = "http://10.0.0.1/members/register.php";
private SessionHandler session;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
session = new SessionHandler(getApplicationContext());
setContentView(R.layout.activity_register);
etUsername = findViewById(R.id.etUsername);
etPassword = findViewById(R.id.etPassword);
etConfirmPassword = findViewById(R.id.etConfirmPassword);
etFullName = findViewById(R.id.etFullName);
Button login = findViewById(R.id.btnRegisterLogin);
Button register = findViewById(R.id.btnRegister);
//Launch Login screen when Login Button is clicked
login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(RegisterActivity.this, LoginActivity.class);
startActivity(i);
finish();
}
});
register.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Retrieve the data entered in the edit texts
username = etUsername.getText().toString().toLowerCase().trim();
password = etPassword.getText().toString().trim();
confirmPassword = etConfirmPassword.getText().toString().trim();
fullName = etFullName.getText().toString().trim();
if (validateInputs()) {
registerUser();
}
}
});
}
// Display Progress bar while registering
private void displayLoader() {
pDialog = new ProgressDialog(RegisterActivity.this);
pDialog.setMessage("Signing Up.. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
// Launch Dashboard Activity on Successful Sign Up
private void loadDashboard() {
Intent i = new Intent(getApplicationContext(), DashboardActivity.class);
startActivity(i);
finish();
}
private void registerUser() {
displayLoader();
JSONObject request = new JSONObject();
try {
//Populate the request parameters
request.put(KEY_USERNAME, username);
request.put(KEY_PASSWORD, password);
request.put(KEY_FULL_NAME, fullName);
} catch (JSONException e) {
e.printStackTrace();
}
JsonObjectRequest jsArrayRequest = new JsonObjectRequest
(Request.Method.POST, register_url, request, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
pDialog.dismiss();
try {
//Check if user got registered successfully
if (response.getInt(KEY_STATUS) == 0) {
//Set the user session
session.loginUser(username,fullName);
loadDashboard();
}else if(response.getInt(KEY_STATUS) == 1){
//Display error message if username is already existing
etUsername.setError("Username already taken!");
etUsername.requestFocus();
}else{
Toast.makeText(getApplicationContext(),
response.getString(KEY_MESSAGE), Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
pDialog.dismiss();
//Display error message whenever an error occurs
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
// Access the RequestQueue through your singleton class.
VolleySingleton.getInstance(this).addToRequestQueue(jsArrayRequest);
}
sessionHandler
public class SessionHandler {
private static final String PREF_NAME = "UserSession";
private static final String KEY_USERNAME = "username";
private static final String KEY_EXPIRES = "expires";
private static final String KEY_FULL_NAME = "full_name";
private static final String KEY_EMPTY = "";
private Context mContext;
private SharedPreferences.Editor mEditor;
private SharedPreferences mPreferences;
public SessionHandler(Context mContext) {
this.mContext = mContext;
mPreferences = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
this.mEditor = mPreferences.edit();
}
public void loginUser(String username, String fullName) {
mEditor.putString(KEY_USERNAME, username);
mEditor.putString(KEY_FULL_NAME, fullName);
Date date = new Date();
//Set user session for next 7 days
long millis = date.getTime() + (7 * 24 * 60 * 60 * 1000);
mEditor.putLong(KEY_EXPIRES, millis);
mEditor.commit();
}
public boolean isLoggedIn() {
Date currentDate = new Date();
long millis = mPreferences.getLong(KEY_EXPIRES, 0);
/* If shared preferences does not have a value
then user is not logged in
*/
if (millis == 0) {
return false;
}
Date expiryDate = new Date(millis);
/* Check if session is expired by comparing
current date and Session expiry date
*/
return currentDate.before(expiryDate);
}
public User getUserDetails() {
//Check if user is logged in first
if (!isLoggedIn()) {
return null;
}
User user = new User();
user.setUsername(mPreferences.getString(KEY_USERNAME, KEY_EMPTY));
user.setFullName(mPreferences.getString(KEY_FULL_NAME, KEY_EMPTY));
user.setSessionExpiryDate(new Date(mPreferences.getLong(KEY_EXPIRES, 0)));
return user;
}
/**
* Logs out user by clearing the session
*/
public void logoutUser(){
mEditor.clear();
mEditor.commit();
}
}
Can you please push me in the right direction as I can't quite figure out where I'm going wrong
If no error message is displayed but nothing is written to the database, it's possible your query is failing to execute.
This piece of code in register.php currently does not have any error checking:
//Query to register new user
$insertQuery = "INSERT INTO member(username, full_name, password_hash, salt) VALUES (?,?,?,?)";
if($stmt = $con->prepare($insertQuery)){
$stmt->bind_param("ssss",$username,$fullName,$passwordHash,$salt);
$stmt->execute();
$response["status"] = 0;
$response["message"] = "User created";
$stmt->close();
}
This can fail in two places:
$con->prepare() can fail if the database already knows the query won't be executed, e.g. due to a syntax error or because a table or column name doesn't exist or your user doesn't have the right permissions to perform an INSERT query into that table
$stmt->execute() can fail if the query fails at runtime, e.g. if you're trying to insert a string into a column that only accepts integer values.
You should add some extra checks on that. At some point you will want to provide a useful error message to your app so users aren't confronted with technical mumbo-jumbo that they can't fix, but for now while debugging I'd recommend to dump the error message in there (it looks like a status of > 1 indicates an error, correct me if I'm wrong):
//Query to register new user
$insertQuery = "INSERT INTO member(username, full_name, password_hash, salt) VALUES (?,?,?,?)";
if($stmt = $con->prepare($insertQuery)){
$stmt->bind_param("ssss",$username,$fullName,$passwordHash,$salt);
if ($stmt->execute()) {
$response["status"] = 0;
$response["message"] = "User created";
} else {
$response["status"] = 2;
$response["message"] = $stmt->error;
}
$stmt->close();
} else {
$response["status"] = 2;
$response["message"] = $con->error;
}
The project im working on allow the user to register and login and all works perfectly until I spotted something wrong with the code. It doesn't count as an error because the compiler don't think its an error. Its just a bug or whatever people call it is. So here's what happened . The user login to their account, the database transfer their data into intent extras. then on the next activities, the username, coins and gems appears on top of the page so that the user know how much coins they have left. For testing purpose, i added add coin and decrease coin button. still, the code works perfectly. But after the user log out and relogin, the coins backs to the original amount. I know the problem caused by putting a value on the coin variable in User.java class. And still while logging in I put the default value of coins and gems for the user in the intent extras. I just cant find my way on how to put the value from database to the intent extras while user logging in.
so heres the code for login activity
buttonLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Check user input is correct or not
if (validate()) {
//Get values from EditText fields
String Email = editTextEmail.getText().toString();
String Password = editTextPassword.getText().toString();
User player1 = new User(null, null, Email, Password);
//Authenticate user
User currentUser = myDb.Authenticate(player1);
//Check Authentication is successful or not
if (currentUser != null) {
System.out.println("Success");
Bundle extras = new Bundle();
extras.putString("P_ID", currentUser.getId());
extras.putString("P_NAME", currentUser.getName());
extras.putInt("P_COINS", currentUser.getCoins());
extras.putInt("P_GEMS", currentUser.getGems());
Intent intent = new Intent(getApplicationContext(),HomeActivity.class);
intent.putExtras(extras);
startActivity(intent);
finish();
} else {
//User Logged in Failed
System.out.println("Failed");
}
}
}
});
the homeactivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Set fullscreen and no title//////////
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
///////////////////////////////////////
setContentView(R.layout.home_screen);
myDb = new DatabaseHelper(this);
Intent intent = getIntent();
Bundle extras = intent.getExtras();
pid = extras.getString("P_ID");
pname = extras.getString("P_NAME");
pcoins = extras.getInt("P_COINS");
pgems = extras.getInt("P_GEMS");
nametxt = (TextView)findViewById(R.id.playernametext);
coinstxt = (TextView)findViewById(R.id.playercoinstext);
gemstxt = (TextView)findViewById(R.id.playergemstext);
addcoin = (Button)findViewById(R.id.addbtn);
decoin = (Button)findViewById(R.id.decbtn);
nametxt.setText(" " +String.valueOf(pname) +" ");
coinstxt.setText(" Coins : " +String.valueOf(pcoins) +" ");
gemstxt.setText(" Gems : " +String.valueOf(pgems) +" ");
addcoin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pcoins += 10;
boolean isUpdate = myDb.updateUser(pid, pname, String.valueOf(pcoins), String.valueOf(pgems));
if (isUpdate == true) {
nametxt.setText(" " +String.valueOf(pname) +" ");
coinstxt.setText(" Coins : " +String.valueOf(pcoins) +" ");
gemstxt.setText(" Gems : " +String.valueOf(pgems) +" ");
}
}
});
decoin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pcoins -= 10;
boolean isUpdate = myDb.updateUser(pid, pname, String.valueOf(pcoins), String.valueOf(pgems));
if (isUpdate == true) {
nametxt.setText(" " +String.valueOf(pname) +" ");
coinstxt.setText(" Coins : " +String.valueOf(pcoins) +" ");
gemstxt.setText(" Gems : " +String.valueOf(pgems) +" ");
}
}
});
}
and of course the user class
public class User {
public String id;
public String userName;
public String email;
public String password;
public int coins = 1000;
public int gems = 10;
public User(String id, String userName, String email, String password) {
this.id = id;
this.userName = userName;
this.email = email;
this.password = password;
}
public String getId() {
return this.id;
}
public String getName() {
return this.userName;
}
public void addCoins(int addAmount) {
this.coins = addAmount;
}
public void decCoins(int decAmount) {
this.coins = decAmount;
}
public int getCoins() {
return this.coins;
}
public void addGems(int addAmount) {
this.gems = addAmount;
}
public void decGems(int decAmount) {
this.gems = decAmount;
}
public int getGems() {
return this.gems;
}
}
Honestly, my brain lacks of logic. Thats why i come here, to see whether my code does make sense.
And please, if you don't understand what i mean, just ask me which parts and please just dont immediately flag my question. Im really bad at english, trust me.
I'd suggest only passing the userid (which should never change) and then always getting the values coins etc from the database and also only changing them in the database (followed by resetting the displayed values from the values in the database).
You would then not have the issue of trying to juggle two sets of data you would then rely on the real data i.e. that in the database.
Working Example
The following is some code that goes through the basics.
When it starts the MainActivity, immediately starts the LoginActivity when you login then it takes you to the HomeActivity. This display the current Userid, Username, coins (initially 0) and gems.
There are 2 buttons Add10Coins and Add10gems clicking them will apply the new values to the DB displaying the updated values. If you stop the App and rerun, login then the values will be as they were.
Passing values wise, although the LoginActivity sets 3 Intent Extra values only one is used (the userid as a long) by the HomeActivity, but as per the values display all are accessible. If another activity is started then all you have to do is pass the userid via the intent.
The code isn't what I'd call complex but I'd certainly suggest going through it and try to understand it.
user.java
I've added some methods and also added some Constants, this is now :-
public class User {
public static final int ADJUSTTYPE_ADD = 1;
public static final int ADJUSTTYPE_REPLACE = 2;
public static final int ADJUSTTYPE_MULTIPLY = 3;
public static final int ADJUSTTYPE_DIVIDE = 4;
String id;
String userName;
String email;
String password;
int coins;
int gems;
public User(String id, String userName, String email, String password) {
this.id = id;
this.email = email;
//And so on. Don't mind this
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setName(String userName) {
this.userName = userName;
}
public String getName() {
return this.userName;
}
public void setEmail(String email) {
this.email = email;
}
public String getEmail() {
return email;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
public void setCoins(int coins) {
this.coins = coins;
}
public int getCoins() {
return this.coins;
}
public void setGems(int gems) {
this.gems = gems;
}
public int getGems() {
return this.gems;
}
public long getLongId() {
long id;
try {
id = Long.valueOf(this.id);
} catch (Exception e) {
return -1;
}
return id;
}
}
DatabaseHelper.java
This has been written from scratch based upon not the most stringent inspection of your code, it will largely be affected by my styling/usage techniques but not to the extent that I'd apply for real development.
Within this is the method adjustCoinsAndOrGems this is what is used to update the gems or coins in the DB and also in the returned User (so that a synchronised version of the User is returned, not that this returned use is used (I personally prefer to access the database as long as it's not an issue (e.g. noticeably affects performance)))
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DBNAME = "mygame.db";
public static final int DBVERSION = 1;
public static final String TBL_USER = "user";
public static final String COL_USER_ID = BaseColumns._ID;
public static final String COL_USER_NAME = "user_name";
public static final String COL_USER_EMAIL = "user_email";
public static final String COL_USER_PASWWORD = "user_password";
public static final String COL_USER_COINS = "user_coins";
public static final String COL_USER_GEMS = "user_gems";
public static final String TBL_PLAYER = "player";
public static final String COL_PLYAER_ID = BaseColumns._ID;
public static final String COL_PLAYER_OWNINGUSER = "player_owninguser";
public static final String COL_PLAYER_NAME = "player_name";
//...... other columns
SQLiteDatabase mDB;
public DatabaseHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
mDB = this.getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
String crt_tbl_user = "CREATE TABLE IF NOT EXISTS " + TBL_USER + "(" +
COL_USER_ID + " INTEGER PRIMARY KEY," +
COL_USER_NAME + " TEXT NOT NULL UNIQUE," +
COL_USER_EMAIL + " TEXT NOT NULL UNIQUE," +
COL_USER_PASWWORD + " TEXT NOT NULL," +
COL_USER_COINS + " INTEGER," +
COL_USER_GEMS + " INTEGER" +
")";
String crt_tbl_player = "CREATE TABLE IF NOT EXISTS " + TBL_PLAYER + "(" +
COL_PLYAER_ID + " INTEGER PRIMARY KEY," +
COL_PLAYER_NAME + " TEXT NOT NULL," +
COL_PLAYER_OWNINGUSER + " INTEGER REFERENCES " + TBL_USER + "(" + COL_USER_ID + ")" +
")";
db.execSQL(crt_tbl_user);
db.execSQL(crt_tbl_player);
}
#Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
}
/*
Note core add but not intended to be used directly
Note this assumes that checks are done to ensure that name, email and password
have been provided
*/
private long addUser(Long id, String name, String email, String password, int coins, int gems) {
ContentValues cv = new ContentValues();
if (id > 0) {
cv.put(COL_USER_ID,id);
}
if (name.length() > 0) {
cv.put(COL_USER_NAME,name);
}
if (email.length() > 0 ) {
cv.put(COL_USER_EMAIL,email);
}
if (password.length() > 0) {
cv.put(COL_USER_PASWWORD,password);
}
cv.put(COL_USER_COINS,coins);
cv.put(COL_USER_GEMS,gems);
if (cv.size() < 1) return -1; //<<<<<<<<<< return if nothing to add
return mDB.insert(TBL_USER,null,cv);
}
/*
For add with just name, email and password (normal usage)
*/
public long addUser(String name, String email, String password) {
return this.addUser(-1L,name,email,password,0,0);
}
/*
For adding a user setting the coins and gems (special usage)
*/
public long addUserSettingCoinsAndGems(String name, String email, String password, int coins, int gems) {
return this.addUser(-1L,name,email,password,coins,gems);
}
public User getUser(long id) {
User rv = new User("-1","",",",""); // Invalid user
String whereclause = COL_USER_ID + "=?";
String[] whereargs = new String[]{String.valueOf(id)};
Cursor csr = mDB.query(TBL_USER,null,whereclause,whereargs,null,null,null);
if (csr.moveToFirst()) {
rv.setId(String.valueOf(id));
rv.setName(csr.getString(csr.getColumnIndex(COL_USER_NAME)));
rv.setEmail(csr.getString(csr.getColumnIndex(COL_USER_EMAIL)));
rv.setPassword(csr.getString(csr.getColumnIndex(COL_USER_PASWWORD)));
rv.setCoins(csr.getInt(csr.getColumnIndex(COL_USER_COINS)));
rv.setGems(csr.getInt(csr.getColumnIndex(COL_USER_GEMS)));
}
csr.close();
return rv;
}
public User getUser(String userid) {
String whereclause = COL_USER_ID + "=?";
User rv = new User("-1","",",",""); // Invalid user
long id;
try {
id = Long.valueOf(userid);
} catch (Exception e) {
return rv;
}
String[] whereargs = new String[]{String.valueOf(id)};
Cursor csr = mDB.query(TBL_USER,null,whereclause,whereargs,null,null,null);
if (csr.moveToFirst()) {
rv.setId(String.valueOf(id));
rv.setName(csr.getString(csr.getColumnIndex(COL_USER_NAME)));
rv.setEmail(csr.getString(csr.getColumnIndex(COL_USER_EMAIL)));
rv.setPassword(csr.getString(csr.getColumnIndex(COL_USER_PASWWORD)));
rv.setCoins(csr.getInt(csr.getColumnIndex(COL_USER_COINS)));
rv.setGems(csr.getInt(csr.getColumnIndex(COL_USER_GEMS)));
}
csr.close();
return rv;
}
public User getUser(String email, String password) {
User rv = new User("-1","","","");
String whereclause = COL_USER_EMAIL + "=? AND " + COL_USER_PASWWORD + "=?";
String[] whereargs = new String[]{email,password};
Cursor csr = mDB.query(TBL_USER,null,whereclause,whereargs,null,null,null);
if (csr.moveToFirst()) {
rv.setId( String.valueOf(csr.getLong(csr.getColumnIndex(COL_USER_ID))));
rv.setName(csr.getString(csr.getColumnIndex(COL_USER_NAME)));
rv.setEmail(csr.getString(csr.getColumnIndex(COL_USER_EMAIL)));
rv.setPassword(csr.getString(csr.getColumnIndex(COL_USER_PASWWORD)));
rv.setCoins(csr.getInt(csr.getColumnIndex(COL_USER_COINS)));
rv.setGems(csr.getInt(csr.getColumnIndex(COL_USER_GEMS)));
}
csr.close();
return rv;
}
public User adjustCoinsAndOrGems(User u, int coins, int coin_adjustmode, int gems, int gem_adjustmode) {
ContentValues cv = new ContentValues();
User rv;
User user_fromDB = getUser(u.getId());
if (user_fromDB.id.equals("-1")) return u; // User not found so return
switch (coin_adjustmode) {
case User.ADJUSTTYPE_REPLACE:
cv.put(COL_USER_COINS,coins);
break;
case User.ADJUSTTYPE_ADD:
if (coins != 0) {
cv.put(COL_USER_COINS,user_fromDB.getCoins() + coins);
}
break;
case User.ADJUSTTYPE_MULTIPLY:
if (coins > 0) {
cv.put(COL_USER_COINS,user_fromDB.getCoins() * coins);
}
break;
case User.ADJUSTTYPE_DIVIDE:
if (coins > 0) {
cv.put(COL_USER_COINS,user_fromDB.getCoins() / coins);
}
break;
}
switch (gem_adjustmode) {
case User.ADJUSTTYPE_REPLACE:
cv.put(COL_USER_GEMS,gems);
break;
case User.ADJUSTTYPE_ADD:
if (gems != 0) {
cv.put(COL_USER_GEMS,user_fromDB.getGems() + gems);
}
break;
case User.ADJUSTTYPE_MULTIPLY:
if (gems > 0) {
cv.put(COL_USER_GEMS,user_fromDB.getGems() * gems);
}
break;
case User.ADJUSTTYPE_DIVIDE:
if (gems > 0) {
cv.put(COL_USER_GEMS,user_fromDB.getGems() / gems);
}
break;
}
if (cv.size() < 1) return u;
String whereclause = COL_USER_ID + "=?";
String[] whereargs = new String[]{u.getId()};
mDB.update(TBL_USER,cv,whereclause,whereargs);
return getUser(user_fromDB.getId());
}
public boolean authenticateUser(String email, String password) {
User u = getUser(email,password);
return (u.getLongId() > 0);
}
}
MainActivity.java
Very simple activity that starts the LoginActivity and when finally returned to does nothing (so you might as well kill the app).
public class MainActivity extends AppCompatActivity {
TextView mMessage;
DatabaseHelper mDB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMessage = this.findViewById(R.id.message);
mDB = new DatabaseHelper(this);
addSomeTestingUsers();
// Immediately start Login Activity
Intent i = new Intent(MainActivity.this,LoginActivity.class);
startActivity(i);
}
#Override
protected void onResume() {
super.onResume();
mMessage.setText("Welcome back");
}
private void addSomeTestingUsers() {
if (DatabaseUtils.queryNumEntries(mDB.getWritableDatabase(),DatabaseHelper.TBL_USER) > 0) return;
mDB.addUser("Fred","fred#fredmal.com","password");
mDB.addUser("Mary","mary#mary.email.com","password");
}
}
LoginActivity
This is pretty straightforward note that as it stands you have to Login and that the emails and passwords for the 2 users are coded in the MainActivity. When supplied correctly the HomeActivivty is started :-
public class LoginActivity extends AppCompatActivity {
public static final String INTENTKEY_USERNAME = "IK_USERNAME";
public static final String INTENTKEY_USERID = "IK_USERID";
public static final String INTENTKEY_STRINGUSERID = "IK_USERIDSTRING";
Button mloginbtn;
EditText mEmail,mPassword;
Context mContext;
DatabaseHelper mDB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mContext = this;
mloginbtn = this.findViewById(R.id.loginbtn);
mEmail = this.findViewById(R.id.email);
mPassword = this.findViewById(R.id.password);
mDB = new DatabaseHelper(this);
mloginbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
handleAuthentication();
}
});
}
private void handleAuthentication() {
if (mDB.authenticateUser(mEmail.getText().toString(),mPassword.getText().toString())) {
User u = mDB.getUser(mEmail.getText().toString(),mPassword.getText().toString());
Intent i = new Intent(mContext,HomeActivity.class);
i.putExtra(INTENTKEY_USERNAME,u.getName());
i.putExtra(INTENTKEY_USERID,u.getLongId());
i.putExtra(INTENTKEY_STRINGUSERID,u.getId());
startActivity(i);
finish();
}
}
HomeActivity
For brevity, this has been used to display the coins and gems, it to is pretty basic and relies upon methods in the DatabaseHelper to do much of the work.
public class HomeActivity extends AppCompatActivity {
TextView mUserameTextView, mUseridTextView, mCoinsTextView, mGemsTextView;
Button mAdd10Coins, mAdd10Gems,mDone;
User mUser;
long mUserid;
Context mContext;
DatabaseHelper mDB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mContext = this;
mDB = new DatabaseHelper(mContext);
mUserameTextView = this.findViewById(R.id.username);
mUseridTextView = this.findViewById(R.id.userid);
mCoinsTextView = this.findViewById(R.id.coins);
mGemsTextView = this.findViewById(R.id.gems);
Intent i = this.getIntent();
mUserid = i.getLongExtra(LoginActivity.INTENTKEY_USERID,-1);
mUser = mDB.getUser(mUserid);
refreshDisplay();
initButtons();
}
private void initButtons() {
mAdd10Coins = this.findViewById(R.id.add10coins);
mAdd10Coins.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mDB.adjustCoinsAndOrGems(mUser,10,User.ADJUSTTYPE_ADD,0,User.ADJUSTTYPE_ADD);
mUser = mDB.getUser(mUserid);
refreshDisplay();
}
});
mAdd10Gems = this.findViewById(R.id.add10gems);
mAdd10Gems.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mDB.adjustCoinsAndOrGems(mUser,0, User.ADJUSTTYPE_ADD,10,User.ADJUSTTYPE_ADD);
mUser = mDB.getUser(mUserid);
refreshDisplay();
}
});
mDone = this.findViewById(R.id.done);
mDB = new DatabaseHelper(mContext);
mDone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
});
}
private void refreshDisplay() {
mUseridTextView.setText(mUser.getId());
mUserameTextView.setText(mUser.getName());
mCoinsTextView.setText(String.valueOf(mUser.getCoins()));
mGemsTextView.setText(String.valueOf(mUser.getGems()));
}
}
enter image description hereFirst of all i want to say that my english isn't very good but i hope this is not a problem (i hope). So I wrote a code that "should" get user id from the user of my app but every time
firebase get other id on the same phone can someone help me with this problem ?
If you need more info, please write it in comments . Thank you in advance. Here my code .
EditText editTextName;
Button buttonAdd;
Spinner spinnerGenres;
DatabaseReference databaseArtists;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one_cent);
databaseArtists = FirebaseDatabase.getInstance().getReference("prousers");
editTextName = (EditText) findViewById(R.id.editTextName);
buttonAdd = (Button) findViewById(R.id.buttonAddArtist);
spinnerGenres = (Spinner) findViewById(R.id.spinnerGenres);
buttonAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addArtist();
}
});
}
private void addArtist(){
String name = editTextName.getText().toString().trim();
String genre = spinnerGenres.getSelectedItem().toString();
if (!TextUtils.isEmpty(name)){
String id = databaseArtists.push().getKey();
Artist artist = new Artist(id, name, genre);
databaseArtists.child(id).setValue(artist);
Toast.makeText(this, "You are a pro user :D", Toast.LENGTH_LONG).show();
finish();
System.exit(0);
}else{
Toast.makeText(this, "Something's wrong", Toast.LENGTH_LONG).show();
}
}
}
and this one too
public Artist(){
}
public Artist(String artistId, String artistName, String artistGenre) {
this.artistId = artistId;
this.artistName = artistName;
this.artistGenre = artistGenre;
}
public String getArtistId() {
return artistId;
}
public String getArtistName() {
return artistName;
}
public String getArtistGenre() {
return artistGenre;
}
}
I'm trying to do field validation for an int in android studio. The code for the field is as follows;
public class Register extends ActionBarActivity implements View.OnClickListener {
EditText etName, etAge, etUsername, etPassword;
Button bRegister;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
etName = (EditText) findViewById(R.id.etName);
etAge = (EditText) findViewById(R.id.etAge);
etUsername = (EditText) findViewById(R.id.etUsername);
etPassword = (EditText) findViewById(R.id.etPassword);
bRegister = (Button) findViewById(R.id.bRegister);
bRegister.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bRegister:
String name = etName.getText().toString();
String username = etUsername.getText().toString();
String password = etPassword.getText().toString();
String ageText = etAge.getText().toString();
if(! TextUtils.isEmpty(ageText)) {
int age = Integer.parseInt(ageText);
}
if(name.length()==0)
{
etName.requestFocus();
etName.setError("Please don't leave the name field empty.");
}else if(username.length()==0)
{
etUsername.requestFocus();
etUsername.setError("Please don't leave the username field empty.");
}else if(password.length()==0)
{
etPassword.requestFocus();
etPassword.setError("Please don't leave the password field empty.");
}/*else if(age == null)
{
etAge.requestFocus();
etAge.setError("Please don't leave the age field empty.");
}*/
else if(!name.matches("[a-zA-Z]"))
{
etName.requestFocus();
etName.setError("Please only use alphabetic characters");
}else{
User user = new User(name, age, username, password);
registerUser(user);
}
break;
}
}
private void registerUser(User user) {
ServerRequest serverRequest = new ServerRequest(this);
serverRequest.storeUserDataInBackground(user, new GetUserCallback() {
#Override
public void done(User returnedUser) {
Intent loginIntent = new Intent(Register.this, Login.class);
startActivity(loginIntent);
}
});
}
}
But I can't get the int age validated, it keps giving me this error;
java.lang.NumberFormatException: Invalid int: ""
User class
public class User {
String name, username, password;
int age;
public User(String name, int age, String username, String password) {
this.name = name;
this.age = age;
this.username = username;
this.password = password;
}
Try this:
String ageText = etAge.getText().toString();
int age = 0;
if(! TextUtils.isEmpty(ageText)) // If EditText is not empty
age = Integer.parseInt(ageText); // parse its content to integer
// Continue validation...
instead of
int age = Integer.parseInt(etAge.getText().toString());
I believe you are looking for something like this:
String ageString = "25"; //age will be null if it is empty or not a number
Integer age = null;
try {
age = Integer.parseInt(ageString);
} catch (NumberFormatException e) {}
if (age == null) {
//enter age
}
I have 2 EditText fields which are email and name. When the user clicks a button I get the value of those 2 fields in the AsyncTask onPreExecute() method. My question is how can I now pass that value to the doInBackground() method and insert it into the String Answers ? I have learned that you should not pass UI items into the doInBackground() . I have been searching on here and testing different variations of the code but keep getting Null values.
private class myprofile extends AsyncTask<String,Void,Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
Email= (EditText)findViewById(R.id.email);
String email= Email.getText().toString();
Name= (EditText)findViewById(R.id.name);
String name= Name.getText().toString();
}
#Override
protected Boolean doInBackground(String... params) {
String email = params[0];
String name = params[1];
String Answers="email="+email+"&name="+name;
return null;
}
// #Override
protected void onPostExecute(Boolean result) {
}
}
There are a lot of ways to do this. It looks like you're set up for passing them into execute().
1) Pass in to AsyncTask.execute()
String email= Email.getText().toString();
String name= Name.getText().toString();
new myprofile().execute(email, name);
2) Pass in to constructor
private class myprofile extends AsyncTask<Void,Void,Boolean> {
private String email;
private String name;
public myprofile(String email, String name){
this.email = email;
this.name = name;
}
...
}
String email= Email.getText().toString();
String name= Name.getText().toString();
new myprofile(email, name).execute();
3) Retrieve in onPreExecute()
private String email;
private String name;
protected void onPreExecute() {
super.onPreExecute();
email = Email.getText().toString();
name = Name.getText().toString();
}