I am trying to get the default/preferred application for a given Intent. For example, when the user installs a second web browser, then attempts to open a URL, he or she will get a dialog like this:
If the user then selects the Use by default for this action option, then the dialog box no longer opens when a URL is pressed.
I am working on an application that should be aware of what this default or preferred app/action is. How do I do this? I am currently using the code below, but getPreferredPackage doesn't return anything:
Intent i = (new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"));
PackageManager pm = context.getPackageManager();
final List<ResolveInfo> list = pm.queryIntentActivities(i, 0);
IntentFilter ifilter = new IntentFilter(i.getAction());
if (i.getCategories() != null) {
for(String category : i.getCategories()) {
ifilter.addCategory(category);
}
}
List<IntentFilter> filters = new ArrayList<IntentFilter>();
filters.add(ifilter);
List<ComponentName> preferredActivities = new ArrayList<ComponentName>();
pm.getPreferredActivities(filters, preferredActivities, null);
for (ComponentName activity : preferredActivities) {
for (ResolveInfo rinfo : list) {
if (rinfo.activityInfo.applicationInfo.packageName.equals(activity.getPackageName())) {
try {
final PackageInfo pi = pm.getPackageInfo(activity.getPackageName(), 0);
Toast.makeText(context, pm.getApplicationLabel(pi.applicationInfo), Toast.LENGTH_SHORT).show();
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
}
What am I doing wrong? Is this even the right approach?
Well, the solution turned out to be much simpler than I made it (although this is very poorly documented). The following code is my solution:
Intent i = (new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com"));
PackageManager pm = context.getPackageManager();
final ResolveInfo mInfo = pm.resolveActivity(i, 0);
Toast.makeText(context, pm.getApplicationLabel(mInfo.activityInfo.applicationInfo), Toast.LENGTH_LONG).show();
The method launchUrlInDefaultBrowser below launches a URL without displaying any selection query for the user. First, it tries to find the user's default browser app and launch the URL with it. Second, if there was no default app, it lists all the capable activities for launching the URL and picks up the first one. In case an activity was launched, the method returns true; otherwise, false.
boolean launchUrlInDefaultBrowser(Context context, String url) {
final Intent browserIntent = new Intent(Intent.ACTION_VIEW);
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
browserIntent.setData(Uri.parse(url));
// 1: Try to find the default browser and launch the URL with it
final ResolveInfo defaultResolution = context.getPackageManager().resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (defaultResolution != null) {
final ActivityInfo activity = defaultResolution.activityInfo;
if (!activity.name.equals("com.android.internal.app.ResolverActivity")) {
browserIntent.setClassName(activity.applicationInfo.packageName, activity.name);
context.startActivity(launchIntent);
return true;
}
}
// 2: Try to find anything that we can launch the URL with. Pick up the first one that can.
final List<ResolveInfo> resolveInfoList = context.getPackageManager().queryIntentActivities(browserIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (!resolveInfoList.isEmpty()) {
browserIntent.setClassName(resolveInfoList.get(0).activityInfo.packageName, resolveInfoList.get(0).activityInfo.name);
context.startActivity(browserIntent);
return true;
}
return false;
}
Beware, the OEMs may have their own ResolverActivity implementation. E.g. Huawei has com.huawei.android.internal.app.HwResolverActivity.
In Kitkat AOSP, getPreferredPackages() always returns empty list. Source code as below
public List<PackageInfo> getPreferredPackages(int flags) {
return new ArrayList<PackageInfo>();
}
Related
I just linked some social networks to my app as a preliminary test and using the same kind of code, the results I am getting are different for Facebook, Instagram and Twitter intents.
When I click Facebook or Twitter, it opens the app automatically when it's installed and uses browser when it's not. However, that's not the case with Instagram. The complete action using dialog pops up and that's not something I want to happen.
protected void LaunchInstagram() {
String InstagramUsername = "USERNAME";
String LaunchInstagram = "http://instagram.com/_u/" + InstagramUsername;
String InstagramURL = "https://instagram.com/" + InstagramUsername;
try {
this.getPackageManager().getPackageInfo("com.instagram.android", 0);
Uri Uri = Uri.parse(LaunchInstagram);
startActivity(new Intent(Intent.ACTION_VIEW, Uri));
} catch (PackageManager.NameNotFoundException InstagramAppNotFoundOpenBrowser) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(InstagramURL)));
}
}
You are using
String InstagramURL = "https://instagram.com/" + InstagramUsername;
So every Intent you'll try to launch, will open a chooser because this is a URL.
than every App that supports URL, like browsers and such, will try to handle that.
EDIT 1:
Try it this way:
public static boolean openApp(Context context, String packageName) {
PackageManager manager = context.getPackageManager();
try {
Intent i = manager.getLaunchIntentForPackage(packageName);
if (i == null) {
return false;
//throw new PackageManager.NameNotFoundException();
}
i.addCategory(Intent.CATEGORY_LAUNCHER);
context.startActivity(i);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
I'm not sure if that will help you to open a specific user page on the App thou.
EDIT 2:
Try it this way:
Uri uri = Uri.parse("http://instagram.com/_u/USERNAME");
Intent insta = new Intent(Intent.ACTION_VIEW, uri);
insta.setPackage("com.instagram.android");
startActivity(insta);
Good day!
Are there some tools in Android SDK, that i can use to remove application from activity. In particular, i need activity method, that removes other application with the same app-name, but other package.
If you mean with "same name app" to app with same label that define in XML menifest as the label of your app, this snippest should work:
private void deleteAppByActivityName(#NonNull String myAppLabel,#NonNull Context context){
try {
PackageManager pm = context.getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> dataInDevice = pm.queryIntentActivities(mainIntent, 0);
for (ResolveInfo resolveInfo : dataInDevice){
String label = resolveInfo.loadLabel(pm).toString();
if (label.equals(myAppLabel)) { //we find app with same name as ours
Intent intent = new Intent(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:" + resolveInfo.activityInfo.packageName));
context.startActivity(intent);
break;
}
}
}catch (ActivityNotFoundException e){
e.printStackTrace();
}
}
I've kept a button which takes user to my facebook page.
In order that the official facebook app is opened I use the following url:
fb://pages/PAGE_ID
instead of http://facebook.com/PAGE_ID
Because in that case you get a list of browsers to open the url instead of teh facebook app.
It works if the user has facebook app installed. However it crashes if the user doesn't have facebook app.
Is there any way to check if the user has the facebook app?
Have you already checked this?
You can always check if an app is installed like this.
In an native android app, this is quite easy to achieve:
Uri dataUri = Uri.parse("fb://....");
Intent receiverIntent = new Intent(Intent.ACTION_VIEW, dataUri);
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(receiverIntent, 0);
if (activities.size() > 0) {
startActivity(receiverIntent);
} else {
Uri webpage = Uri.parse("http://www.facebook.com/...");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
packageManager = getPackageManager();
activities = packageManager.queryIntentActivities(webIntent, 0);
if (activities.size() > 0) {
startActivity(webIntent);
}
}
I think you can reuse this code I wrote for checking if twitter app was installed on the device, to check if facebook app is installed. For twitterApps list you have to replace the values by "com.facebook.katana".
public Intent findTwitterClient() {
final String[] twitterApps = { "com.twitter.android", "com.handmark.tweetcaster", "com.seesmic", "com.thedeck.android", "com.levelup.touiteur", "com.thedeck.android.app" };
Intent tweetIntent = new Intent(Intent.ACTION_SEND);
tweetIntent.putExtra(Intent.EXTRA_TEXT, "#hashtagTest");
tweetIntent.setType("text/plain");
final PackageManager packageManager = getPackageManager();
List<ResolveInfo> list = packageManager.queryIntentActivities(tweetIntent, PackageManager.MATCH_DEFAULT_ONLY);
for (int i = 0; i < twitterApps.length; i++) {
for (ResolveInfo resolveInfo : list) {
String p = resolveInfo.activityInfo.packageName;
if (p != null && p.startsWith(twitterApps[i])) {
tweetIntent.setPackage(p);
return tweetIntent;
}
}
}
return null;
}
My application evokes the android PackageManager when a file is chosen and the user is presented with a choice of applications to handle how the file should be dealt with. I want to limit this choice to Bluetooth. Currently Bluetooth comes up as the first option which is fine and this all works. I was wondering if its possible to only present the user with this single option.
case REQUEST_FILE_SELECT:
if (requestCode == REQUEST_FILE_SELECT) {
// Get the Uri of the selected file
Uri uri = data.getData();
Log.d(TAG, "File Uri: " + uri.toString());
// Get the path
String path = null;
try {
path = FileUtils.getPath(this, uri);
} catch (URISyntaxException e) {
e.printStackTrace();
}
Log.d(TAG, "File Path: " + path);
// Get the file instance
File mFile = new File(path);
// Evoke the file chooser
List<Intent> targetedShareIntents = new ArrayList<Intent>();
Intent shareIntent = new Intent(
android.content.Intent.ACTION_SEND);
shareIntent.setType("*/*");
// Evoke the package manager
List<ResolveInfo> resInfo = getPackageManager()
.queryIntentActivities(shareIntent,
PackageManager.GET_ACTIVITIES);
if (!resInfo.isEmpty()) {
for (ResolveInfo resolveInfo : resInfo) {
String packageName = resolveInfo.activityInfo.packageName;
if (packageName.equals("com.android.bluetooth")) {
Intent targetedShareIntent = new Intent(
android.content.Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM,
Uri.fromFile(mFile));
targetedShareIntent.setPackage(packageName);
targetedShareIntents.add(targetedShareIntent);
startActivity(Intent.createChooser(shareIntent,
"Share File"));
}
}
}
}
Solution: find out which apps does the device support for your intent, find the one that is bluetooh, invoke it directly.
This article answers your question:
http://tsicilian.wordpress.com/2012/11/06/bluetooth-data-transfer-with-android/
From the article:
We can see that the BT application is among those handlers. We could of course let the user pick that application from the list and be done with it. But if we feel we should be a tad more user-friendly, we need to go further and start the application ourselves, instead of simply displaying it in a midst of other unnecessary options…But how?
One way to do that would be to use Android’s PackageManager this way:
//list of apps that can handle our intent
PackageManager pm = getPackageManager();
List appsList = pm.queryIntentActivities( intent, 0);
if(appsList.size() > 0 {
// proceed
}
The above PackageManager method returns the list we saw earlier of all activities susceptible to handle our file transfer intent, in the form of a list of ResolveInfo objects that encapsulate information we need:
//select bluetooth
String packageName = null;
String className = null;
boolean found = false;
for(ResolveInfo info: appsList){
packageName = info.activityInfo.packageName;
if( packageName.equals("com.android.bluetooth")){
className = info.activityInfo.name;
found = true;
break;// found
}
}
if(! found){
Toast.makeText(this, R.string.blu_notfound_inlist,
Toast.LENGTH_SHORT).show();
// exit
}
We now have the necessary information to start BT ourselves:
//set our intent to launch Bluetooth
intent.setClassName(packageName, className);
startActivity(intent);
What we did was to use the package and its corresponding class retrieved earlier. Since we are a curious bunch, we may wonder what the class name for the “com.android.bluetooth” package is. This is what we would get if we were to print it out: com.broadcom.bt.app.opp.OppLauncherActivity. OPP stands for Object Push Profile, and is the Android component allowing to wirelessly share files.
Also in the article, how to enable the bluetooth from your application.
How would one go about launching the browser from an activity without specifying a url. I would like to open the browser so the user can continue browsing without changing the page they were on?
SOLUTION:
Answer below was correct and worked, but to be more specific for future readers, here is the working code:
Intent i = new Intent();
i.setAction(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_LAUNCHER);
i.setAction("com.android.browser");
ComponentName comp = new ComponentName("com.android.browser", "com.android.browser.BrowserActivity");
i.setComponent(comp);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Thanks!
Use Intent#setComponent() to set the Browser's package and class name. Then start the activity.
In case it (the ComponentName("com.android.browser", "com.android.browser.BrowserActivity")) changes in the future, you may try something like the following code:
public static ComponentName getDefaultBrowserComponent(Context context) {
Intent i = new Intent()
.setAction(Intent.ACTION_VIEW)
.setData(new Uri.Builder()
.scheme("http")
.authority("x.y.z")
.appendQueryParameter("q", "x")
.build()
);
PackageManager pm = context.getPackageManager();
ResolveInfo default_ri = pm.resolveActivity(i, 0); // may be a chooser
ResolveInfo browser_ri = null;
List<ResolveInfo> rList = pm.queryIntentActivities(i, 0);
for (ResolveInfo ri : rList) {
if (ri.activityInfo.packageName.equals(default_ri.activityInfo.packageName)
&& ri.activityInfo.name.equals(default_ri.activityInfo.name)
) {
return ri2cn(default_ri);
} else if ("com.android.browser".equals(ri.activityInfo.packageName)) {
browser_ri = ri;
}
}
if (browser_ri != null) {
return ri2cn(browser_ri);
} else if (rList.size() > 0) {
return ri2cn(rList.get(0));
} else if (default_ri == null) {
return null;
} else {
return ri2cn(default_ri);
}
}
private static ComponentName ri2cn(ResolveInfo ri) {
return new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
}
Basically, here I construct an intent to view a dummy http page, get the list of activities that may handle the intent, compare it to the default handler returned by resolveActivity() and return something. I do not need to check if there's a launcher MAIN action (my code uses the VIEW action), but you probably should.
this answer may help. from How to open the default android browser without specifying an URL?
PackageManager pm = getPackageManager();
Intent queryIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
ActivityInfo af = queryIntent.resolveActivityInfo(pm, 0);
Intent launchIntent = new Intent(Intent.ACTION_MAIN);
launchIntent.setClassName(af.packageName, af.name);
startActivity(launchIntent);