Decide which activity to start from a subclass of Application - java

I have a simple application in which before I do anything, I must check whether the user is logged in or not.
To do this, I inherited the Application class like this:
public class GBApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
if (userIsLoggedIn()) {
Intent overviewActivity = new Intent(this, Overview.class);
overviewActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(overviewActivity);
}
}
}
userIsLoggedIn() returns a boolean stored in the SharedPreferences file.
Everything works, but when I press back from the Overview activity, it redirects me to the default activity (MainActivity), and removing it from the AndroidManifest.xml files gives error.
Also, I can't call finish() since this is a non activity class.
How can I terminate my program after I return from the Overview class? I found solutions where they pass a value to the MainActivity, call finish() from there. But this seems to complicated.
What else I can do?
This is my application tag in AndroidManifest.xml

Your plan is going to cause problems. Every time your process is created, you are starting an activity, even if an activity is not needed for this particular process.
Displaying a launcher activity — such as in response to the user tapping on a home screen launcher icon — is one way that a process might be created for your app. But there are many others:
AlarmManager
JobScheduler
a Notification
a push message (e.g., from Firebase Cloud Messaging)
a request sent to a ContentProvider that you export from your app
a request sent to a Service that you export from your app
a manifest-registered BroadcastReceiver
the user returning to your task in the overview screen
and so on
In none of those scenarios is displaying this activity necessarily appropriate. Yet, your code will display the activity in all of them, because any time Android forks a process for your app, you display this activity.
Have all of your activities (other than the login one) see if the user is logged in, and route the user to the login activity if that is needed. When the user completes the login, and the login activity finishes, the user is returned to where they were trying to go, whether that is your launcher activity or some other activity (e.g., they returned to your task after your app had been in the background for a while, so your process was terminated, but Android tries to send them back to whatever activity of yours they had been in last).

You could simply override the onBackPressed() of your overviewActivity and pilot the direction your app goes when the back button is pressed (which in your case is to shut down the app):
#Override
public void onBackPressed(){
startActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
}
The code above just shuts down your app immediately the back button is clicked once (which is pretty boring.. but simple). You could also try the code snippet below; it pops up a dialogue box:
#Override
public void onBackPressed(){
new AlertDialog.Builder(this)
.setMessage("Are you sure you want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int id){
startActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
}
})
.setNegativeButton("No", null)
.show();
}

Related

How do I override onBackPressed to ensure a logged out user cannot "go back" to MainActivity, and a logged in user cannot "go back" to SignInActivity?

Background: I have a SignInUserActivity and a MainActivity. The SignInUserActivity is first presented to the user when the user has not signed in or the auth token expired. On successful login, the user is directed to MainActivity, or if the auth token is valid on open of app the user will directed to MainActivity when the user opens the app. The user can sign out from MainActivity which will direct the user back to SignInUserActivity.
1) User signs in from SignInUserActivity. When user pressed onBackPressed in SignInUserActivity, the app should close (or move to background)>
2) After the user signs in, user should NOT be able to go back to the SignInUserActivity by onBackPressed enough times or navigateUp button on toolbar, onBackPressed should ONLY close the app (or move it to background). Currently, I have
#Override
public void onBackPressed() {
super.onBackPressed();
finish();
}
in my MainActivity, yet
3) If the user signs out from MainActivity, in SignInUserActivity, onBackPressed should not direct the user back to MainActivity (with empty data since the session was already deleted). Currently the way I'm handling it is redirecting the user back to SignInUserActivity:
public void handleRedirect(String sessionId) {
if (sessionId == null) {
Intent requireSignInIntent = new Intent(this, SignInUserActivity.class);
startActivity(requireSignInIntent);
}
}
but instead it should be overriding onBackPressed?
It seems your problem can easily be resolved by starting a new Activity Stack. Just add this when you start SignInActivityand when you navigate to other Activity after a succefull log in
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
This flags should cover your 1st and 2nd problem. As for the 3rd problem, it seems you're doing the logic well but I didn't quite get that last part.

How can I prevent a user from pressing the back button, because if the user does it closes the application and restarts it from the first activity

