Starting the app from Notification remove it from recent app history - android

I have a problem in one of my apps when I start it from a notification. It never appears in the "recent app" list.
Without notifications, every thing works as expected: I start the app, navigate into and when I quit it (with home button or back button) after that I can go back into it with a long press on home button => ok.
The problem starts when I receive a notification. If I start the app from the notification, it starts the correct screen and I can use the app => ok. But when I quit the app (with home or back button) it do not appears anymore in the "recent app" list. More precisely:
If the app was present in the "recent app" list before launching the app from the notification, it removes it
If the app was not present in the "recent app" list, it does not add it
Below, my original code to add the notification in the status bar:
mNotification = new Notification(R.drawable.ic_notif, message, System.currentTimeMillis());
mNotification.flags |= Notification.FLAG_AUTO_CANCEL;
Intent notificationIntent = new Intent(Intent.ACTION_VIEW,Uri.parse(link));
notificationIntent.putExtra(...);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
mNotification.setLatestEventInfo(context, context.getString(R.string.app_name), message, contentIntent);
notificationManager.notify(ConfigApp.NOTIFICATION_ID, mNotification);
I tried adding a FLAG_ACTIVITY_NEW_TASK but it did not help:
Intent notificationIntent = new Intent(Intent.ACTION_VIEW,Uri.parse(link));
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
notificationIntent.putExtra(...);
Manifest declaration of the Activity started by the notification:
<activity
android:name=".activity.ActivityMessages"
android:label=""
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="hostapp"
android:pathPrefix="/prefixapp"
android:scheme="schemeapp" />
</intent-filter>
</activity>
Does anyone knows how to keep the app in the "recent app" list after being started form a notification?

Add the action android.intent.action.MAIN and the category android.intent.category.LAUNCHER to the specification of your activity. Having two actions and categories seem like a hack but it's actually supported by Android.
<activity
android:name=".activity.ActivityMessages"
android:label=""
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<data
android:host="hostapp"
android:pathPrefix="/prefixapp"
android:scheme="schemeapp" />
</intent-filter>
</activity>
That should add it to the recent applications list. The reason is described in the Android developer documentation:
An intent filter of this kind causes an icon and label for the
activity to be displayed in the application launcher, giving users a
way to launch the activity and to return to the task that it creates
any time after it has been launched.
This second ability is important: Users must be able to leave a task
and then come back to it later using this activity launcher. For this
reason, the two launch modes that mark activities as always initiating
a task, "singleTask" and ""singleInstance", should be used only when
the activity has an ACTION_MAIN and a CATEGORY_LAUNCHER filter.
Imagine, for example, what could happen if the filter is missing: An
intent launches a "singleTask" activity, initiating a new task, and
the user spends some time working in that task. The user then presses
the Home button. The task is now sent to the background and is not
visible. Now the user has no way to return to the task, because it is
not represented in the application launcher.

Try adding to the manifest the following:
android:excludeFromRecents = "false"
Good luck,
Luis

You need to use separate Intent Filters for each action/category pair:
<activity
android:name=".activity.ActivityMessages"
android:label=""
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="hostapp"
android:pathPrefix="/prefixapp"
android:scheme="schemeapp" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<data
android:host="hostapp"
android:pathPrefix="/prefixapp"
android:scheme="schemeapp" />
</intent-filter>
</activity>

I bumped into same issue. The problem was that my activity had android:label="". When I open Activity from the Notification then it replaces root activity in the app task with current one. And Android excludes activities with empty label from Recents (see source code).
To hide title of activity you should use:
getActionBar().setDisplayShowTitleEnabled(false);

