android explicit intent by name not resolving to other activity - android

I have 2 apps that are used in conjunction with one another. I want to create a button that launches app A from app B so I am creating an intent like so in app B:
Intent intent = new Intent("com.org.orgmobile.android.action.ACTION_CUSTOM");
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.setData(Uri.parse(url));
startActivity(intent);
where url is https://org.org.com/mobile/Support/action/org/ActionEnumValue/?a=123
the intent filter I have declared in app A's manifest is like so:
<intent-filter>
<action android:name="com.org.orgmobile.android.action.ACTION_CUSTOM"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="https"/>
<data android:host="org.org.com"/>
<data android:pathPrefix="/mobile/Support/action/${manifestplaceholderattr}.*/ActionEnumValue/*"/>
</intent-filter>
and manifestplaceholderattr is an empty string.
I am getting
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.org.orgmobile.android.action.ACTION_CUSTOM dat=https://org.org.com/... flg=0x20000000 }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1936)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1615)
at android.app.Activity.startActivityForResult(Activity.java:4472)
at android.app.Activity.startActivityForResult(Activity.java:4430)
at android.app.Activity.startActivity(Activity.java:4791)
at android.app.Activity.startActivity(Activity.java:4759)
What am I overlooking here? I have tried using pathPattern instead of path prefix with no success.
Edit: to provide more detail, I don't just want to launch that specific activity, I want to match the specific intent associated with that activity to launch the activity. I don't want to launch the activity directly because in the case that the user's app is out of date because it won't have the desired behavior.

