Cannot start market activity with CLEAR_TOP flag - android

Consider this code snippet that prompts the user to rate the app on the market:
private void backToMainActivity() {
Intent i = new Intent(mActivity, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
mActivity.startActivity(i);
mActivity.finish();
}
...
if (mRateToast.leftClicked(x, y)) {
setRate(true);
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + GameGlobals.PACKAGE_NAME));
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | Intent.FLAG_ACTIVITY_NEW_TASK);
mActivity.startActivity(i);
backToMainActivity();
} else if (mRateToast.rightClicked(x, y)) {
setRate(false);
backToMainActivity();
}
What this does is detect what button was pressed (Rate or Later), set a flag accordingly and run the market app if needed. No matter which button is pressed, I want to return to the main menu (this is a game activity, 1 activity away from the main menu activity).
On Android 4.1, this works fine - the market opens to the app's page, and on return from the market, I am on the main menu. On android <= 2.3, the market does not open, I am just returned directly to the main menu. It does, however, open if I comment the i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); in the backToMainActivity method. This causes other problems though, such as the back button going back to the wrong activity instead of exiting the app, so is not a solution.
How can I run the market, return to main menu and have the main menu activity be at the top of the activity stack?
Note: I haven't tried it, but removing the finish is also not really an option. My game activity can also be started by external applications directly, and in that case, if I remove the finish call, for some reason CLEAR_TOP will not work, and pressing the back button on the main menu activity will return to the game activity instead of exiting the application.

try this
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + GameGlobals.PACKAGE_NAME));
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | Intent.FLAG_ACTIVITY_NEW_TASK);
mActivity.startActivityForResult(i,1552);
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==1552){
backToMainActivity();
}
}

I solved this by removing Intent.FLAG_ACTIVITY_NEW_TASK and using startActivityForResult as described by MoshErsan in his answer. Apparently starting the market as a new task does not play well with CLEAR_TOP in android <= 2.3.
If someone can explain why the original approach wasn't working or offer a better solution, I will accept that answer in one or two days, if not I will accept mine.

Related

How to close an Android app from non-root activity by pressing the backbutton

The functionality I want to model in my Android app is, that if the user does login, he gets forwarded to the main menu (MainMenuActivity). From here and everywhere else where I provide a button for it in the app, he must be able to logout, which should send him back to the login screen (LoginActivity) and finish all the activities above on the stack. I achieve this by not destroying the LoginActivity after a login and at logout calling:
Intent intent = new Intent(this, LoginActivity.class);
// Clean up all other activities.
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Also I want that the user can not go back with the backbutton form the main menu to the loginscreen. So I did overwrite the method onBackPressed() in my MainMenuActivity. Instead I want that when the user is pressing the backbutton from the main menu, the app does terminate (just like its the last activity on the stack). How can I achieve this?
I did read about several other approaches, for example finishing the LoginActivity after the login was performed and then later do it like described here:
https://stackoverflow.com/a/3008684/1332314
But I'm not quite sure if this is a proper solution, just read the comments below the post.
use this flag when you move to MainMenuActivity:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
this will delete all the previous activity and if you press back app will be closed.
Now in case of logout button do the same thing when you move to LoginActivity same flag will now make LoginActivity as the only activity on the stack and on back app will be closed.
Apparently I did find a solution to my problem. I just start the MainMenuActivity from the LoginActivity like this:
private void continueToMainMenu() {
Intent intent = new Intent(this, MainMenuActivity.class);
startActivityForResult(intent, 0);
}
Then, when the user presses the backbutton in the main menu, this overwritten function gets called:
public void onBackPressed() {
setResult(LoginActivity.ACTION_QUIT);
finish();
}
This will at first set a resultcode for the LoginScreen and then finish the MainMenuActivity. Then the LoginActivity does terminate receiving this particular resultcode, which I implemented like this:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == LoginActivity.ACTION_QUIT)
{
finish();
}
}
Doing it this way will ensure not to touch too deep into the activity lifecycles, all the callbacks to clean up will still be called and it should not open any security leaks.
Hope this helps if anyone else will bump into the same issue.

Android Start Activity for Result returns different resultCode

