resuming an activity from a notification - java

I have a notification in the status bar for my app:
Notification notification = new Notification(R.drawable.icon, null, System.currentTimeMillis());
Intent notificationIntent = new Intent(this.parent, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this.parent, 0, notificationIntent, 0);
...
notification.flags = Notification.FLAG_ONGOING_EVENT;
mNotificationManager.notify(NOTIFICATION_ID, notification);
The problem with this is that when you press the home button from the app (pushing it to the background) then press on the notification in the list accessed from the status bar, it starts a fresh copy of the activity. All I want to do is resume the app (like when you longpress the home button and press on the app's icon). Is there a way of creating an Intent to do this?

I've solved this issue by changing the launchMode of my activity to singleTask in the androidManifest.xml file.
The default value for this property is standard, which allows any number of instances to run.
"singleTask" and "singleInstance" activities can only begin a task. They are always at the root of the activity stack. Moreover, the device can hold only one instance of the activity at a time — only one such task. [...]
The "singleTask" and "singleInstance" modes also differ from each other in only one respect: A "singleTask" activity allows other activities to be part of its task. It's always at the root of its task, but other activities (necessarily "standard" and "singleTop" activities) can be launched into that task. A "singleInstance" activity, on the other hand, permits no other activities to be part of its task. It's the only activity in the task. If it starts another activity, that activity is assigned to a different task — as if FLAG_ACTIVITY_NEW_TASK was in the intent.
you can find a detailed explanation in the Android Developers' Guide
I hope this helps

I was having a similar problem and the proper way to handle this is to use the flags: Intent.FLAG_ACTIVITY_CLEAR_TOP and Intent.FLAG_ACTIVITY_SINGLE_TOP like so
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
From the documentation this will:
FLAG_ACTIVITY_CLEAR_TOP
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.
FLAG_ACTIVITY_SINGLE_TOP
If set, the activity will not be launched if it is already running at the top of the history stack.

I had inconsistent behaviour between devices with some intents loosing extras and the MainActivity´s OnNewIntent and onCreate methods both being called.
What did not work:
Manifest:
<activity android:name=".MainActivity"
android:launchMode="singleTask">
Service:
Intent notificationIntent = new Intent(this.getBaseContext(), MainActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
notificationIntent.putExtra("TEST", 1);
What did work:
Manifest:
<activity android:name=".MainActivity"
android:launchMode="singleTask">
Service:
PackageManager pm = getPackageManager();
Intent launchIntent = m.getLaunchIntentForPackage(BuildConfig.APPLICATION_ID);
launchIntent.putExtra("TEST", 2);

I have just found a solution this issue: I created getPreviousIntent method and gave it to PendingIntent that`s all:
private Intent getPreviousIntent(Intent newIntent) {
final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final List<ActivityManager.RecentTaskInfo> recentTaskInfos = am.getRecentTasks(1024,0);
String myPkgNm = getPackageName();
if (!recentTaskInfos.isEmpty()) {
ActivityManager.RecentTaskInfo recentTaskInfo;
for (int i = 0; i < recentTaskInfos.size(); i++) {
recentTaskInfo = recentTaskInfos.get(i);
if (recentTaskInfo.baseIntent.getComponent().getPackageName().equals(myPkgNm)) {
newIntent = recentTaskInfo.baseIntent;
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
}
}
return newIntent;
}

Add this line to the corresponding activity in manifest file of your app.
android:launchMode="singleTask"
eg:
<activity
android:name=".Main_Activity"
android:label="#string/title_main_activity"
android:theme="#style/AppTheme.NoActionBar"
android:launchMode="singleTask" />

You can simulate a launch intent (as if the user clicked on your app icon to launch it):
val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)
val contentIntent = PendingIntent.getActivity(context, 0, launchIntent, 0)
This way, you do not have to mark your app as "singleTask" or "singleInstance" in Manifest (which would create other issues). Thus this should be the proper solution.
Note, however, the above solution may not work directly for you, due to an alleged android bug. Discussions about the android bug and a workaround can be found in this question.

I use:
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
notificationIntent.setAction(Intent.ACTION_MAIN);
Not sure these are the values you need to set, but the answer is in those methods/flags.

Related

Destroy activity when creating the same activity

I have 2 activities A and B, A is defined as "singletask" on the manifest launch mode, as it should be and i cannot change this. A launches activity B, then when B clicks the back button i want to launch activity A again, but i want to destroy the previous activity, and create a new instance of A. right now the following code is not working. It just takes me back to the old A activity.
<activity
android:name="A"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="#style/AppTheme" />
public void onBackPressed() {
Intent intent = new Intent(this,A.class);
intent.putExtra("newextra1","newextra1");
intent.putExtra("newextra2","newextra2");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}
Just call finish() in Activity A after you call the intent for Activity B. It will be executed even if another Intent is started before calling finish().
You are calling finish() in Activity B but not Activity A.
if you want the old activity in some cases and new in some, then just pass a flag(boolean) in intent that tells the activity to restart or not. Then if the flag is yes you do
finish();
startActivity(getIntent());
in Activity A.
Try:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

How can I add homescreen shortcut for app after installing

How can I add shortcut of my application to Android homescreen before I lauch app?
I need it added right after installation of app.
if you publish your app in google play store after installing app auto-create shortcut but if you want to handle that Android provides us an intent class com.android.launcher.action.INSTALL_SHORTCUT which can be used to add shortcuts to the home screen. In following code snippet we create a shortcut of activity MainActivity with the name HelloWorldShortcut.
First, we need to add permission INSTALL_SHORTCUT to android manifest XML.
<uses-permission
android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
The addShortcut() method creates a new shortcut on the Home screen.
private void addShortcut() {
//Adding shortcut for MainActivity
//on Home screen
Intent shortcutIntent = new Intent(getApplicationContext(),
MainActivity.class);
shortcutIntent.setAction(Intent.ACTION_MAIN);
Intent addIntent = new Intent();
addIntent
.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "HelloWorldShortcut");
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(getApplicationContext(),
R.drawable.ic_launcher));
addIntent
.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
addIntent.putExtra("duplicate", false); //may it's already there so don't duplicate
getApplicationContext().sendBroadcast(addIntent);
}
Note how we create shortcut Intent object which holds our target activity. This intent object is added into another intent as EXTRA_SHORTCUT_INTENT.
Finally, we broadcast the new intent. This adds a shortcut with the name mentioned as EXTRA_SHORTCUT_NAME and icon defined by EXTRA_SHORTCUT_ICON_RESOURCE.
Also put this code to avoid multiple shortcuts :
if(!getSharedPreferences(Utils.APP_PREFERENCE, Activity.MODE_PRIVATE).getBoolean(Utils.IS_ICON_CREATED, false)){
addShortcut();
getSharedPreferences(Utils.APP_PREFERENCE, Activity.MODE_PRIVATE).edit().putBoolean(Utils.IS_ICON_CREATED, true);
}

using intent flags and androidmanifest

I have a service that starts an activity (say Activity A) as follows:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
getApplicationContext().startActivity(intent);
when I start my app, Activity A appears instead before the app's first activity.
I had 2 solutions to work this around:
1)
changing the above code to:
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY
| Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
problem:
after launching the activity and pressing home-key, I still see the activity in the history stack (=recent tasks). how come?
after I launch my app, the two tasks merge into one with the app's first activity at the top. but any other app, create a new task and the task of Activity A remains. how come?
2)
changing the above code to:
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY
| Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
and adding to the manifest:
<activity
android:name="org.achartengine.GraphicalActivity"
android:taskAffinity="org.achartengine"
>
where Activity A = android:name="org.achartengine.GraphicalActivity"
problem:
I keep unnecessary task stack.
I assume few people start that activity from the service. And even then they will do it only once. Meaning it would be more neat to clean the activity from any history stack when the user clicks home/back key.
which of the options is preferred? (or another one?)
A quick fix is adding android:launchMode="singleTop" to the activity in the manifest, that way there will only be one and not multiple instances. The other way to accomplish the same thing is to use the following just prior to starting the intent.
Intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
There are a couple of other possibilities to try in the manifest put
android:noHistory="true"
and make sure your are calling
finish();
to end that intent.
for the activity or a combination of these 2 intent flags
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP
If the above doesn't work, the last thing I can think of is
moveTaskToBack(true);
which doesn't solve the problem.
Hope this helps.
This is a method that will keep the first activity off your stack.
Thread nohistory = new Thread () {
public void run () {
try {
Intent i = new Intent(Splash.this, ActivitySplash.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
} catch (Exception e) {
e.printStackTrace();
}
}
};
nohistory.start();

Remove all activities except the first one

I want to program Home button, so it will remove all Activities in stack, except one. I did it like in here: How to finish every activity on the stack except the first in Android
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
switch (itemId) {
case android.R.id.home:
Intent intent = new Intent(this, AMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
break;
...
but this way doesn't suit me, because it removes ALL Activities (including the first one) and starts the first one again. For example - if I check user password in onCreate(), he would be asked again.
How to remove all Activities from stack, but so the first one will not be "touched" ?
add following property to your AMainActivity's Activity tag in your manifest.xml.
android:launchMode="singleTop"
Yes, according to the documentation of Intent.FLAG_ACTIVITY_CLEAR_TOP:
The currently running instance of activity B in the above example will either receive the new intent you are starting here in its onNewIntent() method, or be itself finished and restarted with the new intent. If it has declared its launch mode to be "multiple" (the default) and you have not set FLAG_ACTIVITY_SINGLE_TOP in the same intent, then it will be finished and re-created; for all other launch modes or if FLAG_ACTIVITY_SINGLE_TOP is set then this Intent will be delivered to the current instance's onNewIntent().
So, use additional Intent flag:
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
And your activity should not be recreated. Instead, it will just get the new intent delivered via a call to onNewIntent().
You can use ExcludeFromRecent = "true" flag in Activities declaration in manifest, which you don’t want to be in Stack.

Finish all previous activities

My application has the following flow screens :
Home->screen 1->screen 2->screen 3->screen 4->screen 5
Now I have a common log out button in each screens
(Home/ screen 1 / screen 2 /screen 3/ screen 4 / screen 5)
I want that when user clicks on the log out button(from any screen), all the screens will be finished and a new screen Log in will open .
I have tried nearly all FLAG_ACTIVITY to achieve this.
I also go through some answers in stackoverflow, but not being able to solve the problem.
My application is on Android 1.6 so not being able to use FLAG_ACTIVITY_CLEAR_TASK
Is there any way to solve the issue ?
Use:
Intent intent = new Intent(getApplicationContext(), Home.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
This will clear all the activities on top of home.
Assuming you are finishing the login screen when the user logs in and home is created and afterward all the screens from 1 to 5 on top of that one. The code I posted will return you to home screen finishing all the other activities. You can add an extra in the intent and read that in the home screen activity and finish it also (maybe launch login screen again from there or something).
I am not sure but you can also try going to login with this flag. I don't know how the activities will be ordered in that case. So don't know if it will clear the ones below the screen you are on including the one you are currently on but it's definitely the way to go.
You may try Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK. It will totally clears all previous activity(s) and start new activity.
Before launching your new Activity, simply add the following code:
finishAffinity();
Or if you want it to work in previous versions of Android:
ActivityCompat.finishAffinity(this);
When the user wishes to exit all open activities, they should press a button which loads the first Activity that runs when your application starts, clear all the other activities, then have the last remaining activity finish. Have the following code run when the user presses the exit button. In my case, LoginActivity is the first activity in my program to run.
Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("EXIT", true);
startActivity(intent);
The above code clears all the activities except for LoginActivity. Then put the following code inside the LoginActivity's onCreate(...), to listen for when LoginActivity is recreated and the 'EXIT' signal was passed:
if (getIntent().getBooleanExtra("EXIT", false)) {
finish();
}
Why is making an exit button in Android so hard?
Android tries hard to discourage you from having an "exit" button in your application, because they want the user to never care about whether or not the programs they use are running in the background or not.
The Android OS developers want your program to be able to survive an unexpected shutdown and power off of the phone, and when the user restarts the program, they pick up right where they left off. So the user can receive a phone call while they use your application, and open maps which requires your application to be freed for more resources.
When the user resumes your application, they pick up right where they left off with no interruption. This exit button is usurping power from the activity manager, potentially causing problems with the automatically managed android program life cycle.
I guess I am late but there is simple and short answer.
There is a finishAffinity() method in Activity that will finish the current activity and all parent activities, but it works only in Android 4.1 or higher.
For API 16+, use
finishAffinity();
For below 16, use
ActivityCompat.finishAffinity(YourActivity.this);
Hope it helps!
Intent intent = new Intent(this, classObject);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
This Will work for all Android versions. Where IntentCompat the class added in Android Support library.
Use the following for activity
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
remove CLEAR_TASK flag for fragment use.
I hope this may use for some people.
On a side note, good to know
This answer works (https://stackoverflow.com/a/13468685/7034327)
Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
this.finish();
whereas this doesn't work
Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
.setFlags() replaces any previous flags and doesn't append any new flags while .addFlags() does.
So this will also work
Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
From developer.android.com:
public void finishAffinity ()
Added in API level 16
Finish this activity as well as all activities immediately below it in the current task that have the same affinity. This is typically used when an application can be launched on to another task (such as from an ACTION_VIEW of a content type it understands) and the user has used the up navigation to switch out of the current task and in to its own task. In this case, if the user has navigated down into any other activities of the second application, all of those should be removed from the original task as part of the task switch.
Note that this finish does not allow you to deliver results to the previous activity, and an exception will be thrown if you are trying to do so.
If your application has minimum sdk version 16 then you can use finishAffinity()
Finish this activity as well as all activities immediately below it in the current task that have the same affinity.
This is work for me In Top Payment screen remove all back-stack activits,
#Override
public void onBackPressed() {
finishAffinity();
startActivity(new Intent(PaymentDoneActivity.this,Home.class));
}
http://developer.android.com/reference/android/app/Activity.html#finishAffinity%28%29
In my case I use finishAffinity() function in last activity like:
finishAffinity()
startHomeActivity()
Hope it'll be useful.
A solution I implemented for this (I think I found it on Stack Overflow somewhere, but I don't remember, so thanks to whoever did that in the first place):
From any of your activities do this:
// Clear your session, remove preferences, etc.
Intent intent = new Intent(getBaseContext(), LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Then in your LoginActivity, overwrite onKeyDown:
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
moveTaskToBack(true);
return true;
}
return super.onKeyDown(keyCode, event);
}
For logout button on last screen of app, use this code on logout button listener to finish all open previous activities, and your problem is solved.
{
Intent intent = new Intent(this, loginScreen.class);
ntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
Intent i1=new Intent(getApplicationContext(),StartUp_Page.class);
i1.setAction(Intent.ACTION_MAIN);
i1.addCategory(Intent.CATEGORY_HOME);
i1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
i1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i1);
finish();
i have same problem
you can use IntentCompat , like this :
import android.support.v4.content.IntentCompat;
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
this code work for me .
Android api 17
instead of using finish() just use finishAffinity();
Log in->Home->screen 1->screen 2->screen 3->screen 4->screen 5
on screen 4 (or any other) -> StartActivity(Log in) with FLAG_ACTIVITY_CLEAR_TOP
for API >= 15 to API 23
simple solution.
Intent nextScreen = new Intent(currentActivity.this, MainActivity.class);
nextScreen.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(nextScreen);
ActivityCompat.finishAffinity(currentActivity.this);
If you are using startActivityForResult() in your previous activities, just override OnActivityResult() and call the finish(); method inside it in all activities.. This will do the job...
When user click on the logout button then write the following code:
Intent intent = new Intent(this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
And also when after login if you call new activity do not use finish();
I guess I am late but there is simple and short answer. There is a finishAffinity() method in Activity that will finish the current activity and all parent activities, but it works only in Android 4.1 or higher.
For API 16+, use
finishAffinity();
For below 16, use
ActivityCompat.finishAffinity(YourActivity.this);
Hope it helps!
shareedit
answered May 27 '18 at 8:03
Akshay Taru
Simply, when you go from the login screen, not when finishing the login screen.
And then in all forward activities, use this for logout:
final Intent intent = new Intent(getBaseContext(), LoginScreen.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
It works perfectly.
If you log in the user in screen 1 and from there you go to the other screens, use
Intent intent = new Intent(this, Screen1.class);
intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
I found this way, it'll clear all history and exit
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
Intent intent = new Intent(getApplicationContext(), SplashScreen.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
System.exit(0);
I found this solution to work on every device despite API level (even for < 11)
Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
ComponentName cn = intent.getComponent();
Intent mainIntent = IntentCompat.makeRestartActivityTask(cn);
startActivity(mainIntent);
Best way to close all the previous activities and clear the memory
finishAffinity()
System.exit(0);
I have tried the flags on my end and still haven't worked. I have an application with a very similar design and I have a possible solution in terms of logic. I have built my Login and Logout using shared preferences.
If I logout, data in my shared preferences is destroyed/deleted.
From any of my activities such as Home.java I check whether shared preferences has data and in this case it won't because I destroyed it when I logged out from one of the screens. Therefore logic destroys/finishes that activity and takes me back to the Login activity. You can replicate this logic in all your other activities.
However remember to perform this check inside onPostResume() because this is what is called when you go back to Home.java
Code Sample Below:
#Override
protected void onPostResume() {
SharedPreferences pref = this.getSharedPreferences("user_details", Context.MODE_PRIVATE);
if (pref.getAll().isEmpty()){
//Shared Preferences has no data.
//The data has been deleted
Intent intent = new Intent(getApplicationContext(), Login.class);
startActivity(intent);
finish();
//Finish destroys that activity which in our case is the Home.java
}
super.onPostResume();
}
In Kotlin this way:
in Another Activity (with some classes), under Imports
var activity:Activity?=null
get() = field
set(value) {
field = value
}
Then, under onCreate
activity=this
in MainActivity now:
activity?.finish()

Categories

Resources