Best way to do this through Package manager as below.
PackageManager manager = getPackageManager();
try {
Intent intent = manager.getLaunchIntentForPackage("app B package name here");
if (intent == null)
throw new PackageManager.NameNotFoundException();
intent.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
Package manager checks if app with the given package name is installed, if exists it launches the app else it throws NameNotFoundException

You need to use pathPattern instead of pathPrefix. Also you should use .* instead of * at the end of the pattern:
<data android:pathPattern="/mobile/Support/action/${manifestplaceholderattr}.*/ActionEnumValue/.*"/>
This may also not work. If I recall, pathPattern isn't a real regular expression and you may not be able to match the URL like this. Try it and see. If this doesn't work, you'll probably need to rely on just the first part of the path. Let me know how it goes.
See the documentation on path, pathPattern and pathPrefix.

You need to use code as below to launch other App using custom action.
Intent intent = new Intent();
intent.setAction("com.org.orgmobile.android.action.ACTION_CUSTOM");
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.setData(Uri.parse(url));
startActivity(intent);
Also make sure both of your application is installed. Also it is better to have check as below to make sure application exists on the phone to handle such Intent.
PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
boolean isIntentSafe = activities.size() > 0;

Related

ShowCallLog Intent not working when handled by "com.android.contacts"

I am trying to open the call logs activity from my app using an intent and startActivity(ForResult).
It does work fine, except on some devices.
After investigation, I noticed that when the intent resolve to this class:
ComponentName("com.android.contacts", "com.android.contacts.NonPhoneActivity")
then startActivity (or startActivityForResult) has "no effect" / the CallLogs is NOT displayed.
As per the name 'NonPhoneActivity', this makes sense I guess..
(info about this NonPhoneActivity activity :
https://android.googlesource.com/platform/packages/apps/Contacts/+/master/AndroidManifest.xml )
Here is the code (FYI, with startActivityForResult; I observe the same behavior with startActivity:
additionalButtonsBinding.phoneSelectContactFragmentButtonsMissedCallButton.setOnClickListener(v -> {
Intent showCallLog = new Intent();
showCallLog.setAction(Intent.ACTION_VIEW); // "android.intent.action.VIEW"
showCallLog.setType(CallLog.Calls.CONTENT_TYPE); // "vnd.android.cursor.dir/calls"
showCallLogLauncher.launch(showCallLog);
});
showCallLogLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
// result is always {resultCode=RESULT_CANCELED, data=null}
// may the CallLogs be shown OR not
// so startActivityForResult is useless: just here fore investigation purpose and completeness of my question
Log.d(TAG, result.toString());
}
});
Questions:
Why does the CallLogs intent resolve to ComponentName("com.android.contacts", "com.android.contacts.NonPhoneActivity")... even on a Phone!
On emulator, the intent resolve to
"com.android.dialer",com.android.dialer.main.impl.MainActivity",
which is able to display CallLogs.
Since ("com.android.contacts", "com.android.contacts.NonPhoneActivity") is sometimes/often the only component (*) able to handle Intent { act=android.intent.action.VIEW typ=vnd.android.cursor.dir/calls } , should I use another intent (another action) to display CallLogs?Which other Intent should I use to display CallLogs?
*: as per result PackageManager.queryIntentActivities(showCallLog, PackageManager.MATCH_ALL) , which is a list with only one item, being "com.android.contacts", "com.android.contacts.NonPhoneActivity"
Nailed it (almost):
When Google Dialer (Google Phone) app is installed, the following intent action is available: com.android.phone.action.RECENT_CALLS:
Intent googleDialerShowRecent = new Intent("com.android.phone.action.RECENT_CALLS");
if (context.getPackageManager().queryIntentActivities(googleDialerShowRecent, PackageManager.MATCH_ALL).size() > 0) {
showCallLogLauncher.launch(googleDialerShowRecent);
}
I just do not knwow how to force the Google Phone app to display the 'History'/'Recent calls' tab on launch.
Google Phone's manifest excerpt:
<activity
android:name="com.android.dialer.main.impl.MainActivity"
...>
<intent-filter android:label="#ref/0x7f150123">
<action android:name="com.android.phone.action.RECENT_CALLS" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.TAB" /> TAB HERE - Could I send some EXTRA in INTENT to force Google Dialer to display the 'recent call' TAB?
</intent-filter>
Question:
In manifest we can see this: <category android:name="android.intent.category.TAB" />
How could I use this to force Google Phone app to display the 'recent call' TAB? Adding some EXTRA in the Intent? which one?
(I know, we do not have source code of Google Phone app, but, hopefully they use some standard system / naming convention for EXTRA's in Intent)..
Anyone?

Unable to launch arbitrary activity since Android 13

I have a little personal app I built which allows me to specify different browsers for different URLs. Up until Android 13, it was working fine, but at some point after Android 13 it started failing. I suspect it's related to the app's authority (or lack thereof) to launch an arbitrary Activity, but wading through the docs has yielded zilch.
The process works like this:
I query all activities for an Intent that has a URI as its data property
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri); // uri is some location like 'https://www.google.com'
PackageManager pm = context.getPackageManager();
List<ResolveInfo> allTargets = pm.queryIntentActivities(intent, PackageManager.MATCH_ALL);
I loop through allTargets looking for the browser I want based on its name:
ResolveInfo target = null;
for (ResolveInfo b : allTargets) {
String appName = b.loadLabel(pm).toString();
// targetBrowserName will be something like "Chrome"
if(appName.equalsIgnoreCase(targetBrowserName)) {
target = b;
break;
}
}
I then attempt to launch this browser, with the url
ActivityInfo activity = target.activityInfo;
ComponentName name = new ComponentName(activity.applicationInfo.packageName, activity.name);
targetIntent = new Intent(Intent.ACTION_MAIN);
targetIntent.addCategory(Intent.CATEGORY_LAUNCHER);
targetIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
targetIntent.setComponent(name);
targetIntent.setData(uri);
startActivity(targetIntent);
This now fails with an error like:
android.content.ActivityNotFoundException: Unable to find explicit activity class {com.android.chrome/com.google.android.apps.chrome.IntentDispatcher}; have you declared this activity in your AndroidManifest.xml, or does your intent not match its declared <intent-filter>?
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4803)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4836)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:54)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7898)
at java.lang.reflect.Method.invoke(Native Method)
I've tried various permutations of the launch code (which, as a reminder, was working fine). E.g.
targetIntent = pm.getLaunchIntentForPackage(activity.applicationInfo.packageName);
targetIntent.setAction(Intent.ACTION_VIEW);
targetIntent.addCategory(Intent.CATEGORY_BROWSABLE);
targetIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
But I still get the same error (although in the above case with a different Activity class that is still fails to find)
I understand there are constraints on App visibility, but I assumed I was covered as I have this in my AndroidManifest.xml
<!-- As per guidelines, QUERY_ALL_PACKAGES is required to list all browsers -->
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
Reading the docs, I noted that I didn't have a <queries> element in the manifest (is that new?), so I added this:
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
</queries>
No joy.
Does anyone know the correct way to launch a known/specific [browser] app based programmatically? Or maybe what changed in Android 13 to make this code work again?
Thanks!
Edit following correct answer below
The guidance provided in the answer below worked. This is a summarized version of the final code:
// Create an intent with the destination URL
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
// List all activities that support this intent, and choose one:
PackageManager pm = context.getPackageManager();
List<ResolveInfo> allTargets = pm.queryIntentActivities(intent, PackageManager.MATCH_ALL);
ResolveInfo target = null;
for (ResolveInfo b : allTargets) {
String appName = b.loadLabel(pm).toString();
// targetBrowserName is something like "Chrome"
if(appName.equalsIgnoreCase(targetBrowserName)) {
target = b;
break;
}
}
// Set the specific component to be launched
ActivityInfo activity = target.activityInfo;
ComponentName name = new ComponentName(activity.applicationInfo.packageName, activity.name);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
intent.setComponent(name);
// Start
startActivity(intent);
Seems to be related to this behavior change https://developer.android.com/about/versions/13/behavior-changes-13#intent-filters
When your app sends an intent to an exported component of another app that targets Android 13 or higher, that intent is delivered if and only if it matches an element in the receiving app. Non-matching intents are blocked.
To make sure this is indeed your issue check logcat for the tag PackageManager. Something like W/PackageManager( 1828): Access blocked: ComponentInfo{com.android.chrome/com.google.android.apps.chrome.Main} should appear there
I didn't look too much into how it works yet, but seems like now we need to query external activities before using them unless they don't have intent-filters. That's going to "activate" the component and then the intent you use needs to "match" the other apps intent-filter:
Intents are matched against intent filters not only to discover a target component to activate, but also to discover something about the set of components on the device. For example, the Home app populates the app launcher by finding all the activities with intent filters that specify the ACTION_MAIN action and CATEGORY_LAUNCHER category. A match is only successful if the actions and categories in the Intent match against the filter, as described in the documentation for the IntentFilter class.
https://developer.android.com/guide/components/intents-filters#imatch
I was having a similar issue. The reason for it not to work was that I modified the Uri by calling intent.setData after the call to queryIntentActivities. Seems like this is invalidating the activation of the component.
Summary: not calling intent.setData after the queryIntentActivities makes the intent work
There was an error
Unable to find explicit activity class {com.google.android.apps.translate/com.google.android.apps.translate.TranslateActivity}; have you declared this activity in your AndroidManifest.xml, or does your intent not match its declared <intent-filter>?
In my case help to remove intent.addCategory(Intent.CATEGORY_LAUNCHER) for Android 13
final Intent intent = new Intent();
intent.setAction(Intent.ACTION_PROCESS_TEXT);
intent.setType("text/plain");
//Fix for Android 13
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
intent.addCategory(Intent.CATEGORY_LAUNCHER);
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
intent.setComponent(name);
intent.putExtra(Intent.EXTRA_TEXT, selecteText);
intent.putExtra(Intent.EXTRA_PROCESS_TEXT, selecteText);
intent.putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, selecteText);
a.startActivity(intent);
If you're running a SDK target below 33 do:
if (Build.VERSION.SDK_INT < 33) {
intent.addCategory(Intent.CATEGORY_LAUNCHER)
}
Add schema to your intent filter in your exported activity.
That help me for SDK 33
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="https"/>
</intent-filter>

