what are the appropriate launchMode and intent flag? - java

I'm working with an android application that has three activities A(Splash Screen) B(login) C(Home)
My app works as following:
1-A(Splash Screen)->B(login): in the splash screen I check if the user is not logged in, start new B(login) activity
2-A(Splash Screen)->C(Home): in the splash screen I check if the user is logged in, start new C(Home) activity
3-C(Home)->B(login): in home activity the user can logged out, start new B(login) activity
4-Notificatioin->C(Home): when the user opens a notification from the notification area, starts new activity C(home)
Every thing is working fine except
assume that I'm in C(home)1 ,when I open a notification a new C(home)2 activity is created then when I logged out new B(login) activity is also created, However when I pressed back button C(home)1 is opened.
what is the appropriate launchMode or flag intent for each activity?

For this type of flow you can use some of the following suggestions
Firstly, if you want to create only a single instance of the activity try using single top property in the manifest file.
<activity>
...
android:launchMode="singleTop"
...
</activity>
Secondly, if you you want your user to only access the current activity and don't return to previously opened activity then you can use intent filters while opening a new activity as mentioned here. For instance following flags will clear all of the back stack end the current activity and user will not be able to access any of the previously opened activities.
Intent intent = new Intent(this,Login.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
For more help on managing your tasks and activities you can refer here.

Related

Opening Android app using notification & getLaunchIntentForPackage doesn't go through LauncherActivity

I am using Firebase (FCM) to show Push Notifications to the user and I am running into a weird problem.
The code I have works for the following scenarios (using FirebaseMessagingService):
App in foreground - Receiving data in onReceive() and showing a popup inside app.
App in background - Receiving data in onReceive() and showing a notification for the user. If this is clicked the app will be brought back to front. The intent from this is received in LauncherActivity followed by a finish() call which takes me to whatever activity I already had open.
App completely closed - same as background. App will be started and intent will be handled in LauncherActivity before calling finish() on that.
And here is where it gets interesting:
App completely closed -> open it through notification (intent received in LauncherActivity) -> put the app in background and send another notification -> when this notification is clicked the LauncherActivity is completely ignored (onCreate is no longer called) and I get taken straight to whatever activity I already had. The intent here has no extras or categories.
Why is LauncherActivity being bypassed in this specific case? Keep in mind that this works fine if the app was initially started normally (not by clicking on a notification)
Intent mainIntent = getPackageManager().getLaunchIntentForPackage(getPackageName());
if (mainIntent != null) {
mainIntent.addCategory(NOTIFICATION_CATEGORY);
mainIntent.putExtra(.........);
}
PendingIntent pendingMainIntent = PendingIntent.getActivity(this, SERVICE_NOTIFICATION_ID, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, context.getString(R.string.default_notification_channel_id));
notificationBuilder.setContentIntent(pendingMainIntent);
//.....icon, color, pririty, autoCancel, setDefaults, setWhen, setShowWhen, contentText, setStyle
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
getString(R.string.default_notification_channel_id),
getString(R.string.default_notification_channel),
NotificationManager.IMPORTANCE_HIGH
);
notificationManager.createNotificationChannel(channel);
notificationBuilder.setChannelId(getString(R.string.default_notification_channel_id));
}
notificationManager.notify(SERVICE_NOTIFICATION_ID, notificationBuilder.build());
}
I'd appreciate any ideas. Thank you.
When you launch an app for the first time, Android remembers the Intent that was used to launch it. Normally, when you launch an app from the HOME screen, this is an Intent that contains ACTION=MAIN and CATEGORY=LAUNCHER. If your app then goes to the background (for whatever reason), and the user later taps the icon on the HOME screen, the same launch Intent is used. Android matches this against the Intent used to launch the app for the first time, and if these match, Android doesn't launch a new Activity, it just brings the task containing the app from the background to the foreground in whatever state it was in when it got moved to the background. Under normal circumstances, this is exactly the behaviour that you want (and that the user expects).
However, when the app is launched for the first time from a Notification, this can mess things up. In your case, this is what you are seeing. You launch the app from a Notification and Android remembers the Intent used (from the Notification), when you later launch the app (again from a Notification), android matches the Intent in the Notification with the Intent used to launch the app for the first time, and thinks you want to bring the existing app task from the background to the foreground.
There are several ways to deal with this, depending on the behaviour that you want to have. The best thing to do is probably not to launch your root Activity (the one with ACTION=MAIN and CATEGORY=LAUNCHER) from the Notification. Instead launch a different Activity and have that Activity determine what it should do next (ie: redirect to the root Activity or something else, depending on the state of your app). You should also set the NO_HISTORY and EXCLUDE_FROM_RECENTS flags on the Intent that you put in the Notification. This will ensure that Android won't remember this Intent as the one that launched the app.