There are a lot of questions out there on similar topics, but after searching around I haven't found one that matches my issue.
I know about starting intents for result, and overriding onActivityResult() to handle these intents, but for some reason, I'm having issues when I'm coming back from activity b to activity a. So, for example, in the last of 3 activities (AddDirections class) I start in my project, I call this method to return back to the previous activity:
public void finish(View v){
Intent intent = new Intent(getApplicationContext(), AddIngredients.class);
intent.putExtra(Home.RECIPE_INTENT, (Parcelable)recipe);
intent.putExtra(Home.RECIPE_ID_INTENT, recipe.getId());
setResult(RESULT_OK, intent);
finish();
}
In the AddIngredients class, I have this method:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK && requestCode == DIRECTIONS_REQUEST){
Intent intent = new Intent(getApplicationContext(), NameRecipe.class);
Recipe recipe = data.getParcelableExtra(Home.RECIPE_INTENT);
intent.putExtra(Home.RECIPE_INTENT, (Parcelable)recipe);
setResult(RESULT_OK, intent);
finish();
}
}
This should accept the returned result from the AddDirections class, and pass it off to NameRecipe, where I have the exact same method (Except for in the new Intent method it says Home.class). In the Home class, I have basically the same method again to receive the intent as it backs all the way out of the app.
Now, I will say that this works if I go straight through the steps from beginning to end. But if I use the up navigation to go the current activity's parent activity, then it messes everything up. Then when I click finish in the final step it messes up the resultCodes that I set for each intent. I make sure to explicitly set the correct result to RESULT_OK (which equals 1) but then for some reason, sometimes it changes what I've set to be the resultCode to be 0 instead.
Here's what I do in an activity if the user clicks the up navigation:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent intent = NavUtils.getParentActivityIntent(this);
intent.putExtra(Home.RECIPE_INTENT, (Parcelable)recipe);
setResult(RESULT_OK, intent);
NavUtils.navigateUpTo(this, intent);
finish(); //Have tried with and without this
return true;
}
return super.onOptionsItemSelected(item);
}
Like I said, I've searched for a lot of reasons why the resultCode gets overwritten after using the up navigation, but I haven't found a single reason why.
Any help would be greatly appreciated.
It looks like the underlying question is really how do I navigate between multiple activities through the stack using the up navigation that is built in. I am wondering if the project is setup correctly for this type of navigation. From the android developer resources, up navigation from google, you have to setup the navigation buttons with a parent activity. Then the application can traverse between the different activities. From what it looks like this should allow A->B B->C c->D and back to A if needed. I would also add in a button that would allow a direct path back to A if the user so chooses.
If you have more information on what you are trying to accomplish between activities whether it is data passed back and forth or just returning to the previous activity that would be helpful. Hopefully the link will help your issue with this.
your problem seems to be the NavUp, this util class tends to clear everything to navigate to the parent including your resultCode and the instance of the activity, resulting in a Canceled result (if started for result) to a new instance of the parent activity, in order to fix that a quick fix would be to declare android:launchMode="singleTop" in your manifest, but I wouldn't recommend to use that unless you are 100% that you want that, instead I would go into my navigator class, or my method for navigate and overwrite that specific navigation to something like:
Intent parentActivityIntent = NavUtils.getParentActivityIntent(this);
parentActivityIntent.setFlags(
Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP
);
NavUtils.navigateUpTo(this, parentActivityIntent);
Hope this helps!!
Sorry for the late answer :p
if by 'up navigation' you mean back key pressed then you need to override a function
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
}
if from what it seems to be you are trying to get back when clicking an item from the Options Menu to your parent activity directly then i think you will need to go back step by step as at this moment there is already an activity running and waiting for a result so when you go directly to home activity its already waiting an answer from activity B and not activity C i hope i explained it right :)

Android 2.2 (API 8) Logging Out

I have an app that will have multiple activities open.
Activity A -> Activity B -> Activity C
I want to logout and close all open activities. I have read many different links that describes how to do this.
On logout, clear Activity history stack, preventing "back" button from opening logged-in-only Activites
Close all running activities in an android application?
The issue for this however is that the Intent Flags only work with API level 11 and above. I have an app that I would like to be made available for API level 8 and above. I know that it goes way back but what is the best way to accomplish this for API level 8?
Or should I just give in and make the minimum level 11?
Intent intent = new Intent(this, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);``
Did you try this ?
void signOut() {
Intent intent = new Intent(this, HomeActivity.class);
intent.putExtra("finish", true);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // To clean up all activities *not necessary*
startActivity(intent);
finish();
}
from this answer
Okay, you can do one thing get ProcessID of your application and in onDestroy() kill that process. Thats it from this link How to force stop my android application programmatically?
int pid=android.os.Process.myPid();
android.os.Process.killProcess(pid);
you can use alternative told by one of user here using startActivityForResult() and onActivityResult() works fine even on API level 8.
For this u need to use
startActivityForResult() instead of startActivty. and onActivtyResult() for you work.
you say "I want to logout and close all open activities." , Intent.FLAG_ACTIVITY_CLEAR_TOP works on API Level 8 , I have incorporated Logout functionality ,that way in app that is already in store, but there is one difference if I understand you correctly , logout goes to LoginActivity , logout does not kill process or something as this goes against concept of Android. Anyway you can even do this also when you do this as suggested above:
void logout() {
Intent intent = new Intent(this, LoginActivity.class);
intent.putExtra("finish", true);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
And then in LoginActivity you can search for "finish" boolean in extra in onCreate method and finish that activity too.
#Override public void onCreate(Bundle state) {
super.onCreate(state);
if (getIntent().getBooleanExtra("finish", false)) finish();
}

