I have implemented Sign In the method using Google Accounts, my problem is the logout function doesn't behave what I want. I don't receive any error, it's just the code doesn't work properly.
Can someone tell me what's wrong with this code?
Options Fragment:
Preference logoutPreference = findPreference(getString(R.string.pref_key_logout));
logoutPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
FirebaseAuth.getInstance().signOut();
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("com.example.budgetapp.ACTION_LOGOUT");
getActivity().sendBroadcast(broadcastIntent);
getActivity().startActivity(new Intent(getActivity(), SignInActivity.class));
getActivity().finish();
return true;
}
});
Main Activity:
#Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.budgetapp.ACTION_LOGOUT");
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
registerReceiver(receiver, intentFilter);
}
Why is the code not working? I'm using Firebase Realtime Database
Whenever I click Logout the app redirects me to Sign In Activity (which is good) but when I try to Sign In, it automatically signs in to the previous Google Account.
When you are using the following line of code:
FirebaseAuth.getInstance().signOut();
It means that you are signing out only from Firebase.
Whenever I click Logout the app redirects me to Sign In Activity (which is good) but when I try to Sign In, it automatically signs in to the previous Google Account.
As I understand, you are using the Google Provider for authentication. Signing out from Firebase doesn't mean that you are automatically signed out from Google. To sign out from Google you have to explicitly add a call to GoogleSignInClient#signOut() method:
googleSignInClient.signOut();
Don't also forget that the sign-out operation is asynchronous, meaning that you have to wait until the operation completes. Since this method returns an object of type Task<Void>, you can use addOnCompleteListener(OnCompleteListener listener) method, to know when you are completely signed out.
Related
I am trying to make an app with a login function and I want to keep the user logged in.
I'm using Firebase auth and android studio.
This is what I tried:
auth.signInWithEmailAndPassword(txt_email, txt_password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()){
Intent intent = new Intent(login.this, sendForm.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
}
else {
Toast.makeText(login.this, "cant sing in", Toast.LENGTH_SHORT).show();
}
}
});
First you need to check if the user exists when you log in to the app from second time. If the user exists you directly take him to the MainActivity else you'll take him to the LoginActivity.
So, your launchActivity should be something that is other then Login/Main activities. Typically, it would be a splash screen. So, let's say you're launch activity is SplashActivity.
Now, in your SplashActivity.java onCreate() do this:
FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
if (Objects.nonNull(currentUser)) {
// This means that user has already logged into the app once.
// So you can redirect to MainActivity.java
startActivity(new Intent(this, MainActivity.class));
} else {
// This means no user logged into the app before.
// So you can redirect to LoginActivity.java
startActivity(new Intent(this, LoginActivity.class));
}
If you don't want to use a SplashScreen, you can check for the user existence in LoginActivity.java using FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser(); and redirect him to MainActivity if currentUser is nonNull.
I want to keep the user logged in.
This is happening by default. There is nothing special that you need to do in order to keep your users logged in. They will be logged in until they explicitly sign out. Here is the official documentation for Android:
https://firebase.google.com/docs/auth/android/start/
If you want to keep track of the auth state, then please check my answer from the following post:
One time login in app - FirebaseAuth
Besides that, please also note that the state of being "signed in" doesn't depend on internet connectivity but on the user token currently in use, which is present locally and has not expired after one hour since the last refresh.
When I call mFirebaseAuth.signOut() or mFirebaseUser.delete() my FirebaseAuth.AuthStateListener() works correctly and returns null as FirebaseUser instance in onAuthStateChanged, I refresh UI and show "Sign in with Google" button.
But when I want to log in again, I don't see the dialog with users (I have 2 users on my device, attached the image). The app shows this dialog only in first sign in, after that it uses the same user. If I clear app's data on the settings screen I will be able to see this dialog again.
My question is how to show this dialog after every sign out.
I run this code when press Sign In button:
// in onCreate()
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
// in OnClickListener
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, FirebaseActivity.REQUEST_SIGN_IN);
In onActivityResult(), I get an instance of GoogleSignInResult so everything I need happens after I call startActivityForResult().
In the Firebase Auth Quickstart sample code, the sign-out for Google provider includes these steps. Are you calling GoogleSignInClient.signOut() when you sign-out?
private void signOut() {
// Firebase sign out
mAuth.signOut();
// Google sign out
mGoogleSignInClient.signOut().addOnCompleteListener(this,
new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
updateUI(null);
}
});
}
Another option is to use the FirebaseUI library. It simplifies sign in and sign out operations in a sense that it will do all the heavy lifting for you.
Kotlin
AuthUI.getInstance().signOut(this).addOnCompleteListener {
// do something here
}
Java
AuthUI.getInstance()
.signOut(ActivityMainOld.this)
.addOnCompleteListener(new OnCompleteListener<Void>(){
#Override
public void onComplete(#NonNull Task<Void> task) {
// do something here
}
});
Hope this helps
I was confused since all of the solutions required having a reference to the GoogleSignInClient, but it is actually not required for you to hold a reference to it, you can simply create a new instance and call signOut() on it.
GoogleSignIn.getClient(
getContext(),
new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).build()
).signOut();
For anyone else who wants this result (as in getting the google account options back) on a different activity.
public static void signOut() {
// Firebase sign out
mAuth.signOut();
// Google sign out
Auth.GoogleSignInApi.signOut(mGoogleApiClient);
}
Add this on the sign in page, and before you pass to the next activity, just call SignOut().
// everything ok...
signOut();
startActivity(new Intent(SignIn.this,NextOne.class));
and then, in your other class you can call
FirebaseAuth.getInstance().signOut();
startActivity(new Intent(NextClass.this, SignIn.class));
It's easy, and it will work. Cheers!
You can also define something like this:
private void signOut() {
mAuth.signOut();
mGoogleSignInClient.signOut().addOnCompleteListener(this,
new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Intent intent = new Intent(YourActivity.this, NextActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
});
}
None of the above did fix the issue for me,
accepted answer requires access to mGoogleApiClient defined in login view (normally log out button is in settings view)
another answer was suggesting to logout in the login view (after successful login and just before launching to the main view). This was addressing the mGoogleApiClient accessibility issue, but the issue with this approach is every time user opens the app it ends up in login view and requires to log in every time which is not ideal.
So here is what I ended up doing and it is kind of all-round fix that support all the third-party log out options (in my case Facebook and Google)
logOutButton.setOnSingleClickListener {
FirebaseAuth.getInstance().currentUser?.getIdToken(false)?.addOnSuccessListener {
result ->
when (result.signInProvider){
"facebook.com" -> {
LoginManager.getInstance().logOut()
signOutFromApp()
}
"google.com" -> {
GoogleSignIn.getClient(
this,
GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).build()
).signOut()
signOutFromApp()
}
else -> {
signOutFromApp()
}
}
}
}
private fun signOutFromApp() {
FirebaseAuth.getInstance().signOut()
LauncherActivity.start(this) //starts login view
finish() //finish settigs view
}
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 did mGoogleSignInClient.signOut()
this is working as expected.
you can set a custom parameter for the GoogleAuthProvider to force user to re authenticate via google.
var provider = new Firebase.auth.GoogleAuthProvider();
provider.setCustomParameters({
prompt: 'select_account'
});
Use same instances of Firebase Auth and GoogleSignInClient,
for example, If we declared and instantiated a Firebase Auth called mAuth in LoginActivity,
Then if we declare a new mAuth in other activity and try to call mAuth.login, it will not work properly.
Make Firebase Auth and GoogleSignInClient variables public and static and use the same from the other activities
For flutter use,
await GoogleSignIn().signOut();
await _auth.signOut();
How can I open Main Activity if user taps on push notification sent from OpenSignal. I wanted to override the default behaviour which was causing some issue when App was active. I added following line as per the doc
<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT" android:value="DISABLE" />
Now if app is closed, how can i open MainActivity, and let it execute NotificationOpenedHandler.
Thank you.
If you still always want your launcher / main Activity to open / resume when tapping on a OneSignal notification add the following code to your Activity intead.
private static boolean activityStarted;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ( activityStarted
&& getIntent() != null
&& (getIntent().getFlags() & Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
finish();
return;
}
activityStarted = true;
}
See Resume last Activity when opening a Notification instructions for more details.
If you need to do something more custom keep the manifest entry you noted above and add a OneSignal NotificationOpenedHandler to OneSignal.startInit in your Application class.
import com.onesignal.OneSignal;
public class YourAppClass extends Application {
#Override
public void onCreate() {
super.onCreate();
OneSignal.startInit(this)
.setNotificationOpenedHandler(new ExampleNotificationOpenedHandler())
.init();
}
// This fires when a notification is opened by tapping on it or one is received while the app is running.
private class ExampleNotificationOpenedHandler implements NotificationOpenedHandler {
#Override
public void notificationOpened(String message, JSONObject additionalData, boolean isActive) {
// The following can be used to open an Activity of your choice.
/*
Intent intent = new Intent(getApplication(), YourActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
*/
// Follow the instructions in the link below to prevent the launcher Activity from starting.
// https://documentation.onesignal.com/docs/android-notification-customizations#changing-the-open-action-of-a-notification
}
}
See 4. Add Optional NotificationOpenedHandler for more details on this callback.
I am working on a messaging app, it sends user notification when he is on a different activtyon my app or is on another app but if the user is on MessagingActivity.java it just updates the chat history and does not send any notifications which is perfectly fine, but the problem arises when the user is on MessagingActivity.java meanwhile an email or something else happen user leaves the MessagingActivity.java open and checks that app if in the meantime a message comes user does not receive any notifications
public void parseRequest(Bundle extras) {
if (extras.containsKey("for") && extras.containsKey("recipientID")) {
if (Integer.parseInt(extras.getString("recipientID")) == M.getID(this)) {
switch (extras.getString("for")) {
case "chat":
if (isRunning("MessagingActivity")) {
Intent intent = new Intent("update_messages_list");
intent.putExtra("data", extras);
sendBroadcast(intent);
} else {
Intent resultIntent = new Intent(this, MessagingActivity.class);
resultIntent.putExtra("conversationID", Integer.parseInt(extras.getString("conversationID")));
resultIntent.putExtra("recipientID", Integer.parseInt(extras.getString("ownerID")));
M.showNotification(getApplicationContext(), resultIntent,
extras.getString("ownerUsername"),
extras.getString("message"),
Integer.parseInt(extras.getString("conversationID")));
}
Let me know how you are checking that your MessageActivity is Running i.e. functioning of isRunning("MessagingActivity") method. If you are setting any global boolean variable for checking this and making isRunning value false in onDestroy() method of that activity then, according to life cycle of Activity it is not called until your activity is finished i.e. in your case user just switching from MessageActivity to Mail .
I am by no means an expert, but you could just set a boolean variable by overriding the Activity's onPause() and onResume() events.
Simply set msgActivityActive to true in onResume(), false in onPause(), and change your call to:
if (isRunning("MessagingActivity") && msgActivityActive)
I'm trying to simply set a proximity later for an area an for testing, I simply added this to the onCreate method of my main activity.
public void onCreate(Bundle bndBundle) {
IntentFilter filter = new IntentFilter(WidgetService.ACTION_STOP_PROXIMITY);
registerReceiver(new ProximityIntentReceiver(), filter);
LocationManager locManager = (LocationManager) this.getSystemService(LOCATION_SERVICE);
Intent ittIntent = new Intent(this, ProximityIntentReceiver.class);
ittIntent.putExtra(WidgetService.KEY_STOP_IDENTIFIER, 1000);
PendingIntent pitIntent = PendingIntent.getBroadcast(this, 0, ittIntent, 0);
locManager.addProximityAlert(60.15769, 24.94150, 150, -1, pitIntent);
super.onCreate(bndBundle);
getActionBar().setDisplayHomeAsUpEnabled(false);
}
..and here's the simple receiver class that I'm using
public class ProximityIntentReceiver extends BroadcastReceiver {
private static final int NOTIFICATION_ID = 1000;
#Override
public void onReceive(Context context, Intent intent) {
String key = LocationManager.KEY_PROXIMITY_ENTERING;
Boolean entering = intent.getBooleanExtra(key, false);
if (entering) {
Log.d(getClass().getSimpleName(), "entering");
}
else {
Log.d(getClass().getSimpleName(), "exiting");
}
}
}
I'm testing this on my emulator and when I use the DDMS console to set the co-ordinates of the phone manually, I still don't see the log message.
My manifest file doesn't have any special code. I've added the correct permissions and have the code for a simple activity- no services or anything.
I read through a whole bunch of posts on StacKOverflow but I haven't been able to resolve the issue. Am I missing something in my snippet?
You are registering this receiver dynamically, through registerReceiver(), to have it respond to broadcasts whose action string is WidgetService.ACTION_STOP_PROXIMITY.
However, the actual broadcast you are sending is trying to use an explicit Intent, identifying your receiver class. This does not line up with the IntentFilter that you are using with registerReceiver().
Either:
Register your receiver in the manifest and get rid of registerReceiver(), in which case your explicit Intent will work, or
Use new Intent(WidgetService.ACTION_STOP_PROXIMITY) instead of new Intent(this, ProximityIntentReceiver.class), so your Intent lines up with your IntentFilter
You cannot use explicit Intent objects to send broadcasts to receivers registered via registerReceiver(). An explicit Intent will only work with a manifest-registered receiver.
make sure you type in the right coordinates. in DDMS they're reversed, longitude first, then latitude