Hey guys I'm currently developing an application for my final project, the concept is a contact keeping app but with user login and registration. When the user enters their credentials and presses the login button it starts an Intent to move to another page, on this Intent I end it with the .finish() method so the user can't go back but when that is executed and lets say by accident the user presses the physical back button on the device the application will close and if you try to open it again by going on the multitask physical button on the device and you select it, it starts the application again from the beginning (the login screen) how can i make it that if the users presses it by accident they can open it again from the multitask or the physical icon of the application so the it picks up on where it left at (the display activity after you login it) essentially not restarting the application.
Is that even possible?
Thanks in advance
Override onBackPressed() in your activity and remove super.onBackPressed().
#Override
public void onBackPressed() {
// super.onBackPressed();
}
First of all to stop device default back key event you have to remove super.onBackPressed() from onBackPressed() of activity
#Override
public void onBackPressed() {
// super.onBackPressed();
}
Now to keep the flow management after login, you have to save the activity name or any other value to SharedPreferences so whenever you come again to the application you will make a check for last activity after login. And navigate to the same.
SharedPreferences preferences = getSharedPreferences("AppName", Activity.MODE_PRIVATE);
Editor editor = preferences.edit();
//add this to onCreate of the activity where you want to come directly
editor = editor.putString("LAST_ACTIVITY", "MULTITASK_ACTIVITY/*Navigated activity name*/").commit();
Now make a check on app start in loading screen:
if(preferences.getString("LAST_ACTIVITY", "").equalsIgnorCase("MULTITASK_ACTIVITY")){
//Navigate to Mutitask activity
}else{
//Navigate to other activity
}

Check whether an activity is active or not from a different activity

I have a flow in my application like this:
For new users:
Splash Screen --> Login Activity --> Home Activity
For already registered users:
Splash Screen --> Home Activity
Basically the Splash Screen has an if else to decide which activity to go to. Once a first time user logs in, his status is saved in a preference variable for the splash screen to decide next time not to open the login activity.
Now the situation is that. If a new user logs in and goes to the home activity, and then logs out. He is redirected to the Login screen which is pretty much what should happen. But, in case an existing user opens the app, he is shown the Splash screen and directly moved to the Home Activity. Now if the user logs out, he gets out of the app. This happens because the Login Activity does not have any instance created and thus finishing the Home Activity finishes the whole app. Logout actually finishes the Home Activity, naturally the last active activity should open up. Which is not happening.
What I want to do is that, I want to implement a logic which will check that the Login Activity is available or not. If its available then finish() will be called else the Login Activity will be called via intent.
Please tell me how to achieve this.
P.S: My app uses a custom theme with a customized action bar. If I call finish and Intent together or I use flags to clear existing activities then there is a weird transition effect which shows the black standard action bar for a split second thus creating a bad user experience.
Now if the user logs out, he gets out of the app. This happens because
the Login Activity does not have any instance created and thus
finishing the Home Activity finishes the whole app.
If i understood your question, why dont you just call the Login Activity manually after user click a logout button?
Its what i always did with apps that have flow like yours
when user login finish login activity and start home activity.
when user logout finish home activity and start login activity
You always can call Login Activity via intent. If the activity is available, android will show this activity. Else android will create new activity automatically.
Actually that's why we use intents to show activity instead of creating activityes manually. System catches this intents and does all dirty work.
EDIT:
Hmm, but wouldn't you have the transition problem anyways? (If you were already logged in, and then log out - using intent/finish() you will have the same black action bar issue no?)
Maybe consider following ( I actually did this in my app):
Merge Splash screen and Login into one activity and depending whether you are logged in - display the login fields or proceed to home screen. Then you have a out of box consistent stack of activities regardless of use cases and no mambo-jumbo with do I already have this or not.
I can't comment because of I lack 4 rep, so I'll post as answer here:
I think #Blaze Tama is right. You can also use FLAG_ACTIVITY_CLEAR_TOP on intent to avoid stack flow problems:
From docs:
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
Always start Login activity and start Home activity right away if the user already logged in.
In the Splash Screen activity
Intent intent = new Intent(this, Login.class);
If (user already logged in)
{
intent.putextra("Logged in", true);
}
startActivity(intent);
In the Login activity
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Intent intent = getIntent();
if (intent != null)
{
if (intent.getBooleanExtra("Logged in", false))
{
startActivityForResult(new Intent(this, Home.class), requestCode);
}
}
else
{
// The existing code here
}
}
In Home activity send back a code to indicate if the user logged out or just BackPress. If BackPress finish this Login activity.

App won't close after finish() [duplicate]