What is the difference between available "close Android application" code?

I have an application and the launcher activity is a login activity. I want the user to be able to close the app in another activity and when he opens it again the application to start again from the login activity (in other words to close the app and not just send it to background).
I have found a lot of ways to close an app:
1.finish();
2. Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
3. finishAffinity();
4. finishAndRemoveTask();
5. System.exit(0);
and combinations of the above. Which one is more efficient? What is the best practice?
Use whichever one you like. System.exit(0) probably is the most efficient, being a system method that directly exits the JVM running your app.

Launcher Activity overlaps notification tap activity in Android

I have implemented notification in android application, Everything is working as expected. I am getting one problem to open activity after tapping on notification or action button from the notification.
Process:
Kill the application instance from the background that means application should not run in the background.
Send the notification from the FCM, Tap or click on the action from the notification. Open the activity named "B". In application, there is one Main activity + Splash activity which loads when the application is getting started fresh (Application was not running in the background).
Problem: When the application is not running in the background. If I click on the notification, I can see that Activity "B" opens but overlap by my Splash+Main Activity. If I press back from the main activity then I can see my activity B. I am not able to find any lead or solution from the internet. In short, when application is not active in the background in that case my launcher activity (main+splash) and Activity B both are trying to start together and main activity starts late as it's checking some login/authentication/session related things.
What is the solution in this case?
Thanks for your time.
EDIT
Intent defaultClickIntent = new Intent(context, B.class);
defaultClickIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
 | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
PendingIntent pendingIntent = PendingIntent.getActivity(context, notificationId, defaultClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Android how to create notification that resumes activity instead of starting a new onw

So I've read the varios SO questions about this and I'ved tried to implement what they said and it doesnt work. When the notification is pressed i want it to pull back to the activity without clearing any of the EditTexts or turning off the toggle button. I.e resuming the activity from its last state. But so far my code doesnt work.
Intent myIntent = new Intent(this,Locator.class);
PendingIntent pendingIntent
= PendingIntent.getActivity(getBaseContext(),
0, myIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP),
Intent.FILL_IN_DATA);
myNotification.defaults |= Notification.DEFAULT_SOUND;
myNotification.defaults |= Notification.DEFAULT_VIBRATE;
myNotification.flags |= Notification.FLAG_AUTO_CANCEL;
The Android OS is solely responsible for managing the lifecycle of an Activity and can kill an Activity at any time, thus there is no way to specify resume activity. The OS will bring the requested activity to the top of the stack if it is still in memory; if the activity has been killed, it will be launched again and any saved state passed to it.
See Recreating an Activity
maybe
<activity name="your activity" android:launchMode="singleInstance" />
is what you want. If activity not destroyed and in background, then it will appear, instead creating new.

Login activity problem

Im currently developing an application for android, the first screen of the application is the LoginActivity, it is authenticating with facebook and a facebook login dialog is shown on users request. The whole login process is working great, when you have logged in user are brought to a new activity. I've created a logout function in that activity which logging the user out of facebook in the whole application, but. If you press the "back-button" on an android device when the user is at the activity where you are when you have logged in the loginactivity is shown for the user. I want to make it impossible for the user to show the loginactivity but i don't know how. When the user successfully logging in from the beggining the following lines are runned:
Intent intent = new Intent().setClass(LoginActivity.this, LocationActivity.class);
startActivity(intent);
And when the user successfully logged out from the MainActivity the following lines are runed:
ApplicationController appController = (ApplicationController)getApplicationContext();
appController.setfullnametoNull();
appController.setuseridtoNull();
finish();
Any suggestions on how to make it impossible for the user to get to the loginactivity when the user is currently logged in?
finish() the activity and if the user navigates to other app without log out then you should check in the login activity when comes back to app and redirect the user to appropriate activity. You need to save the login credentials for this. You can use SharedPreferences for this.
Use an broadcast intent which you send from the activity you start after the login activity. Then use the login activity as the receiver of the broadcast intent. Then you can use this broadcast to call finish() for the login activity. This way the login activity should get out of the android activity stack.
Not sure if I understood your question correctly... you are saying after you logged in and another Activity is started the user hits the back button and the activity is shown again?
If yes: you can prevent this with starting the activity using startActivityForResult(intent, REQUEST_CODE) instead of using startActivity(intent).
Then you have to add this method:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
finish();
}
}

Categories

Resources