Selecting and launching shortcuts from a non-launcher app

What I would like to do is the following:
User selects a shortcut from a list of all available shortcuts in the system;
The relevant info is stored;
User performs an action and the selected shortcut is executed, like if it was an icon on the home screen.
So far I am able to populate and present a list with all the shortcuts, using
getPackageManager().queryIntentActivities(new Intent(Intent.ACTION_CREATE_SHORTCUT), 0);. Upon selecting a shortcut, I start the ACTION_CREATE_SHORTCUT intent to customize the shortcut parameters - it presents the proper UI and seems to work. I use this code to start the intent:
ActivityInfo activity = resolveInfo.activityInfo;
ComponentName name = new ComponentName(activity.applicationInfo.packageName, activity.name);
Intent i = new Intent(Intent.ACTION_CREATE_SHORTCUT);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
i.setComponent(name);
startActivityForResult(i, 1);
Here is my onActivityResult:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode==1 && resultCode == RESULT_OK) {
try {
startActivity((Intent) data.getExtras().get(Intent.EXTRA_SHORTCUT_INTENT));
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(), "Success!!", Toast.LENGTH_LONG).show();
finish();
}else{
Toast.makeText(getApplicationContext(), "Fail: "+resultCode+" "+resultCode, Toast.LENGTH_LONG).show();
}
super.onActivityResult(requestCode, resultCode, data);
}
Now, the problem is that the onActivityResult always gets triggered immediately after startActivityForResult with requestCode=0, resultCode=0 and with no data. It does not trigger when the ACTION_CREATE_SHORTCUT activity actually ends. I really don't get it. I think that after the activity ends it should return the requestCode I sent it and the data intent, containing the Intent.EXTRA_SHORTCUT_INTENT which I could then use somehow to actually start the shortcut.
The second part of the question is how do I actually store the necessary information for the shortcut the user selected, preferably in SharedPreferences, so I could later execute this shortcut with the specific parameters. I couldn't find any example of this.
Any help would be much appreciated! Thanks!
More then 2 years later, here is the answer to my question:
The proper functioning of the startActivityForResult/onActivityResult system obviously depends on both the calling and the called Activities being part of the same Task. Therefore any action which would cause the two activities to be launched in separate Tasks would break this functionality. Such actions include setting any exclusive launchMode for any of the Activities in the AndroidManifest.xml or using flags such as Intent.FLAG_ACTIVITY_NEW_TASK when launching any of the two Activities.
Upvoted the answer of user2427931 for the Intent.parseUri() solution.
I had the same behavior when my calling activity had launchMode="singleInstance". Do you have that defined as well?
Regarding saving the Intents. You could turn the intent into an URI and save it as a string in SharedPreferences. You could then use Intent.pareseUri() once you have retrieved it.
//Erty

Removing an activity from the history stack

