I need to set the default app for a specific mime type. I know how to clear the default but I need to then prompt the user without actually opening the app.
PackageManager p = mContext.getPackageManager();
ComponentName cN = new ComponentName(mContext, FakeDownloadActivity.class);
p.setComponentEnabledSetting(cN, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Intent selector = new Intent(Intent.ACTION_DEFAULT);
selector.addCategory(Intent.CATEGORY_DEFAULT);
selector.setType(mimeType);
mContext.startActivity(selector);
p.setComponentEnabledSetting(cN, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
The code above launches the activity rather than ONLY selecting the default activity. It works be enabling a fake activity then disabling it. This causes the Select Default App dialog to show the next time it is called. I simply want to ONLY select the default activity.
What you are looking for is an ACTION_PICK_ACTIVITY intent.
First, you create an intent that defines the apps that should be eligible to choose, for instance:
Intent mainIntent = new Intent(Intent.ACTION_DEFAULT, null);
mainIntent.addCategory(Intent.CATEGORY_DEFAULT);
Then, you create the ACTION_PICK_ACTIVITY intent, and as an Extra, you pass the main intent you created before
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
Now, you just start an activity for result with this intent:
startActivityForResult(pickIntent, 0);
And a dialog will be created where the used can pick an application, but when clicked, the activity is not launched, instead, it will stay in your activity, and the function onActivityResult will be called with the results. So you need to create that function:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//In data, you have all the information about the selected application
if (data != null) {
//You can launch the application that we just picked with startActivity(data);
//or explore the variable to get all the information than you want
}
}
Take a look at the Intent class. There you have information about the package name, and the class that would be launched.
From now, what you need is to set that package and class as the default to the intent, or whatever else you need. The bad side, is that you only can save that information for your own internal purposes, for example to decide what app to launch next time that the users performs some action. What you cannot do is to modify the system settings to set a default activity for a given intent. Actually, the package manager has the addPreferredActivity method, that was supposed to do this, but it is deprecated since API level 8, giving this reasons:
This is a protected API that should not have been available to third
party applications. It is the platform's responsibility for assigning
preferred activities and this cannot be directly modified. Add a new
preferred activity mapping to the system. This will be used to
automatically select the given activity component when
Context.startActivity() finds multiple matching activities and also
matches the given filter.
Related
I need to launch an activity (not the main activity) of an application from an application I have made. The activity I want to launch is proprietary, hence, I cannot make any changes to its code(or manifest).
For example: I want to launch somebody's Facebook profile from my own application. A normal intent to facebook from my app would open the 'newsfeed'(which I don't want). I want to know how to access any other activity.
Thanks in advance!
The little code I have:
String PACKAGE="com.facebook.katana";
Intent launchIntent = getPackageManager()
.getLaunchIntentForPackage(PACKAGE);
startActivity(launchIntent);
To launch specific activity you need to use explicit intent. Or use implicit intent with action if you know what action that activity answers to.
To use explicit intent you can do the following (provided you call it from the activity):
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.package.name", "com.package.name.ActivityName"));
if(getPackageManager().resolveActivity(intent, 0) != null) {
startActivity(intent);
} else {
Toast.makeText(this, "No app installed that can perform this action", Toast.LENGTH_SHORT).show();
}
You can also add flags to the intent, add actions and categories. As long as the intent can be resolved as viable intent by the PackageManager, it will launch the activity.
Now...
The question about facebook profile, is a different one.
Perhaps, the best way to achieve that would be to use intent with action VIEW and povide Intent.setData with uri to the profile page. That should also be checked for possibility of being resolved correctly. And then will launch the chooser of all supported activities to open it, which should include facebook application. It is then up to user to open the intent using Facebook app or launcher.
I have recently started a new Android project and I'm working off the previous developer's code. I'm relatively new to Android and I've come across something that I'm unsure of.
What is the difference between this:
Intent intent = new Intent("com.example.project.MENU");
and this:
Intent intent = new Intent(this, DisplayMenu.class);
I understand what the 2nd code snippet does, I just can't get my head around as to what the first one is doing? Is it referencing the file in the package? Thanks
The first one is an implicit intent, while the second is an explicit intent.
The first one fired an Intent for the action com.example.project.MENU. If you look inside you project AndroidManifest.xml you can see some <intent-filter> balise. This baslise register activity, service or broadcast receiver to different actions.
This mecanism can be used to allow third party app to launch some of your activities.
You can see more on this tutorial http://www.vogella.com/tutorials/AndroidIntent/article.html#intenttypes
Basically an Intent carries some information that are used by the system in order to determine which component should be called for executing the action.
These information are:
Component name: the name of the component that should be launched. (If present the Intent is Explicit)
Action: it specifies the generic action that should be executed (es. ACTION_VIEW, ACTION_SEND). It determines how the rest of the intent is strucutred.
Data: represents the URI that refers to the object that should be associated with the action. For example with the action ACTION_EDIT, the Data should contain the URI of the document that you want modify.
Category: Additional infromation (for example if you want that your app is shown in the launcher you can use CATEGORY_LAUNCHER)
Extras: keys-values pairs that carries additional information
Flags: it is like a metadata that specify how the intent should be managed by the system.
The Intent class provides a lot of different constructors.
The first one you asked for is public Intent (String action)
So, this sets the Action, and lets null all other fields.
The second one public Intent (Context packageContext, Class<?> cls) creates an intent for a specific component by its Component name. All other fields are null. This is a Explicit Intent, since you declare exactly which component should receive it.
The first one is used when you need to call Intent from System
such as Open Camera, Gallery, or Share something to other Application
for example
// this one call Camera to Capture Image
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// this one call gallery to let you select image
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
and That MediaStore.something here is just a Path to the system
for example
MediaStore.ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"
Intent.ACTION_PICK = "android.intent.action.PICK"
The first type of intent is mostly used if you want to open another application from your application while the second type of intent is used to open another activity in your application.
I am trying to append certain data to an intent, before using StartActivityForResult on it.
When the intent returns in OnActivityForResult, I would like to access the data I appended in the intent. So I can correlate the data retrieved in the intent, with things like database entries, container ids, etc.
Unfortunately the intent that returns does not seem to be the same one I started. I tried comparing (==) the old and the new intent in a test case, and the result failed, and not surprisingly then the data I am trying append is not there. Is there any link back to the original intent?
Basic idea of what I've tried:
Code to StartActivityForResult in psuedo code:
Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
i.putExtra([-Key-], [int]);
i.putExtra([-Key-], [int]);
....
getParentFragment().startActivityForResult(i, requestCode);
Pseudo Code for OnActivityResult
#Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
....
switch(requestcode){
case RESULT_LOAD_IMAGE :
//These always evaluate to default. The intent returns with the picture,
//and I process it fine (with default values), but any extra data i try to append
//to the intent is lost.
int rowId = intent.getIntExtra([-Key-], [-def_value-]);
....
....
break;
default:
throw new RuntimeException();
}
}
When you launch an Activity using implicit Intent resolution, which is what you are doing when you do this:
Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
....
getParentFragment().startActivityForResult(i, requestCode);
you don't have any guarantees what Activity will actually be chosen to perform the action. Because of this, there isn't any "contract" between your Activity and the Activity that will be used to perform the desired action. This is, unfortunately, one of the disavantages of using implicit Intent resolution. Because there is no contract between the 2 Activities, you can't be sure what you are going to get in the result that is returned to you in onActivityResult().
If you look at the documentation for ACTION_PICK, it at least indicates what "should" happen (if the selected Activity actually behaves the way the documentation reads):
Input: getData() is URI containing a directory of data
(vnd.android.cursor.dir/*) from which to pick an item.
Output: The URI of the item that was picked.
This indicates that you should provide a URI that contains a directory of data and that you will be returned an Intent containing the URI of the item that was picked. That's it. That's all you can expect to get. You can put lots of other "extras" in the Intent that you pass to the Activity with ACTION_PICK, but that Activity doesn't care about those extras and will just ignore them. The Activity that performs the ACTION_PICK will create a new Intent containing the URI of the selected item and pass that back to you. It doesn't pass your original Intent back. The "input Intent" and the "output Intent" are completely different and don't have anything to do with each other.
To solve your problem, I'd suggest that you create a unique integer requestCode and save your "extras" in a table or map in your Activity associated with that requestCode. Then you can launch the ACTION_PICK activity using the requestCode. In onActivityResult() you can use the requestCode argument that comes back to find your "extras" that you saved and you'll be able to associate the returned URI with them.
NOTE: One more thing: When you call startActivityForResult() your Activity will be paused and the launched Activity will run. Your Activity won't be resumed until onActivityResult() is called. This means that you will only ever be able to have one ACTION_PICK pending at any given time. For this reason you may not need a way to associate a specific PICK action with any given data.
I have a question about intent resolution and the difference between Intent.ACTION_PICK_ACTIVITY and Intent.ACTION_CHOOSER (including it's convenience function version, Intent.createChooser()).
I'm writing a "package manager" app. In it I have a ListActivity that displays all packages installed on the device (populated with PackageManager.getInstalledPackages()). I also have a context menu registered on the list, one of whose items is "Launch".
Below is my code from onContextItemSelected() for handling the "Launch" context menu item.
Intent intent ;
List<ResolveInfo> ris ;
int nLauchables ;
int REQUEST_LAUNCH = 1 ; // for use in onActivityResult()
// PackageInfo pi ; // set outside this code
intent = new Intent (Intent.ACTION_MAIN) ;
intent.addCategory (Intent.CATEGORY_LAUNCHER) ;
intent.setPackage (pi.packageName) ; // limit to launchable activities in the package represented by pi
ris = getPackageManager ().queryIntentActivities (intent, 0) ; // get list of launchable activities in pi
nLaunchables = ris.size () ;
if (ris == null || nLaunchables == 0) {
// do nothing (in the real code, the "Launch" item is already disabled in this case, so this never happens)
}
else if (nLaunchables == 1) {
// only 1 launchable activity, so just start that activity
intent.setComponent (new ComponentName (ris.get (0).activityInfo.packageName, ris.get (0).activityInfo.name)) ;
startActivity (intent) ;
}
else if (nLaunchables > 1) {
// mutiple launchable activites, so let the user choose which one they want to launch
// Intent chooseIntent = new Intent (Intent.ACTION_CHOOSER) ;
// chooseIntent.putExtra (Intent.EXTRA_INTENT, intent) ;
// chooseIntent.putExtra (Intent.EXTRA_TITLE, "Select activity") ;
// startActivity (chooseIntent) ; // doesn't show all launchable activities in the package
//
// or
//
// startActivity (Intent.createChooser (intent, "Select activity") ; // doesn't show all launchable activities in the package
Intent pickIntent = new Intent (Intent.ACTION_PICK_ACTIVITY) ;
pickIntent.putExtra (Intent.EXTRA_INTENT, intent) ;
startActivityForResult (pickIntent, REQUEST_LAUNCH) ;
}
I first tried the ACTION_CHOOSER version...but it doesn't always show all launchable activities in the package. For example, Google Maps has 4 launchable activities (Latitude, Maps, Navigation and Places) that show up with ACTION_PICK_ACTIVITY but ACTION_CHOOSER only shows 2 (Latitude, Maps). The only thing I can see that is different between the activities that do show when using ACTION_CHOOSER and those that don't is that they have CATEGORY_DEFAULT in their <intent-filter>s.
Below are the parts of the documentation that I have consulted to understand what is going on:
Docs for CATEGORY_DEFAULT say, in part, "Setting this will hide from the user any activities without it set when performing an action on some data."
This seems to explain the behavior I'm seeing...but...
Docs for ACTION_CHOOSER say, in part, "...all possible activities will always be shown even if one of them is currently marked as the preferred activity." (emphasis mine)
This seems to be in conflict with the above docs for CATEGORY_DEFAULT and suggests that using ACTION_CHOOSER and ACTION_PICK_ACTIVITY should produce the same results....and...
Docs for Intents and Intent Resolution (sorry, as a new user, I'm limited to 2 links in a post, so I can't link to this...just look in the "Intent Resolution" section, "Category test" subsection), says, in part, "Android treats all implicit intents passed to startActivity() as if they contained at least one category: android.intent.category.DEFAULT" (the CATEGORY_DEFAULT constant). Therefore, activities that are willing to receive implicit intents must include android.intent.category.DEFAULT" in their intent filters. (Filters with android.intent.action.MAIN" and android.intent.category.LAUNCHER" settings are the exception. They mark activities that begin new tasks and that are represented on the launcher screen. They can include "android.intent.category.DEFAULT" in the list of categories, but don't need to.)" (emphasis mine)
Again, this seems to explicitly say that using ACTION_CHOOSER and ACTION_PICK_ACTIVITY should produce the same results.
So, is this just a case of incomplete documentation for ACTION_CHOOSER (i.e., that it doesn't mention that CATEGORY_DEFAULT activities are excluded) or is there something else going on?
Using ACTION_PICK_ACTIVITY works for me but is not ideal because of the need for calling startActivityForResult() with it (rather than just startActivity()).
I think your reading of those last two excerpts from the documentation is not the intended meaning. Starting with the ACTION_CHOOSER doc, "...all possible activities will always be shown even if one of them is currently marked as the preferred activity," specifically refers to preferred activities. Normally, when you use an implicit intent, and more than one activity matches, if the user has previously chosen "Always" from a previous chooser for this intent, then you'll get that activity without a chooser. If you use the ACTION_CHOOSER intent, you'll get all the activities that match, even if one has been chosen. That's all this line means: "all possible activities" means all activities that match the intent filter, taking categories into account too. It's simply another explanation of the difference between getting a chooser automatically vs. using ACTION_CHOOSER.
The other part you call out, about android.intent.action.MAIN and android.intent.category.LAUNCHER, doesn't mean that that action and category are handled specially in the intent filtering process. Don't forget that most people reading this documentation are simply writing launchable apps, and need to know what to put in their manifest to get an activity shown in the launcher. The "exception" here isn't an exception to the intent filter rules: it's an exception to the usual behaviour that implicit intents use CATEGORY_DEFAULT, and that's only an exception because launchers set this category (CATEGORY_LAUNCHER) instead of CATEGORY_DEFAULT.
In summary, the whole area of intent resolution is quite underdocumented, as you've found, but there's no inconsistency in the excerpts you've mentioned: they're just talking about slightly different things.
My boss asked me to prove that my application behaves properly when summoned by another application (dunno why he asked that).
So I have two apps here, one launches a second one. How I launch the specific app I want? Using Intent launch seemly any generic app that reaches a certain goal, not the app I really want.
Give this a try.
Intent secondIntent = new Intent();
secondIntent.setAction(Intent.ACTION_MAIN);
secondIntent.setClassName("com.example", "com.example.YourSecondApp");
startActivity(secondIntent);
I should point out that com.example should be the package of your second application (the one you want to call) and com.example.YourSecondapp is the class name where you have your onCreate() method.
Intent secondApp = new Intent("com.test.SecondApp");
startActivity(secondApp);
Check out for more examples
http://developer.android.com/resources/faq/commontasks.html#opennewscreen
Create one Intent using the following code
Explicit Intent
When you know the particular component(activity/service) to be loaded
Intent intent = new Intent();
intent.setClass("className/package name");
start<Activity/Service>(intent);
Imlicit Intent
When we do not have the idea which class to load and we know the Action to be perform by the launched application we can go with this intent.
Action needs to set, and the Android run time fallows the intent Resolution technique and list out(one or more components) the components to perform the action. from the list out components (if more than one), user will get the chance to launch his chosen application