Consider 3 activities:
(A) Login Activity (main launcher)
(B) Main Activity
(C) Specific Activity
After users logged in (A) they will access (B), and from, and ONLY from (B), they can access (C).
Now everytime the app is opened, it will first launch (A) and then (B).
I want to make a push notification where when clicked, it can access (C) but must start (B) first.
I am using Xamarin.Android + Appcenter Push Notification
I can get notifications both when my app is in foreground and background.
My problem is when my app is in the background, clicking at the received notifications in the status bar causes it to relaunch the app, starting from (A).
I need help with skipping (A) since user is already logged in, opens (B) and THEN opens (C)
Any ideas? Hoping this is not too confusing for you guys.
I have also tried setting launchMode=singleInstance to (A) and (B) but it still relaunch the app
You cannot change the launcher activity dynamically, but there are a few workarounds you can try:
Create a transparent activity and make it as the Launcher activity:
<activity
android:name=".ActivityLauncher"
android:theme="#android:style/Theme.Translucent.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
And select the next activity in it's onCreate()
if ( logged() ) {
intent = new Intent(this,ActivityB.class);
} else {
intent = new Intent(this,ActivityA.class);
}
startActivity(intent);
finish();
You can achieve this send a activity name or some value to select your activity. Depending on the value that u are sending you can launch the activity and also add the activity in backstack whenever u go back fron notified activity the page in backstack will appear.
I do always like this, hope this will work for you.
Related
This question already has answers here:
Android: bug in launchMode="singleTask"? -> activity stack not preserved
(12 answers)
Closed 2 years ago.
My launcher activity has the launchMode attribute set to singleTask due to certain requirements.
<activity
android:name=".map.MapsActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="#style/MapScreenTheme"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The problem I'm facing is that if I open another activity -> press home -> Click on app icon in launcher application -> It opens the MapActivity and not the activity that was previously open.
This however does not happen if I navigate to the app via the recents menu. Then the newly opened activity stays on top.
Can someone please explain what is happening here with regards to the backstack and why is the ActivityManagerService not taking into account that the app process already exists and yet decides to start the launcher app and clear the backstack and not simply bring the app forward?
This issue can be observed in a small sample app created here -
https://github.com/abhiank/SingleTaskActivity
I think this is the desired behavior of SingleTask launch mode. Keeping Launcher Activity as SingleTask has its consequences.
I can not think of an exact solution for this problem but some workaround will do the Job.
Adding the link below which i have mentioned in comment to go through.
Android: bug in launchMode="singleTask"? -> activity stack not preserved
I think, When you click on app icon again, It opens the Launcher Activity on top of your previously opened Activity. What you can do is apply a simple check whether there are any activity in the backstack apart from this, then finish this launcher activity, It will reveal previously opened screen. Try the below link.
https://stackoverflow.com/a/38450232/3497972
check these links too, they have other ways to maintain screen when launched app icon, when app is in background
How to make an android app return to the last open activity when relaunched?
Android app restarts when opened by clicking app icon
Determine when application icon is clicked to launch the app in android
What is the difference between launch app from "recent apps" and tapping app icon
There is some solution for case when your main activity would be launched only by other activities within your own application:
You can remove launchMode attribute from your main activity definition in manifest. And just pass Intent.FLAG_ACTIVITY_NEW_TASK to every intent that opens your MainActivity, for example like this:
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Be aware that behaviour of Intent.FLAG_ACTIVITY_NEW_TASK or launchMode="singleTask" within your own application only works in conjunction with taskAffinity attribute on activity definition in manifest.
I hope it will help you a little.
Sounds to me like you are seeing this nasty long-standing Android bug
Re-launch of Activity on Home button, but...only the first time
To test whether that is the case, please kill your app (settings->apps->your app->force quit). Then launch your app by tapping the app icon on the HOME screen. Do whatever you need to do to launch another Activity into the task. Press HOME. Now tap the icon on the HOME screen again. This should bring your task to the foreground in the same state you left it in.
My app has 2 activities: a main activity, and a detail activity. When I click a button on main it generates a push notification which when clicked brings up the details page.
The problem is, I do not believe I've configured anything to suggest that the activity should open with any different launch properties other than standard nor are their any flags set to suggest my activity open differently either. However when the notification is clicked and the new activity opens, when I click the back button I am taken back to the homescreen and no active tasks are available any longer.
I've noticed through experimentation that if I direct the intent triggered by the notification to go to back to the main activity instead of the detail activity it operates as I would expect. I can click the button on the first instance of main activity to fire the notification, click the notification to bring up the second instance of main activity, then press back to go back to the original instance of Main activity. It even has the correct state of details represented in the original (a text box populated with what I provided to trigger the first notification to say).
I've also found that if I direct the intent to fire the detail activity but set the affinity associated w/ the activity to something else that it SORT OF works by just creating a new task w/ that activity as the sole activity associated w/ the task. But this isn't what I want nor is it what I think should be happening anyway.
EDIT: I've added a button that takes me to the details activity through a standard intent. This works as intended. I've also added a button to the details activity that generates a notification to the Main Activity operating on the same logic as the button on Main that fires the notification to go to the Details Activity except with the intent class changed. Clicking this generates the notification, and pushes the main activity onto the already existing task stack as is standard.
So it seems like the issue is related to the Detail activity being targeted by the pending intent but I haven't figured out exactly what yet and following the details in the android website is of no help (though this is obvious as it's where I started from originally)
Code:
Generates the push notification (found on main activity)
fun generatePush2(view: View){
var generalTapIntent = Intent(this, ActivityDetail::class.java)
var pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, generalTapIntent, 0);
var notificationId = 0;
var builder = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("Instant Message")
.setContentText(txt_notification.text)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent) //sets the event to fire when notification is clicked
.setAutoCancel(true) //Removes notification when user taps it
with(NotificationManagerCompat.from(this)){
notify(notificationId, builder.build());
}
}
Android Manifest details (for proof)
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".ActivityDetail">
</activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
you can override the onBackPressed() like this:
public void onBackPressed()
{
this.startActivity(new Intent(DetailActivity.this,MainActivity.class));
return;
}
if you want the main activity to look different than default you can still pass some data through the intent and display it the way you want using :
Detail Activity
intent.putExtra(String key, Object data);
Main Activity
intent.getExtra(String key);
SO while not understanding the bug fully, I have found that the issue is related to two things. The AVD I was using and the activity name. On the original AVD I changed the activity name from ActivityDetail to ActivityDetail2 and this fixed the entire problem. I realized something was up w/ the activity when creating a third activity didn't have the issue. Unfortunately upon changing the name back (shift + f6 in Android studio) the problem began to occur again. Perplexed I then deleted the AVD (had to reinstall android studio to fix emulator:process failed for error code 0 error) and created a new one with a different phone type and different version of android. I was then able to run the application w/ the activity name "ActivityDetail" and the problem didn't occur.
I was also not able to re-create the issue on the original AVD. This tells me that something on the AVD was associated to that specific activity name, set somehow through an application call I might have made while following the guide on the official android notification page: https://developer.android.com/training/notify-user/build-notification
Unfortunately that's all I can say for certain. That and there's no need to overwrite the on back key action just to fix this issue.
I'm using Firebase Cloud Messenger (FCM) to push notifications to my app.
The notifications are received when the app is in the background so onMessageReceived is not triggered as the notification doesn't have a payload (data). Everything is fine with that but it means I can't create my own notification as everything is automatically handled by System tray.
When I click the notification I expect the entire backstack to be cleared and the app to restart from scratch. Basically I want the opposite of this post.
This is supposed to be the default behaviour.
However, when I click on the notification, if the app was already opened, the app restarts from the launcher but on top of the existing backstack.
For instance if you have:
HomeScreen -> Page1
when the notification is clicked, you now have in the stack:
HomeScreen -> Page1 -> HomeScreen
when it's supposed to only be:
HomeScreen
My launcher is an Activity only displayed when the app starts so I don't want it to be kept in the backstack. I turns out this this why I get this issue. So basically if the Launcher Activity calls finish() on itself and/or has noHistory="true" set in the Manifest, the backstack is not cleared when the notification is clicked.
How can I solve this issue?
I found a solution. The idea is to create a new LauncherActivity in charge of launching the existing one and clearing the backstack in the process.
There are probably other ways to do that but I wanted to keep the original Launcher with noHistory="true" as otherwise I have issue with the transition animation with the next Activity if I implemented the below solution directly to it.
The new Launcher is called StartActivity
In the Manifest:
<activity
android:name=".StartActivity"
android:screenOrientation="portrait"
android:theme="#style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The Activity:
public class StartActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, LauncherActivity.class);
// Add the flags to clear the stack
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
// Start the intent with a defined transition animation. The animation is not
// required but it make the transition seamless.
startActivity(intent, getFadeInOutAnimation(this));
// Necessary for the app not to crash. Basically just a FrameLayout
setContentView(R.layout.activity_start);
}
public static Bundle getFadeInOutAnimation(Context context) {
// Allows us to display a fading animation as transition between the activities.
// The animation can be whatever you want
return ActivityOptions.makeCustomAnimation(context,
R.anim.fade_in, R.anim.fade_out).toBundle();
}
}
I have an app that may run in the background. While it is running, it may bring a certain activity to the front. However, when the app brings the activity to the front, if the app is currently running at background, I do not want Android to bring the app itself to the front, just do it at background. The reason being is I do not want my app to interrupt what the customer is doing at the moment.
The following is my code that launches the activity.
Intent intentLogin = new Intent(getApplicationContext(), LoginActivity.class);
intentLogin.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intentLogin);
The issue with the above code is every time when it is called, it always bring my app to the front even the app is running at background, that is, annoy my customer.
My question is, is there a way that I can quietly bring the activity to the front? If my app is running in front, thats great --- the customer see the new activity straight away. If my app is running at background, I want to quietly bring the activity to the front when app is running in background, and next time when my customer resume the app, they will see the new activity I brought forward.
How can I do that?
Thank you very much!
如果我没理解错的话:
App background and usual player.
When user logged out , you can clear the user data saved in local and show a notification.And when the notification is clicked, start LoginActivity.
App background and unusual player.
When the notification shows ,the user do not click it instead of run the app.You can check the user data whether existing or not by onResume()in BaseActivity.If not ,start LoginActivity.
App foreground.
clear user data and force to start LoginActivity.
If you don't like the solution above(the best user experence I think),try this:
In onCreate() in the specific Activity ,use moveTaskToBack(true) to hide the intent.But remember to check whether the app is running background or foreground.you can refer to this.
If understand correctly, I suggest this:
User leaves your app, and when user come back to your app you want to show another activity instead of .MainActivity
define another activity as Main and with NoDisplay theme.
<activity
android:name=".MainActivity"
android:theme="#android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
then define your normal activities. In MainActivity class define a static variable. for example
public static boolean appRun = false;
onCreate() of SecondActivity change its value to true.
class SecondActivity extends Activity{
#Override
protected void onCreate(Bundle Saved){
super.onCreate(Saved);
MainActivity.appRun = true;
}
}
and onPause set this.finish(); to avoid not resuming to SecondActivity and force to start from MainActivity.
then onCreate() or onResume() of MainActivity check it s value and navigate to another activity.
if(appRun == true){
/*it means user went to SecondActivity and you want to display another*/
startActivity(new Intent(context, NewActivity.class));
}
else{
//this is first time so navigate to SecondActivity
}
Also If you can use Fragments this solution can work for that too.
In my application, I have specified a second activity that can be launched from the launcher, using this manifest entry:
<activity
android:name=".Lists.ListOfListsActivity"
android:icon="#drawable/ic_launcher_lists"
android:launchMode="singleTop"
android:label="#string/lists_activity_name" >
<!-- An Intent filter so that the Lists activity shows in the Launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Let's say I have the app open at the "main" activity then press the home key. My app will still be running, but in background.
Later the user selects the launcher icon I have for "ListsOfListsActivity" from the homescreen.
This will bring the application to the foreground, but NOT at the "ListOfListsActivity", but at whatever it's current activity was when it went to the background (e.g. at the "main"activity).
This is confusing, as the user selected the "ListOfListsActivity" but is shown another one. Then they have to navigate to it.
I had this working better, by specifying launchMode = "singleTask" for the "ListOfListsActivity", but in that mode it cannot be launched from another activity for a result (startActivityForResult() ), and I need to be able to do that to pick a list...
Question:
- how to specify an intent-filter that will force an activity to the foreground and be the selected activity, no matter what the current status of the application and it's current activity??
My final implementation was to define a different taskAfinity string for each activity I wanted to launch independently from the Launcher.
That way, each "shortcut" always launches the activity I want, but the downside that I have not been able to avoid is that the user may have multiple tasks with an activity from my application in it, and maybe the same activity open/active in different tasks....