My app shows a signup activity the first time the user runs the app, looks like:
ActivitySplashScreen (welcome to game, sign up for an account?)
ActivitySplashScreenSignUp (great, fill in this info)
ActivityGameMain (main game screen)
so the activities launch each other in exactly that order, when the user clicks through a button on each screen.
When the user goes from activity #2 to #3, is it possible to wipe #1 and #2 off the history stack completely? I'd like it so that if the user is at #3, and hits the back button, they just go to the homescreen, instead of back to the splash screen.
I think I can accomplish this with tasks (ie. start a new task on #3) but wanted to see if there was simpler method,
Thanks
You can achieve this by setting the android:noHistory attribute to "true" in the relevant <activity> entries in your AndroidManifest.xml file. For example:
<activity
android:name=".AnyActivity"
android:noHistory="true" />
You can use forwarding to remove the previous activity from the activity stack while launching the next one. There's an example of this in the APIDemos, but basically all you're doing is calling finish() immediately after calling startActivity().
Yes, have a look at Intent.FLAG_ACTIVITY_NO_HISTORY.
This is likely not the ideal way to do it. If someone has a better way, I will be looking forward to implementing it. Here's how I accomplished this specific task with pre-version-11 sdk.
in each class you want to go away when it's clear time, you need to do this:
... interesting code stuff ...
Intent i = new Intent(MyActivityThatNeedsToGo.this, NextActivity.class);
startActivityForResult(i, 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == R.string.unwind_stack_result_id) {
this.setResult(R.string.unwind_stack_result_id);
this.finish();
}
}
then the one that needs to set off the chain of pops from the stack needs to just call this when you want to initiate it:
NextActivity.this.setResult(R.string.unwind_stack_result_id);
NextActivity.this.finish();
Then the activities aren't on the stack!
Remember folks, that you can start an activity, and then begin cleaning up behind it, execution does not follow a single (the ui) thread.
One way that works pre API 11 is to start ActivityGameMain first, then in the onCreate of that Activity start your ActivitySplashScreen activity. The ActivityGameMain won't appear as you call startActivity too soon for the splash.
Then you can clear the stack when starting ActivityGameMain by setting these flags on the Intent:
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
You also must add this to ActivitySplashScreen:
#Override
public void onBackPressed() {
moveTaskToBack(true);
}
So that pressing back on that activity doesn't go back to your ActivityGameMain.
I assume you don't want the splash screen to be gone back to either, to achieve this I suggest setting it to noHistory in your AndroidManifest.xml. Then put the goBackPressed code in your ActivitySplashScreenSignUp class instead.
However I have found a few ways to break this. Start another app from a notification while ActivitySplashScreenSignUp is shown and the back history is not reset.
The only real way around this is in API 11:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
I use this way.
Intent i = new Intent(MyOldActivity.this, MyNewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i);
I know I'm late on this (it's been two years since the question was asked) but I accomplished this by intercepting the back button press. Rather than checking for specific activities, I just look at the count and if it's less than 3 it simply sends the app to the back (pausing the app and returning the user to whatever was running before launch). I check for less than three because I only have one intro screen. Also, I check the count because my app allows the user to navigate back to the home screen through the menu, so this allows them to back up through other screens like normal if there are activities other than the intro screen on the stack.
//We want the home screen to behave like the bottom of the activity stack so we do not return to the initial screen
//unless the application has been killed. Users can toggle the session mode with a menu item at all other times.
#Override
public void onBackPressed() {
//Check the activity stack and see if it's more than two deep (initial screen and home screen)
//If it's more than two deep, then let the app proccess the press
ActivityManager am = (ActivityManager)this.getSystemService(Activity.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(3); //3 because we have to give it something. This is an arbitrary number
int activityCount = tasks.get(0).numActivities;
if (activityCount < 3)
{
moveTaskToBack(true);
}
else
{
super.onBackPressed();
}
}
In the manifest you can add:
android:noHistory="true"
<activity
android:name=".ActivityName"
android:noHistory="true" />
You can also call
finish()
immediately after calling startActivity(..)
Just set noHistory="true" in Manifest file.
It makes activity being removed from the backstack.
It is crazy that no one has mentioned this elegant solution. This should be the accepted answer.
SplashActivity -> AuthActivity -> DashActivity
if (!sessionManager.isLoggedIn()) {
Intent intent = new Intent(context, AuthActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
context.startActivity(intent);
finish();
} else {
Intent intent = new Intent(context, DashActivity.class);
context.startActivity(intent);
finish();
}
The key here is to use intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); for the intermediary Activity. Once that middle link is broken, the DashActivity will the first and last in the stack.
android:noHistory="true" is a bad solution, as it causes problems when relying on the Activity as a callback e.g onActivityResult. This is the recommended solution and should be accepted.
It's too late but hope it helps. Most of the answers are not pointing into the right direction. There are two simple flags for such thing.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
From Android docs:
public static final int FLAG_ACTIVITY_CLEAR_TASK
Added in API level 11
If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the
activity to be cleared before the activity is started. That is, the
activity becomes the new root of an otherwise empty task, and any old
activities are finished. This can only be used in conjunction with
FLAG_ACTIVITY_NEW_TASK.
Just call this.finish() before startActivity(intent) like this-
Intent intent = new Intent(ActivityOne.this, ActivityTwo.class);
this.finish();
startActivity(intent);
Removing a activity from a History is done By setting the flag before the activity You Don't want
A->B->C->D
Suppose A,B,C and D are 4 Activities if you want to clear B and C then
set flag
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
In the activity A and B
Here is the code bit
Intent intent = new Intent(this,Activity_B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
super.finishAndRemoveTask();
}
else {
super.finish();
}
Here I have listed few ways to accomplish this task:
Go to the manifest.xml- and put android:noHistory="true", to remove the activity from the stack.
While switching from present activity to some other activity, in intent set flag as (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK). It is demonstrated in the example below.
Intent intent = new Intent(CurrentActivity.this, HomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent);here
Note :Putting the intent flags can cause blank screen for sometime (while switching activity).
Try this:
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)
it is API Level 1, check the link.

Categories

Resources