This question already has answers here:
How to exit from the application and show the home screen?
(22 answers)
Closed 5 months ago.
So, I'm trying to create an app which have a function like an alarm clock for Android phones, it will alert the user at their chosen time. When the alert screen show up, the user has an option to push a notification or snooze, and the app will push a notification and then close.
However, when I click the snooze or the notification button, the app did not close. Instead, the app stop the alarm sound and minimized (just as when the user touch the home button). If I touch the recent app, I then can open the alert screen again.
Edit: I know that there're some codes such as System.exit() or killProcess, since those code are not recommended, I prefer avoid using them.
The reason I ask is because I tested the real clock app that come with my phone (4.3), and the it's alert screen will close after the I press the snooze or dismiss button. So there must be a way for me to do the same, right ?
Answer
Okay, so as Sagar Pilkhwal explained below, and after reading others related problems, I found out that there's no "good" method to close you app by codes, you have to leave that option to the users or OS. Unless you want to use System.exit or killProcess, but they're bad ways to force your app to close.
Sagar Pilkhwal also have a alternatively method to this problem, if you don't want your alert screen show up in recent app, you bring up another activity.
However, as for this case and Alarm Manager in general, open MainActivity will lead to nasty stuffs, since MainActivity is when we handle Alarm events. Then I found out another solution, if you don't want your alert screen show up in recent app, simply add
android:excludeFromRecents="true"
to your Alert.class Activity in the Manifest, or add Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTSto the intent used to start Alert.class.
This will lead to other problem, as when the user press the Home button, the alarm won't turn off, and the user can't open recent app to access the alert screen (he'll has to open the app to do so). I fix this problem by try to detect the home button pressed event. Detail answer are below.
well im thinknig.
System.exit(0);
maybe? im new to android thou..but i sometimes use it..
Put the following to Manifest, in your Alert activity :
android:excludeFromRecents="true" //this will make the Activity be exclude from recents list.
You can also add android:launchMode="singleInstance" and android:taskAffinity="" (if you know what they do)
In the Alert class, use this to detect home button pressed event:
#Override
public void onPause() {
if (!isFinishing()) {
createNotf(); //Handle home button press here.
}
super.onPause();
}
Use this to handle back button pressed: (You have to have this code if you want to detect home button press using isFinishing();
#Override
public void onBackPressed() {
//Handle BackButton event here.
}
For my case only, when the user press home button, I will create a notification, so he can either click on the notification or open the app again to access to Alert Screen.:
private void createNotf() {
Intent screenIntent = new Intent(MyAlert.this, MyAlert.class);
screenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
screenIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
PendingIntent pIntent = PendingIntent.getActivity(MyAlert.this, MainActivity.SEND_ALARM_CODE, screenIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Notification.Builder ntfBuilder = new Notification.Builder(this)
.setAutoCancel(true)
.setContentTitle("ALARM_RUNNING")
.setLargeIcon(bitmap)
.setSmallIcon(R.drawable.ic_launcher)
.setContentText("CLICK_TO_OPEN_ALERTSCREEN.")
.setContentIntent(pIntent);
NotificationManager myNotfM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
myNotfM.notify(999, ntfBuilder.build());
}
When the Alert stop, that notification will also be clear:
#Override
public void onDestroy() {
super.onDestroy();
NotificationManager mntfM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mntfM.cancel(999);}
System.exit(0);
That right there will close your application out leaving nothing running in the background.However,use this wisely and don't leave files open, database handles open, etc.These things would normally be cleaned up through the finish() command.
I personally HATE when I choose Exit in an application and it doesn't really exit.

How to cancel notification in onDestroy function

i want to make a notification like BBM connected notification (for android)...
so when i open my app, the notification will appear, and it cant be canceled...
so i use this code
nm=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification=new Notification(android.R.drawable.stat_notify_more, "this is important", System.currentTimeMillis());
notification.flags = notification.FLAG_NO_CLEAR; //notification never dissapear
Context context=MainActivity.this;
CharSequence title="hello there";
CharSequence detail="this is demo";
Intent intent=new Intent(context,MainActivity.class);
PendingIntent pending=PendingIntent.getActivity(context, 0, intent, 0);
notification.setLatestEventInfo(context, title, detail, pending);
nm.notify(0, notification);
i put that code in public void onCreate(Bundle savedInstanceState)...
so, the notification cant cancel when i click or slide.
and when i close my app, the notification still there.
then i have an idea to use this code :
#Override
protected void onDestroy() {
nm.cancelAll();
}
but, this function never called???
how can i cancel the notification when i close the app?
It might be because onDestroy will not be called immediately when you navigate away with the home button.
Android has callback methods available that work well with notifications etc.
These are called onUserLeaveHint() and onUserInteraction().
The JavaDoc for onUserLeaveHint() states:
Called as part of the activity lifecycle when an activity is about to
go into the background as the result of user choice. For example, when
the user presses the Home key, onUserLeaveHint() will be called, but
when an incoming phone call causes the in-call Activity to be
automatically brought to the foreground, onUserLeaveHint() will not be
called on the activity being interrupted. In cases when it is invoked,
this method is called right before the activity's onPause() callback.
This callback and onUserInteraction() are intended to help activities
manage status bar notifications intelligently; specifically, for
helping activities determine the proper time to cancel a notfication.
I'd suppose you will want to override either one of these; especially onUserLeaveHint() seems a good choice for your purpose.
#Override
protected void onUserLeaveHint()
{
nm.cancelAll();
super.onUserLeaveHint();
}
You can't intercept the event of 'force closing' the application process. Android doesn't support this. When the user does this, the system calls Process.killProcess(int pid) and all resources will be freed. It's just not possible to catch this event and perform tasks before the process is really killed. Maybe a workaround is possible, but it wouldn't be how Android wants it.
There is no guarantee that the method will called. If application will not have enough memory, it can be killed by OS.
There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
You missed the super.onDestroy
#Override
protected void onDestroy() {
nm.cancelAll();
super.onDestroy();
}

Categories