How to set default app launcher programmatically?

I am creating a launcher (kiosk) app that will be downloadable through google. When first installing this application the user has the ability of choosing which launcher (mine or the stock) will be the default. I am trying to bring this up manually if the user does not make my application the default launcher. I want the user to be forced into selecting ALWAYS instead of JUST ONCE when that dialog comes up, otherwise the dialog will continue to appear periodically with a friendly message. This is what I have attempted so far.
I created a method to check for if my application is the default
/**
* method checks to see if app is currently set as default launcher
* #return boolean true means currently set as default, otherwise false
*/
private boolean isMyAppLauncherDefault() {
final IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
filter.addCategory(Intent.CATEGORY_HOME);
List<IntentFilter> filters = new ArrayList<IntentFilter>();
filters.add(filter);
final String myPackageName = getPackageName();
List<ComponentName> activities = new ArrayList<ComponentName>();
final PackageManager packageManager = (PackageManager) getPackageManager();
packageManager.getPreferredActivities(filters, activities, null);
for (ComponentName activity : activities) {
if (myPackageName.equals(activity.getPackageName())) {
return true;
}
}
return false;
}
Then I make the attempt of launching the chooser
/**
* method starts an intent that will bring up a prompt for the user
* to select their default launcher. It comes up each time it is
* detected that our app is not the default launcher
*/
private void launchAppChooser() {
Log.d(TAG, "launchAppChooser()");
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
When I do this I am not receiving the choice between my app and the stock launcher. I tried using startActivity(Intent.createChooser(intent, "Please set launcher settings to ALWAYS")); and I get the choices between my app and the stock launcher, however, I don't get the options ALWAYS or JUST ONCE.
I can create a custom dialog for this instead of launching chooser but I need to know how to set the default app launcher programmatically. Thanks in advance!
This is actually possible with a little workaround:
Create an empty Activity that acts as a launcher called FakeLauncherActivity. Add it to your manifest as a disabled component:
<activity
android:name="com.path.to.your.FakeLauncherActivity"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Check whether your desired launcher activity is the default one (with the isMyAppLauncherDefault() from your question).
If not, offer the user to choose the preferred launcher activity like this:
public static void resetPreferredLauncherAndOpenChooser(Context context) {
PackageManager packageManager = context.getPackageManager();
ComponentName componentName = new ComponentName(context, com.path.to.your.FakeLauncherActivity.class);
packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Intent selector = new Intent(Intent.ACTION_MAIN);
selector.addCategory(Intent.CATEGORY_HOME);
selector.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(selector);
packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, PackageManager.DONT_KILL_APP);
}
This method temporarily enables FakeLauncherActivity, which leads to a change in the set of available launcher activities, which forces Android to forget its default launcher. You will see something like...
521-735/system_process I/PackageManager﹕ Result set changed, dropping preferred activity for Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000000 } type null
... in your log.
The method then simply opens a launcher intent where you can see all installed launchers and the buttons "Always" / "Just once".
Finally, the method disables FakeLauncherActivity again so that it doesn't display in the list.
You could repeat that as often as you want and only let the user proceed if your desired launcher activity is set as default.
The isMyAppLauncherDefault() function in the question doesn't always work for some reason.
This code might be better for determining what is the default package for the HOME screen.
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
ResolveInfo resolveInfo = getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
String currentHomePackage = resolveInfo.activityInfo.packageName;
I want the user to be forced into selecting ALWAYS instead of JUST ONCE when that dialog comes up
That is not possible, except perhaps on rooted devices, barring some security flaw in Android.
When I do this I am not receiving the choice between my app and the stock launcher
Correct. If a default has already been chosen, this will simply launch the default.
I tried using startActivity(Intent.createChooser(intent, "Please set launcher settings to ALWAYS")); and I get the choices between my app and the stock launcher, however, I don't get the options ALWAYS or JUST ONCE.
Correct. createChooser() forces a choice, but does not allow setting a default.
Android Q (API 29) has RoleManager. Let's say your app is a Launcher.
[AndroidManifest.xml]
<activity
... />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
private val startForResult = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
// Perhaps log the result here.
}
}
private fun showLauncherSelection() {
val roleManager = requireActivity().getSystemService(Context.ROLE_SERVICE)
as RoleManager
if (roleManager.isRoleAvailable(RoleManager.ROLE_HOME) &&
!roleManager.isRoleHeld(RoleManager.ROLE_HOME)
) {
val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME)
startForResult.launch(intent)
}
}
When you call showLauncherSelection(), you should see a dialog similar to the following.
There are other roles, such as ROLE_BROWSER, ROLE_DIALER, ROLE_SMS, and such.
If you are implementing Google EMM solution (Dedicated Device):
https://developer.android.com/work/dpc/dedicated-devices/cookbook
// Create an intent filter to specify the Home category.
IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
filter.addCategory(Intent.CATEGORY_HOME);
filter.addCategory(Intent.CATEGORY_DEFAULT);
// Set the activity as the preferred option for the device.
ComponentName activity = new ComponentName(context, KioskModeActivity.class);
DevicePolicyManager dpm =
(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.addPersistentPreferredActivity(adminName, filter, activity);

Launch Main Activity with Implicit Intent in Service

I have an implicit intent in a service that sends information to my main activity, as well as to another class. I also now want that intent to launch my main activity. I've looked at the myriad posts related to this, and tried lots of different things--addCategory, setAction(MAIN; the activity's name; you name it, I've tried it...), category.DEFAULT in the manifest, and several other things that either resulted in ActivityNotFoundExceptions (most commonly) or behavior that was otherwise undesirable.
Here's where the intent is set up and the relevant part of the manifest. The receiver for the intent is registered in the main activity.
final String NEW_DOSES = "changed to protect the innocent";
Intent bluetoothBroadcast = new Intent();
several putExtra lines here
bluetoothBroadcast.setAction(NEW_DOSES);
sendBroadcast(bluetoothBroadcast);
<activity
android:name=".AsthmaAppActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Is it possible to get this intent to launch my main activity with relatively minor changes? Thanks in advance.
Yes it is possible but no with sendBroadcast(bluetoothBroadcast); sendBroadcast does not launch an activity. You must use startActivity to achieve this. For example here is what a launcher application will do in order to launch an application:
public static void LaunchApplication(Context cx, String packagename) {
PackageManager pm = cx.getPackageManager();
Intent i = pm.getLaunchIntentForPackage(ai.packageName);
if (i != null) cx.startActivity(i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
You can easily adjust the extras and the data needed in order to launch the activity. For example if your activity is named myActivity then you can go like this:
Intent i = new Intent(cx, myActivity.class);
//Put the extras and the data you want here...
//If you are launching the activity from a receiver component you must use
//i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
cx.startActivity(i);
Hope this helps...

Start Activity Using Custom Action

I am looking to start an activity in my app using a custom action. I have found a few answers but everything I try it throws java.lang.RuntimeException saying No Activity found to handle Intent { act=com.example.foo.bar.YOUR_ACTION }.
This is the activity in my manifest file:
<activity
android:name=".FeedbackActivity" >
<intent-filter>
<action android:name="com.example.foo.bar.YOUR_ACTION" />
</intent-filter>
</activity>
And this is how I'm starting the activity:
Intent intent = new Intent("com.example.foo.bar.YOUR_ACTION");
startActivity(intent);
Any help would be greatly appreciated.
I think what you need is to add a default category to your intent-filter,
eg.
<activity
android:name=".FeedbackActivity" >
<intent-filter>
<action android:name="com.example.foo.bar.YOUR_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
see this answer for more info.
I think you are creating your intent wrong. Try like this:
String CUSTOM_ACTION = "com.example.foo.bar.YOUR_ACTION";
//Intent i = new Intent(this, FeedBackActivity.class); // <--- You might need to do it this way.
Intent i = new Intent();
i.setAction(CUSTOM_ACTION);
startActivity(i);
Just add and intent-filter category as Default.
Implicit intent works perfectly and in many cases its better to use a implicit intent with Intent-action to call a service/Activity than using class-name.
Before startActivty() / startService() with proper context you cane use this method 'queryIntentActivities(Intent intent, int flags)' from package manager class.
It helps the ActivityManager (responsible for launching activities) to check whether the Android system is getting any match with you Intent.
If it doesn't it returns a list size 0 or else >0.
By this you can also check if your app is getting the call,and in this case even if your app is not installed / has got some problem, it will not crash but will throw a warning in Log. Users will face no big trouble apart from app not being launched.
(users will never forgive you if tour app crashes).
Hope this will help !!!
Happy Coding. :)
I faced the same problem when trying to launch the activity residing in the dynamic feature module and starting through action String as the Activity is not resolvable by name at compile time.
So I set the action but the activity crashes every time (No Activity found to handle intent bla bla.. ) until I set the correct package name.
Context c = getApplicationContext();// flag would be require Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag
Intent i = new Intent(action_string);
i.setPackage(context.getPackageName());//this did the trick actually
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
In the Manifest : add catrgory default to the intent filters
from google docs:
<category android:name="android.intent.category.DEFAULT"/>
Note: In order to receive implicit intents, you must include the CATEGORY_DEFAULT category in the intent filter. The methods startActivity() and startActivityForResult() treat all intents as if they declared the CATEGORY_DEFAULT category. If you do not declare it in your intent filter, no implicit intents will resolve to your activity.

Categories

Resources