Old topic but I discover solution (and I can't find in web anyone), maybe it will be helpful for sb. It doesn't give possibility to set any activity as a parent but I think (not sure) that you can change it programmatically (in OpenFromNotificationActivity) if it is necessary.
In manifest
<activity android:name=".OpenFromNotificationActivity"
android:label="#string/label">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".StartSplashActivity" />
</activity>
<activity android:name=".StartSplashActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Related

Bring Android app's previous instance to foreground from FCM notification

On my app I have a Splash Screen set with intent:
<activity
android:name=".Splash"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
My app then opens a ".MainActivity", which is where all the action happens. Although when I get a push FCM notification and tap it, the app restarts and I get a new instance of everything. How do I keep the same instance of the app but just bring it to the foreground, basically like iOS does.
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
If FLAG_ACTIVITY_SINGLE_TOP is set, the activity will not be launched if it is already running at the top of the history stack.
Referenced from: How to use Flags in android ?

Android: Recents starts incorrect activity

I am developing an android app which has 2 methodes of starting.
One is the normal way by pressing the app icon on the phone.
The other method is with a deep link from a website.
The deeplink also sends some data which the app needs to do some "stuff". However this should only be done once.
When the deeplink activity is finished it start the main activity. However when I press back (on the device) and open the app from recents it opens the deeplink activity again.
I could exclude the deeplink activity from the recents in the manifest. This also excludes the mainactivity from the recent apps, this should not be the case.
How do I prevent the deeplink activity from beeing started from the recent apps?
My Manifest:
<activity
android:name="MainActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:launchMode="singleTask"
android:theme="#style/AppTheme">
</activity>
<activity
android:name="DeeplinkActivity"
android:label="#string/app_name"
android:noHistory="true"
android:screenOrientation="portrait"
android:launchMode="singleTask"
android:theme="#style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="app_name" android:host="test" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="test" android:path="/" android:scheme="app_name" />
</intent-filter>
</activity>
To switch to the MainActivity I do the following:
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
EDIT:
This post was marked as duplicate with: Android: Starting app from 'recent applications' starts it with the last set of extras used in an intent
However that post is regarding the same activity. I want to change the root activity so when I start the app from recents it does not start the DeeplinkActivity. Yes as a workaround I could check the Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY flag. But then every time the user starts the app from recents the DeeplinkActivity is opened whilst it is not needed anymore.
Setting and or clearing aditional intent values does not seem to work.
I use information from the getIntent().getData()
If you still feel as if this is a duplicate please explain.
Your problem is that both DeepLinkActivity and MainActivity are in the same task, so when the user selects the app from the list of recent tasks, Android will either bring an existing task to the foreground, or if there is no existing task (with live/active activities in it), start the Activity that was the root Activity in the most recent task. You can't predict which Activity will be the root Activity, since the task could be started with either DeepLinkActivity or MainActivity, depending on which one the user chose first.
You really need to have 2 separate tasks to do this. One task will have your DeepLinkActivity in it, and this task should be excluded from the "recent task list". The other task will have your MainActivity in it.
I assume that MainActivity has the <intent-filter> with ACTION=MAIN and CATEGORY=LAUNCHER, even though your posted manifest does not show this.
Your manifest should look like this:
<activity
android:name="MainActivity"
android:label="#string/app_name"
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>
<activity
android:name="DeeplinkActivity"
android:label="#string/app_name"
android:noHistory="true"
android:screenOrientation="portrait"
android:taskAffinity=""
android:excludeFromRecents="true"
android:theme="#style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="app_name" android:host="test" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="test" android:path="/" android:scheme="app_name" />
</intent-filter>
</activity>
You definitely do not need launchMode="singleTask" for MainActivity and you probably don't need it for DeepLinkActivity either (that depends on what else you do with this).
Specifying taskAffinity="" ensures that DeepLinkActivity is not launched into the same task as MainActivity, and allows you to launch MainActivity from DeepLinkActivity in a separate task. NOTE: Without specifying taskAffinity, both activities will end up in the same task, even though you specify launchMode="singleTask" for both of them.
Specifying excludeFromRecents="true" on DeepLinkActivity tells Android that the task with DeepLinkActivity as its root activity should not appear in the list of recent tasks.
When you launch MainActivity from DeepLinkActivity, you should do this:
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
and make sure that you call finish() on DeepLinkActivity.
If necessary you can also add noHistory="true" to DeepLinkActivity, but I don't think it is necessary. If the user is in DeepLinkActivity and gets an incoming phone call, after the phone call is ended, DeepLinkActivity should be displayed. If you specify noHistory="true", DeepLinkActivity would be finished immediately when the user accepts the incoming phone call.
Let me know if this is clear and works for you.

Android Intent with Cordova - New app instance launched for every share. Should be only one

I want to share url's from other apps to mine.
I am using this Phonegap Plugin to implement the intents:
https://github.com/chrisekelley/olutindo-app/tree/master/plugins/com.borismus.webintent
Intents are working, but everytime i share an intent from another app, a new instance of my app is launched, but i want to use one instance. If the app is already opened, it should be reinitialized and brought to front or restarted with the shared intent initialization.
I tryed android:launchMode="singleTop", but the same behavior occurs, app would be opened multiple times.
My manifest entry:
<activity android:configChanges="orientation|keyboardHidden|screenSize"
android:name=".StartActivity"
android:label="#string/app_name"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
These is no initialization in my MainActivity because the intents would be initialized from javascript with a own function (See PG plugin above).
Edit: I tryed to use android:launchMode="singleInstance". Now on every share request my app would be brought to top, but the intent is not initialized. How can i initialize the incoming intent request again with cordova, if the app is already started?
Thank you!
I'm not sure how to workaround this. But i'm pretty sure that even if your code is launchMode="singleInstance" or singleTask, the OS will open an different Instance for each intent.action.
The only way to workaround i did find is creating a empty activity that calls your activity with a unique intent.action.
final Intent myIntent = new Intent(this,
MainActivity.class);
myIntent.setAction("android.intent.action.MAIN"); //myIntent.setAction(Intent.ACTION_MAIN);
startActivity(myIntent);
You can do a listening service. When you try to share the service get launched and it opens your activity if one intent.action aways.

App started with a custom url scheme does not appear in recent apps list

When my app is started with a custom url scheme it does not appear in the "recent apps" list (appears on holding the home button).
Example:
I start my app from a link in an SMS. My app launches. This is ok.
Then I press the Home button and go to the home screen. Still ok.
Then I hold the Home button and the list of recent apps appears. My app is not on the list. This in not ok - I would expect my app to be on this list.
If I select the Messaging app from the list my app comes up. This is not ok. I would expect to see the Messaging app instead.
AndroidManifest.xml:
<activity android:name=".MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="myhost.com" android:scheme="http" android:pathPattern="/Y.*"/>
</intent-filter>
</activity>
I believe what's happening is that your activity is being launched with an affinity to the task (application) that launched it, rather than launching a new task (your application).
Try setting the launchMode of your activity to singleInstance (the default is standard).
i.e.:
<activity android:name=".MainActivity"
android:screenOrientation="portrait"
android:launchMode="singleInstance">
(Note: check the above linked launchMode documentation as you may prefer singleTask over singleInstance depending on what you are trying to achieve with your application.)

Preventing main activity from being launched if running already

I have an application that is launched via an intent-filter action. The problem is that every time the event/ action occurs, Android displays a dialog asking to launch the app even if it is already started.
I want the behavior to be as follows:
User asked to launch the app if app is not open.
Dialog does not display if app is running in the foreground.
Is there a way to achieve both of these goals? I am targeting Android 4.0.
edit
Here is my intent filter:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"
android:resource="#xml/device_filter" />
You need to set the Activity's launchMode to singleTask. You can do this by adding the activity attribute in your Android Manifest:
android:launchMode="singleTask"
See the documentation for more details.
Use flags when asking the user to start the application. Set the flag when this is first enabled and each time check if this flag is ticked. For example if (flag == 1) askusertostart() else continue; if this is clear to you?

Categories

Resources