Launching default apps with intents - android

How, in android, do I start an app set as the default (i.e. Handcent for Messaging, Dolphin for browsing)?
I can only find how to use definite package names for intents:
Intent i = new Intent(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_LAUNCHER);
switch (position) {
case 0: //messages
i.setPackage("com.android.mms");
break;
case 1: //inbox
i.setPackage("com.android.email");
break;
case 2: //browser
i.setPackage("com.android.browser");
default:
i = null;
}

How, in android, do I start an app set as the default (i.e. Handcent for Messaging, Dolphin for browsing)?
"Default" is for a specific operation (e.g., sending a message), not for some abstract notion of "Messaging" in general.
Also, the code you are showing above uses things that are not in the SDK (namely, specific packages). Your code will break on some devices, where the device manufacturer has replaced the app. Your code may break in future versions of Android, when the stock apps are refactored or otherwise renamed.
I think you need to reconsider what it is you are trying to accomplish.

You can search for apps that satisfy a given Intent (e.g., ACTION_SEND), decide which one you want, retrieve its component name, and then launch it with a different Intent that specifies the component name.
Start with:
Intent intent = new Intent(...);
List<ResolveInfo> list = getPackageManager().queryIntentActivities(
intent, PackageManager.MATCH_DEFAULT_ONLY);

Related

Permission Denial on SEND action intent

This is the log, I am receving on crash in Samsung running Oero OS:
Fatal Exception: java.lang.SecurityException: Permission Denial:
starting Intent { act=android.intent.action.SEND typ=text/plain
flg=0x80001 pkg=com.google.android.apps.maps
cmp=com.google.android.apps.maps/com.google.android.apps.gmm.sharing.SendTextToClipboardActivity
clip={text/plain T:"XYZ"
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("text/plain");
share.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name));
share.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
share.putExtra(Intent.EXTRA_TEXT, shareMessage);
share.setPackage(packageName);
Please suggest.
Thanks
You have a couple of options here. You can avoid this crash by specifically filtering out the SendTextToClipboardActivity that Google Maps recently added as an intent-handler. (It looks exactly like the genuine Android "Copy to clipboard" share-target, and is most likely the result of a bug on the part of Google Maps.) Or you can filter out any ResolveInfo where the corresponding Activity is not exported; however, this could result in also filtering out share-targets within your own app that you do want to show to the user, in which case you would need to allow non-exported Activities from your own app package.
For example, suppose you have something like this to obtain a list of providers for your ACTION_SEND intent:
PackageManager packageManager = mActivity.getPackageManager();
List<ResolveInfo> providers = packageManager.queryIntentActivities(sendIntent, 0);
You could then filter out providers that are known to cause problems, and/or providers for which the Activity isn't marked as exported. For example, you could use a check such as the following to build your own list of providers to be displayed to the user:
for (ResolveInfo provider : providers) {
if ("com.google.android.apps.maps".equalsIgnoreCase(provider.activityInfo.packageName)
&& "com.google.android.apps.gmm.sharing.SendTextToClipboardActivity".equalsIgnoreCase(provider.activityInfo.name)) {
continue; // Skip specific Activity you don't want to show
}
if (!BuildConfig.APPLICATION_ID.equalsIgnoreCase(provider.activityInfo.packageName) && !provider.activityInfo.exported) {
continue; // Skip providers where the Activity is not marked with exported=true, unless they're from our own app
}
acceptableProviders.add(provider);
}
How to then go about displaying the acceptableProviders as share options is left as an exercise to the reader. The key is filtering out known bad providers.
Meanwhile, you can also contact Google to complain about the bad behavior of this new intent-handler, which is essentially masquerading as the trusted Android text/plain handler used for the "Copy to clipboard" share-target.

DevicePolicyManager.enableSystemApp() method does not work as expected

