We have an app with an Activity that can be started in two ways:
From another Activity - always with some extra data filled in
From deep linking
As far as I can see this is always working just fine. We either get the Intent.ACTION_VIEW with a data URI, or we get some string extras.
However, we have a very few instances where action is Intent.ACTION_MAIN and there are no extra data.
The toString() of the Intent is as follows (class name changed):
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10400000 cmp=com.example.OurActivity }
Intent.getExtras() returns null, Intent.getDataString() returns null.
In which cases can this happen? Why is the category for the Activity Intent.CATEGORY_LAUNCHER? How can we get the data needed to show the user the right contents?
launchMode is not specified for the Activity. The only IntentFilter in AndroidManifest.xml is for the deep linking (and not the launcher category).
The issue happens on Android 4-6 on a wide range of devices.
Edit: Forgot to mention the flags:
As the print out suggests the flags for the Intent are FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_BROUGHT_TO_FRONT. I suppose that could be relevant here.
I believe, I nailed it:
There're launchers, like Nova Launcher which allows users to start with any of app's Activities, instead of the normal flow:
For example, you can add a shortcut on your desktop to start Gmail client with Account setup Activity.
And in this case, Activity is being started with empty Extras and technically it becomes a launcher's Activity.
Now that AndroidManifest.xml is manipulated by the build system, it often happens that libraries that you include also add things to the manifest, which I suspect may be happening here.
Although you state that there is only one IntentFilter in the manifest, have you actually checked the installed app to see what its manifest says (rather than relying on what you think you put in your source code)?
Various apps are available in the Play Store to show you the manifest of an installed app - including App Detective (which I wrote).
Related
Our activity can be launched from a GCM notification. We set extras in the GCM intent to ensure the user is taken to the message thread for that GCM notification, and we call removeExtra afterwards to remove it from the intent.
If the user launches our app from the recent history menu, then the activity is started with the same intent as from the previous launch (e.g. from the GCM notification).
This scenario is quite easy to detect:
Intent i = getIntent();
// If the caller intent is from the recent apps and has the RECIPIENT_ID_KEY
// extra we should remove it to avoid open the messages thread again
if (((i.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) &&
i.hasExtra(MyConstants.RECIPIENT_ID_KEY)) {
i.removeExtra(MyConstants.RECIPIENT_ID_KEY);
}
However, we also want this to work if the activity has been destroyed by the OS. At the moment, when the Developer option "Do not keep activities" is set (only available on OS 4.0+), then the activity keeps being recreated with the same intent when pressing the Back button from another one of our screens, resulting in bad things happening.
I considered adding a unique extra in our GCM intent and saving that in Shared Preferences once we have processed it. However, we also need this to work when sharing an image into our app through a SEND image/jpg intent. We don't control that intent, so how will we know if we've already processed it? I guess we could use the file/URI information, although that means if a user shares the same image twice in a row, we'll ignore the second one.
Is there a clean and simple way to solve this problem?
We currently support OS 2.3+, and our application is available all around the world. Here's the relevant section of my AndroidManifest.xml:
<activity
android:name=".ui.MyClass"
android:configChanges="orientation|screenSize"
android:launchMode="singleTop"
android:windowSoftInputMode="stateHidden" >
I was interested in how to solve the part:
However, we also need this to work when sharing an image into our app
through a SEND image/jpg intent.
As soon as I handle the images I put an extra flag on the Intent. As you can imagine, I check for that flag before doing the files processing. This worked even if the Intent was created by another application.
It isn't clear to me how Android determines which Activity starts first when an app starts. The Android documentation states the following concerning the AndroidManifest.xml file about Activities:
"Only one activity should have the "main" action and "launcher" category..."
So in the AndroidManifest.xml file, you should essentially have only one:
action android:name="android.intent.action.MAIN"
category android:name="android.intent.category.DEFAULT"
However, while looking at sample code from the Android SDK, the application called "APIDemos" contains a manifest file with tons of
"android.intent.action.MAIN" and
"android.intent.category.DEFAULT"
I am totally confused. This seems to go contrary to what Google is stating about there only suppose to be one. Does Android simply grab whichever one appears first in the manifest and ignores all the others? If not, why are there multiple MAINs and DEFAULTs?
Activities will very often need to support the CATEGORY_DEFAULT so that they can be found by Context.startActivity(). So, CATEGORY_DEFAULT can appear number of times.
Android does not grab whichever one appears first in the manifest but it starts with activity having CATEGORY_LAUNCHER.
CATEGORY_LAUNCHER : The activity can be the initial activity of a task and is listed in the top-level application launcher.
For more details refer:
http://developer.android.com/guide/topics/intents/intents-filters.html
action.MAIN and category.LAUNCHER are the ones that are used to specify what activity gets launched when the user presses your app icon or selects it from the running list of apps.
You can use other combinations of actions and category.DEFAULT to respond to different events but the combination of action.MAIN and category.LAUNCHER should only be defined once.
I am totally confused. This seems to go contrary to what Google is stating about there only suppose to be one.
It isn't contrary. These activities have category CATEGORY_DEFAULT, but not CATEGORY_LAUNCHER.
I am trying to programmatically add and remove application shortcuts from the app drawer. I understand the app drawer knows which applications should be presented by using an intent filter with the LAUNCHER category.
I would like to be able to add/remove shortcuts to specific activities in my application, according to dynamic conditions, which is why I can't have them simply in my manifest file.
Thank you.
As far as I know, this is not possible. Unfortunately, with the current Android API level there is no way to add IntentFilters to Activity objects through code. Check out this doc on intent filters. Relevant quote:
An intent filter is an instance of the IntentFilter class. However, since the Android system must know about the capabilities of a component before it can launch that component, intent filters are generally not set up in Java code, but in the application's manifest file (AndroidManifest.xml) as elements. (The one exception would be filters for broadcast receivers that are registered dynamically by calling Context.registerReceiver(); they are directly created as IntentFilter objects.)
Could you please explain me purpose and usage of LauncherActivity? Documentation says that it "Displays a list of all activities which can be performed for a given intent". I understood that it should automatically build list of all activities found in application and provide their launching. Am I right?
And how to use it? I have found no examples in the web.
Google Code shows the class code itself... It has a different constructor than is described in the Android Platform API.
public abstract class LauncherActivity extends ListActivity {
Intent mIntent;
PackageManager mPackageManager;
IconResizer mIconResizer;
Your phone can have more than one possible app which handles a given intent. One great example is opening a webpage. There's the stock WebKit based browser, you can install Firefox Mobile, Dolphin Browser, Opera Mini... When they all advertise that they can handle a given intent, how does the device know which one it should pass the intent to?
Android will use a LauncherActivity to bring up a selection list of packages where each one listed is one that knows how to do something with the given intent you provide it. When you pick one, you're picking which app you want, and the intent is routed to the matching app.
From that perspective, it's a class that's really part of the Android OS support code, part of figuring out where to distribute given intents to. It's hard to see a situation where you would need to involve yourself with it directly... you should be able to just call StartActivity(Intent), which throws the intent over the wall to the OS, and at that point the device itself should fire up LauncherActivity on its own (if it's even needed).
Completely unrelated (and horribly name-disambiguated) is your application's "Launcher Activity" (documentation) -- an activity that shows in AndroidManifest.xml with an intent filter with "android.intent.action.MAIN" and "android.intent.category.LAUNCHER" ... This is how your app advertises to the system that it wants to have an icon in the device's application list, and that a specific activity should be started when that icon's clicked. You absolutely need to do that.
I am interested in activating another application's activity. I know from reading the Android SDK that it's probably better to do this with an implicit intent. However, this activity doesn't reside in an application I own, so I don't know the action and category and data flags on the intent-filter.
How can I examine an Android applications metadata like the activity classes and the intent-filters for those activities (if declared in the manifest)?
Thanks!
I would try this.
Check on openintents
Contact the developer.
Use android-apktool too see the app's manifest.
It might be illegal to use android-apktool. Use it under your own risk.
There is one more solution: you could run this app and look into logcat. All intents are logged, so you could see what is called up. You won't see extra data though.