I have a bug in my app which I thought I knew how to resolve, but now I've thought more about what is happening I'm not sure I do know the fix.
My app receives an incoming intent from a calling third party app as a string. That string can be sent as a SEND intent or a VIEW intent.
All of that works fine unless the app is already running...
This is what is happening:
My app is not running (not listed in the running apps view)
Share is clicked in another (third party) app and my app is selected to receive the shared text (text1).
My app opens and the text is displayed (and processed) as expected.
The user switches back to the third party app and shares some different text (text2) and my app is selected to receive this new text.
My app opens, but the original text (text1) is still displayed.
At this point I thought that the bug was because I am reading the intent in onCreate() and then displaying and processing it. My thinking was that as the app is already running onCreate() is not being called when the app is shown the second time as we jump into the lifecycle at onResume().
However, if I continue the test as follows:
Without exiting my app the user switches back to the third party app again and again shares the same piece of second text (text2) with my app.
My app is displayed again but this time correctly shows and processes the second text.
How can this be, as the app is still running, surely onCreate() is still not going to be called!
I thought that the fix was going to be simply to move the getIntent() call into onResume() (or onStart() ?) But now I'm not sure about this. Is this right thing to do?
The core of the issue is the fact that your Activity is already on top of the activity stack when the second Intent is being fired.
The launch mode will matter here.
What you can do is, set the launchMode to singleTop, and then get the intent in onNewIntent() method.
That is a good way of handling such scenarios. Please read the link above and it will make things very clear.
Related
We are using intents to switch from one of our apps to another on request, typically a button that is pressed. That way our apps present themselves as a functional unit to the user. We switch back by means of results we hand back.
Recently we implemented a switch that is not triggered by an immediate user interaction, but by an implicit event. When navigating inside one app we use an activity from another app as a drop-in-replacement for some feature in the first app. So the first app sends the user to the second app if it detects that second app is installed.
I realize we have an issue here: if that second app is buggy, crashes, then the first app is broken. Since it switches to the second back again and again without the user being able to alter that behavior. So apparently it makes sense to enable the first app to realize that the second app just crashed. So that it would not switch over next time, although that second app is indeed installed.
This does not work out of the box, since the first app never is informed about the crash of the second app. Instead that app crashes, the OS hint comes app ("Unfortunately XY just crshed") and that's it. The flow never returns to the first app, so there is no return value to evaluate or similar.
So my question is: how can I enable the first app to learn about the fact that the second app just crashed?
I thought about registering a global handler for uncaught exceptions in the second app. That handler would have to somehow signal to the first app that it is currently crashing. Either by sending a specific intent itself (sounds ugly) or by handing back a result (is that possible at all?).
Is there a common practice for this? What is it? What other options exist? Or is that question itself obsolete, since I only failed to see how this is meant to be done?
UPDATE:
Interesting enough I learend that this actually works if the crash in that second app is raised not upon startup but much later ... In that case indeed the first app is in foreground again and is indeed able to detect the crash: the result is "CANCELED" in that case, which is perfectly fine for me.
The the question is reduced to "early crashes" and how this can be handled. Or, the other way round: what is the difference between early and later crashes in that second app?
You technically can't detect that the app crashed, but you can keep something like a "failure counter" in your 1st app. Basically, every time you're about to launch app #2, save a variable in SharedPreferences, something like launchAttempts. You'll want to increment it every time right before you launch app #2, and then decrement it in your onActivityResult() when a result is returned. Then you can set a threshold for how many failed attempts would qualify for "too many", and stop launching app #2
I have an app that acts as sortofa bridge between two other apps, A and B, both of which are mostly black boxes. The user almost always stays in app A but sometimes needs to do something that my app or app B know how to handle. App A supports external actions via URL so I have a custom scheme://host defined for my app.
If the user does an action that my app handles, I get launched via the URL then do my thing then call finish() and the user's back in app A where they started (edit: same activity and etc) - perfect.
If the user does an action that app B handles, my app needs to be in the middle so it can do some translation. App A launches me, I format the message for app B and launch it. When it's done and comes back to my app, I call finish() and.. end up back in app B. Understandable I guess but I really want to end up in app A.
So the question is, how to I tell Android to put A back on top/in front without changing it? I can find the URL for app A via getReferrer() but when I put that into an Intent, it acts like I'm restarting app A instead of just going back to where it was. The doc for Intent.FLAG_ACTIVITY_NEW_TASK looked promising but it still acts like a new instance of the app.
It seems like this should totally be possible but I'm not seeing it. Java/api25.
The problem is that App B is not ending, returning control to your app. App B is launching your app, putting your app on top of it. When your app finishes, your app goes away revealing the still running App B underneath.
So basically App B has bad behaviour (at least, behaviour that is inappropriate for what you are trying to do).
To solve the problem you can either fix App B, or you can do the following:
Instead of just calling finish(), when you want to return to App A just launch it the same way that Android launches an app when the user presses on the app icon:
Intent intent = getPackageManager.getLaunchIntentForPackage("package.name.of.app.A");
startActivity(intent);
finish();
This will bring App A to the front in whatever state it was in when it was put in the background (ie: doesn't actually launch any new Activity). If App A isn't running, it will launch the root Activity of App A, as if the user pressed the app's icon on the HOME screen.
I'm assuming that both App A and App B are running in separate tasks. If that isn't the case, I'll need you to provide more information about which activities are running in which tasks.
I'd like to prevent my application from starting when an Android for Work profile is not available for my application (not yet configured, or deployed on the device). Instead, I'd like to be able to display a Toast like message telling the user to contact his IT administrator. Example of this at the bottom of this message.
Example:
Divide Productivity Suite of application displays this message (mail, notes, etc).
"Configuration from managing application required. Contact your IT admin for details".
Screen Capture
Is there a way to implement this? I've tried to hook into MainActivity onCreate function, or even put it directly in the Application onCreate() function. Hooking code in here seem to still have launched the application (the title bar is displayed despite there's no content displayed).
I was able to figure out how to determine if your Application was running on a for Work profile and display a alert dialog here:
Android for work - How to check if my application is running in the work profile?
Man i can give you specific topic . You can search for services instead of Activities. Activity codes performing only when application is running .
But you can call services everytime without your app is not running.
You can look here
Apparently, this was actually pretty trivial.
In your AndroidManifest.xml, you reference a new Activity that starts your main application. This activity will use the "Theme.Translucent.NoTitleBar"
When you are unable to configure Android for Work profile, use a Toast.makeToast() message to notify your user, then call finish() and return from your onCreate() function.
When you are able to complete Android for Work configuration, start your MainActivity by creating an Intent, set the action and category and then call startActivity() from your initial Activity.
My app can be opened by NFC, and then use the information in the tag to do some processing, the processing is around 5 seconds.
If my app is opened by NFC, I don't want it shows on screen. So this is the onCreate.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.ab.R.layout.test);
Intent intent=getIntent();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
Log.v("nfc", "Start processing");
SystemClock.sleep(5000); // simulate the processing
Log.v("nfc", "End processing");
this.finish();
System.exit(0);
}
}
But it is not work, the app will shows on screen about 5 seconds.
Even I don't process anything
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
this.finish();
System.exit(0);
}
I still can see the app screen in very short time.
How to prevent the app to show the screen if I use NFC to run it?
In your manifest.xml you can specify set the following theme for your activity:
android:theme="#android:style/Theme.Translucent.NoTitleBar"
This makes your activity invisible (if it's empty).
If I am getting you right, you want to start some operations in the background as soon as the app gets started via NFC. The point is that, as soon as you actually start your app and the onCreate method of an activity gets called, your application will enter foreground and will become visible.
Assuming, you do not necessarily need to start an activity but some process in your application via NFC, the best solution is to outsource the code that should run without bringing the app into foreground into a BackgroundService. Set up a BroadcastReceiver onto the NFC-events you want to get informed about. As soon as it receives a notification, this receiver can then start your background service.
EDIT: grexter89 is right, I am sorry for my non-realizable hint. The intents provided by an NFC event can only be processed within an activity! Well, I am sure this is not the answer you want to here but I guess that this limitation is based upon some security/privacy issues. If the approach mentioned above was possible, NFC events could start processes without the consent and confirmation of the user as soon as the user, maybe accidentally, gets into contact with an NFC field. This is the use case you would like to use for your application but, however, these circumstances could be easily misused.
Regarding these points you should rethink if you actually want your activity to be invisible. Given the activity-only-limitation from Google and the above reasons (=> activation by accident, lack of user awareness) I would implement an approach with a visible Activity that shortly displays a hint to the user.
Put the line setContentView(com.airbutton.R.layout.test); inside an IF to validate if you should display it or not. Remember that activities can exist without an UI.
I'm having a bit of an issue with interaction beween my app and other apps on my phone, but I'm starting to think that maybe it's working as designed? Anyway, here's the problem.
My App, call it App A is a photo-manipulation app. So a user goes in, plays around to make changes and then uses the Share button to pass it on (SEND Intent). The photo is sent to another app, chosen from the Share menu, call it App B. This stand-alone app has its own menus, completely different look and feel, etc. The user does his thing in this app for a bit, then hits the home button and goes his way to do something else.
Sometime later, he decides he wants to run my app again. He goes into the launcher, hits the icon for App A (my app), and up pops App B. Very confusing. If he happens to remember that last time he ran App A, he used the share button to get into App B, maybe he'll think to use the back button, to get back into App A. If he doesn't remember, all he knows is that he is trying to use App A, but Android is giving him App B.
(I have one app on my phone that takes over the back button for its own use so you more-or-less get stuck in App B with no way out. Ugh. You hit the icon for App A and always end up in App B)
Is there any solution to this, or is it working as designed? None of my onCreate, OnResume, onStart, etc. methods get called when this is second-open is occurring, so I can't trap it. And realistically, I can see the desire for this behavior when timelines are short - i.e. hit the home button, quickly use some other tool, and then go back to what you were doing. But with a timeline any longer than a minute or two, it gets very confusing.
Anybody else dealing with this problem? Is there a basic Android architectural issue here? Is the SEND intent being mis-used by being accepted by stand-alone apps instead of small utilities?
I think you may use Intent flag 'FLAG_ACTIVITY_NO_HISTORY'. It means starting intent never goes into activity stack.