I am creating an app on Android that uses Firebase as database and Batch for pushing notifications. Usually, when my app starts, it goes to the main page, a login activity. The activity verifies if a user is still logged in using:
Firebase dbRef = new Firebase(Constants.URL_DB);
AuthData auth = dbRef.getAuth();
if (auth != null) // Proceed with a logged in user
else // Show authentication layout
My problem is that when I get a notification from Batch, I click on the notification to go to the app but then I am not logged in as I should be... auth == null. I don't want my users to need to log in every time they get a push from Batch. Can I detect that the app started from a notification? How is that I lose authentication from Firebase?
Here is the onCreate and onResume of the MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initiating Batch
Batch.onStart(this);
// Initiating layout
setContentView(R.layout.login);
// Setting database
Firebase.setAndroidContext(this);
// Unrelated stuff done here (Setting Views, etc)
}
#Override
protected void onResume() {
super.onResume();
// Getting login information from previous authentication.
Firebase dbRef = new Firebase(Constants.URL_DB);
AuthData auth = dbRef.getAuth();
// I added the addAuthStateListener here
if (auth != null) {
goToHomePage();
}
}
All right I found the problem. When I click on the notification, my MainActivity is called obviously. The thing is that when the user is logged in successfully, I start another Activity using:
startActivityForResult(intent, Constants.SUCCESS);
Now, onActivityResult is normally called to log out the user when the back button has been pressed on the home page. Otherwise, onResume is called and since the user is logged in, I would go straight back to the home page. BUT: when I click on a notification, somehow onActivityResult is called (probably because the activity stack gets trashed) and the user is logged out before resuming the activity.
So the solution is to log out the user in the onBackPressed of the home page activity. Then I don't need to startActivityForResult anymore.
// In the home page activity
#Override
public void onBackPressed() {
super.onBackPressed();
Firebase dbRef = new Firebase(Constants.URL_DB);
dbRef.unauth();
finish();
}
Related
Code of my splash screen:
public class SplashScreen extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
Thread thread = new Thread() {
public void run() {
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
Intent intent = new Intent(SplashScreen.this, FirstSlider.class);
startActivity(intent);
finish();
}
}
};
thread.start();
}
}
I want to move directly to my mainActivity if user already exist.
I'm using phone number to to sign in user in firebase android ,how can i keep user signed in until user sign out?
This is actually the default behavior of Firebase Authentication: it persists the user credentials and restores them when the app restarts.
So by the time your main activity executes the FirebaseAuth.getInstance().getCurrentUser() should already be returning the restored user account. If that is not happening, consider listening to the authentication state to ensure your code executes after the user is restored.
If neither of these is working for you, edit your question to show the relevant code - as none of the code you shared now seems to call Firebase in any way.
i have tried on completion listener , but i want to check when i press the close sesion button if there is no data left to upload, my problem is that when i press close sesion and go to my loginActivity again, data is still uploading to firebase, so i get a null error because it cant reach the user to post the last data, what i want to do is to put a listener on the close sesion button where i can check if that user id is done with uploads
button.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
//here i want to test if the user has finished uploading all before sign out
FirebaseAuth.getInstance().signOut();
mGoogleApiClient.disconnect();
finish();
}
});
return true;
}
});
You don't need to wait untill Firebase finish uploading to the database, you need to use a DatabaseReference.CompletionListener.
This interface is used as a method of being notified when an operation has been acknowledged by the Database servers and can be considered complete
This means that once your data was successfully writen on Firebase database server, then you can sign out.
I am able to log in and do export/import from my Android app using the v2 Dropbox API. The only problem is on first run when a token is requested and the Dropbox app/website is launched - I have to run Auth.startOAuth2Authentication at least twice with a pause in between to be able to read the token with Auth.getOAuth2Token.
Is there anyway to wait() and get notified when startOAuth2Authentication returns after acquiring a token?
Auth.startOAuth2Authentication(this, getString(R.string.app_key));
//wait for response, retry, or time out and finish
String accessToken = Auth.getOAuth2Token();
prefs.edit().putString(ACCESS_TOKEN, accessToken).commit();
You shouldn't call startOAuth2Authentication twice, and you shouldn't call getOAuth2Token immediately after calling startOAuth2Authentication.
You should start the flow by calling startOAuth2Authentication as shown in the example here:
https://github.com/dropbox/dropbox-sdk-java/blob/master/examples/android/src/main/java/com/dropbox/core/examples/android/UserActivity.java#L36
And then you should complete the flow by calling getOAuth2Token later in onResume as shown in the example here:
https://github.com/dropbox/dropbox-sdk-java/blob/master/examples/android/src/main/java/com/dropbox/core/examples/android/DropboxActivity.java#L22
Here is a simple example for implementing the Dropbox Android API:
https://www.sitepoint.com/adding-the-dropbox-api-to-an-android-app/
Now, to get to the point of your question, you will not be able to get a toke immediately after Auth.startOAuth2Authentication(this, getString(R.string.app_key)); is called. After you call this method, the Dropbox login activity is shown, and you can get the token only after the user logs in (which is in no way immediate, and you have no way of telling how long it will take).
After the user logs in successfully your activity will be resumed, and you can see in the example from the tutorial that the Activity's onResume method is overridden a check is performed in there.
I will copy below the LoginActivity from this tutorial. It should be easy enough to start from here:
public class LoginActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Button SignInButton = (Button) findViewById(R.id.sign_in_button);
SignInButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
Auth.startOAuth2Authentication(getApplicationContext(), getString(R.string.APP_KEY));
}
});
}
#Override
protected void onResume() {
super.onResume();
getAccessToken();
}
public void getAccessToken() {
String accessToken = Auth.getOAuth2Token(); //generate Access Token
if (accessToken != null) {
//Store accessToken in SharedPreferences
SharedPreferences prefs = getSharedPreferences("com.example.valdio.dropboxintegration", Context.MODE_PRIVATE);
prefs.edit().putString("access-token", accessToken).apply();
//Proceed to MainActivity
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
}
}
}
I'm developing a small android app, and basically so far it just has login and logout functionality. I'm using Firebase to store user data and also for authentication.
So I have login working and it authenticates users as it should and I have logging out working in the sense that it unauthenticates users. But is there anything I have to do from within the app to kill the session?
if (id == R.id.action_log_out) {
ref.unauth(); //End user session
startActivity(new Intent(MainActivity.this, LoginActivity.class)); //Go back to home page
finish();
}
Will this work as I think it should? Obviously if someone logs out they shouldn't be able to hit th back button and magically go back to the last page without re-logging in.
From Firebase docs
https://firebase.google.com/docs/auth/android/custom-auth
call this FirebaseAuth.getInstance().signOut();
When Firebase authenticates the user (or you authenticate the user with Firebase), it stores the token for that user in local storage on your device. This happens when you call one of the authWith... methods (of course only if it successfully authenticates the user).
Calling ref.unauth(); immediately deletes that token from local storage.
A properly implemented flow would not automatically re-authenticate them when the user presses the back button, but that depends on the flow you implement (which is missing from your question and would likely be too much code anyway).
I see 2 options for the issue we have with the back-Button after Logout:
In your LoginActivity, wich should be you launcher activity, Override onBackPressed Method and leave it empty:
#Override
public void onBackPressed() {
// empty so nothing happens
}
Or/and you can add the LoginActivityIntent in your LogoutActivty if user == null.
This way, whenever a not authenticated user lands on the activity, it will redirect to the LoginActivity instantly, although this looks kinda weird.
mAuth = FirebaseAuth.getInstance();
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
} else {
// User is signed out
Log.d(TAG,"onAuthStateChanged:signed_out");
startActivity(new Intent(LogoutActivity.this, LoginActivity.class));
}
// ...
}
};
First Option is easier, but I guess if you apply both your on the save side ^^ Im coding for 2 weeks now so correct me if im wrong.
You can replace finish() with finishAffinity();
Delete tokens and Instance IDs
String authorizedEntity = PROJECT_ID;
String scope = "GCM";
FirebaseInstanceID.getInstance(context).deleteToken(authorizedEntity,scope);
You can also delete the Instance ID itself, including all associated tokens. The next time you call getInstance() you will get a new Instance ID:
FirebaseInstanceID.getInstance(context).deleteInstanceID();
String newIID = InstanceID.getInstance(context).getId();
private void sendToLogin() { //funtion
GoogleSignInClient mGoogleSignInClient ;
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
mGoogleSignInClient = GoogleSignIn.getClient(getBaseContext(), gso);
mGoogleSignInClient.signOut().addOnCompleteListener(/*CURRENT CLASS */.this,
new OnCompleteListener<Void>() { //signout Google
#Override
public void onComplete(#NonNull Task<Void> task) {
FirebaseAuth.getInstance().signOut(); //signout firebase
Intent setupIntent = new Intent(getBaseContext(), /*To ur activity calss*/);
Toast.makeText(getBaseContext(), "Logged Out", Toast.LENGTH_LONG).show(); //if u want to show some text
setupIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(setupIntent);
finish();
}
});
}
this code is written to work as copy past just read COMMENTS in code to customize it to ur needs, i prefer to send user to login
I have problem with code below. I try to log in with facebook to my app, when I use app with Activities this code works, but when I change it to Fragments it's stops work. When I first click on fb button I'm redirect to fb login but when I give username and pass, it doesn't go to onUserInfoFetched metod and doesn't directed me to ScreenFragment, and stay on the first fragment, and when I click the fb login button again in logcat shows me info "NOT_WORK" so user is null.
Could you help me with this?
loginBtn.setReadPermissions(permissions);
loginBtn.setUserInfoChangedCallback(new LoginButton.UserInfoChangedCallback() {
#Override
public void onUserInfoFetched(GraphUser user) {
if (user != null) {
getActivity().getFragmentManager().beginTransaction().
replace(android.R.id.content, new ScreenFragment()).addToBackStack(null).commit();
} else {
Log.d("FB", "NOT_WORK");
}
}
});
If you're using Fragments, you need to call
loginBtn.setFragment(this);
from within your Fragment implementation, and also override the onActivityResult method in your Fragment and pass it to the loginBtn.