I'm trying to use enableSystemApp method to activate default system apps after provisioning device with the app that is set to device owner mode.
There are two methods to do this:
1) void enableSystemApp (ComponentName admin, String packageName) - in this case you need to pass package name explicitly as String. It works fine, the app gets enabled.
For example, calling this
devicePolicyManager.enableSystemApp(deviceAdminComponent, "com.google.android.gm");
enables default Gmail client, which is disabled after provisioning.
2) int enableSystemApp (ComponentName admin, Intent intent) - in this case, you need to pass an implicit intent and Android should enable all system apps that match this intent. In addition, this method returns int number of apps that match the intent. And here's the problem - I can't get this method to work, it always returns 0 and doesn't enable anything.
Here's the snippet I'm trying to use:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_APP_EMAIL);
int i = devicePolicyManager.enableSystemApp(deviceAdminComponent, intent);
It does not work and i == 0 in this case. What am I doing wrong?
Any help is appreciated!
Under the hood, the method that accepts an intent queries to get the list of activities that respond to that intent and then loops through the list passing in the package name string to enable the package. It's similar to doing this:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_APP_EMAIL);
List<ResolveInfo> infoes = getPackageManager()
.queryIntentActivities(intent, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
for (ResolveInfo info in infoes) {
devicePolicyManager.enableSystemApp(deviceAdminComponent, info.activityInfo.packageName);
}
Since you are able to enable the app using the package name string, the fault most likely lies in the way the intent is being resolved - which is supported by the fact that it always returns 0.
It is counter-intuitive, but my suspicion is that the application does not resolve the ACTION_MAIN intent because the app is disabled. Have you tried a less generic intent? I would try the following
Intent i;
// #1
// This goes full circle, but I expect it should work
i = getPackageManager().getLaunchIntentForPackage("com.google.an‌​droid.gm")
// #2
i = new Intent(Intent.ACTION_SEND).setPackageName("com.google.android.gm");
// #3
// Generic, but should resolve _all_ email apps - not just the default one.
// The mailto schema filters out non-email apps
i = new Intent(Intent.ACTION_VIEW , Uri.parse("mailto:"));
Option #1 and #2 are more academic. Both require the package name at which point you may as well use the string overload of enableSystemApp. Option #3 is my best guess for something generic that might still work, but it's possible that it still won't work because the app is disabled.
Note: I find it interesting that enableSystemApp only passes the MATCH_DIRECT_BOOT_AWARE and MATCH_DIRECT_BOOT_UNAWARE flags when querying activities that can resolve the intent, because the MATCH_DISABLED_COMPONENTS and MATCH_SYSTEM_ONLY flags seem much more relevant in this situation.

Android packagemanager not launching app

So a few days ago I build an update for my custom android car tablet with my own launcher (based on Nexus 7 2013, Android 5.1.1). I added a few new features and some fixes (which have nothing to do we the activity that causes the problem), and I added accidentally the device admin permission together with the install packages permission.
After the update was installed on the tablet, the device opened always the Android for work app when clicked something which should start an external app (like Spotify or Maps). I thought it might be something with these permission and I deleted them and reinstalled a new version of the app (not updated!), but it didn't worked, it still started the Android for work app.
Then I uninstalled the Android for work app, and now the google now app started. After uninstalling it too, the settings app now launches?!
Has anyone an idea why this is happening and what I can do to get rid of it?
PS: Here is the code I am using to start an app using it's package name which is hundred percent right (there cannot be the failure):
pkg1 = prefs.getString("dash_app_music", null);
....
private View.OnClickListener clickhandler = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_action_1:
Intent i = pm.getLaunchIntentForPackage(pkg1);
startActivity(i);
break;
case R.id.tv_action_2:
Intent i2 = pm.getLaunchIntentForPackage(pkg2);
startActivity(i2);
break;
case R.id.tv_back:
onBackPressed();
break;
}
}
};
Ok it came out that for some reason the package name for the packagemanager which gets the intent was empty and therefore android starts the settings app as a fallback(?).

Unknown sources settings android

The issue is that I need to install an apk(non market app) and for this, the user need to activate the unknown source setting, so i send him (if he didn't have it activated) to the settings so he can turn on the option, the issue is that i tested it in different phones and in samsung that option is on applications while in htcs phones is on security. i want send the user to that option but i don't know how to do it
I read about this and no one knows exactly how to do it
this is my code
int canInstallFromOtherSources = Settings.Secure.getInt(ctx2,Settings.Secure.INSTALL_NON_MARKET_APPS);
if(canInstallFromOtherSources == 0)
{
Intent intentSettings = new Intent();
intentSettings.setAction(android.provider.Settings.ACTION_APPLICATION_SETTINGS);
startActivity(intentSettings);
}
You can do it with the following line (changing to the corresponding action):
startActivityForResult(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), REQUEST_CODE_ENABLE_LOCATION_PROVIDERS);
Check Android Settings documentation.
I think you should use ACTION_SECURITY_SETTINGS and one of ACTION_APPLICATION_SETTINGS or ACTION_APPLICATION_DEVELOPMENT_SETTINGS.
And here (line 304), you've got a working example of one of my apps: Tureame

Obtaining the android:label from other applications

i'm programming an android app, a Tasker, and i really don't find the way to obtain the label of another app. This is my point, i'm using an ListActivity where you select an installed app, then when you click it creates the Intent and all the app stuff, what i wanna do is to show to the user the android:label from the app he selected, i found in ResolverInfo an attribute called .activityInfo.labelRes, and i think is the label descriptor for the R class of the app the user selected, is there anyway to obtain the string that matches to that id???
Thanks!
D.Gómez
You can use the loadLabel(PackageManager) method of ResolveInfo to get the label of an activity. Here's a full example which finds all the launcher activities on the device and prints them to logcat:
// Get the package manager
PackageManager pm = getPackageManager();
// Create an intent that matches all launcher activities
// (and ignores non-launcher activities)
Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
// Get all activites matching the intent
List<ResolveInfo> launchers = pm.queryIntentActivities(launcherIntent, 0);
for(ResolveInfo info : launchers) {
// Get the activity label and print it
CharSequence label = info.loadLabel(pm);
Log.v("LabelTest", "App found: " + label);
}
To answer the second part of your question too, about accessing the resources of an application: They can be accessed by calling getPackageManager().getResourcesForApplication(String), which will return a Resources object that you can use, though in your case, that should not be necessary.

Categories

Resources