The Android#startActivity(Intent) is specified to throw android.content.ActivityNotFoundException if there was no Activity found to run the given Intent.
I therefore have code like
try {
// Try to start activity provided by external app:
startActivity(intent);
} catch (ActivityNotFoundException e) {
// [...] Inform user about external app needed
// for this functionality to work.
}
which catches ActivityNotFoundException to handle the case where the external app is not installed.
However, from the Crashes & ANRs section of the Google Play Developer Console I'm starting to get crashes as IllegalArgumentException: Unknown component com.example.package/com.example.package.Activity. Should code invoking startActivity() be ready to handle that exception as well? Is this a framework bug (or documentation error)?
This exception generally arises when you haven't declared it in your manifest file. So, try doing it
Somewhere inside your application tag do this
<activity
android:name="Your_Activity_Name"
android:theme="Whatever your theme is"
</activity>
If its any other issue please let me know.
You can use this code to check it. This is the better approach then handling exception
List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0)
{
// start your activity
}
Related
I have 2 different apps in 2 different Application Projects in Eclipse. I will call them H and G. Until now, I have been able to launch H from G by using
Intent intent = getPackageManager().getLaunchIntentForPackage("com.xxx.h");
startActivity(intent);
This has been working great, but in reality, I don't really need the H app to launch, I just need to do something with that app in the background, so I started looking into services. So now I am trying to use
Intent intent = new Intent();
intent.setClassName("com.xxx.h","com.xxx.h.MyService");
startService(intent);
But now I am getting the error saying
W/ActivityManager(1044): Unable to start service Intent { cmp=com.xxx.h/.MyService } U=0: not found
Very new to Services and even Intents so I am guessing it is something simple that I am missing and hoping you guys can help.
EDIT
I fixed the issue with is saying that I was unable to start service intent. That was fixed by including
service android:name=".MyService"
to the AndoirdManifest.xml in H. Now I am getting
E/AndroidRuntime(1022): java.lang.IllegalStateException: Could not execute method of the activity
EDIT 2
Found out it was not letting me start without permission so I had to include android:exported="true" in the AndroidManifest.xml as well
Try this:
private void startService(String aServiceName) {
if (aServiceName.trim().length() > 0) {
try {
Context ctx = getApplicationContext();
Intent iServiceIntent = this.ctx.getPackageManager().getLaunchIntentForPackage(aServiceName);
ctx.startActivity(iServiceIntent);
Thread.sleep(800);
} catch (Exception e) {
}
}
}
The initial problem of it being unable to start the service was because I did not include the <service> to the AndroidManifest.xml which fixed that issue, and then the could not execute error was caused by a permissions issue. So all in all, all it took to fix my issues was including
<service
android:name=".MyServiceHomework"
android:exported="true"
/>
To the AndroidManifest.xml of my H (the service) project
I post this question here for educational purposes, since I couldn't find answers anywhere and eventually found the root cause the old way, i.e. by myself.
Here's the problematic code :
// initially getting the intent from polling the PackageManager about activities resolving Search intent.
ComponentName componentName = intent.resolveActivity(pm);
if (componentName != null) {
context.startActivity(intent);
}
despite the check i get an ActivityNotFound exception.
EDIT: apparently the point wasn't obvious to everyone so : how come there's an activity resolving the intent, yet trying to launch it throws an ActivityNotFound exception - two facts apparently contradictory ?
From what i could see, intent.resolveActivity() will return true if there is ANY activity resolving this intent. Even if this activity is not exported (which makes it unusable for all practical purposes in case it's not from your package).
Android's API doesn't care to mention that, so you have to figure it out by yourself, and make sure that the activity you're trying to launch is indeed exported.
ActivityInfo activityInfo = intent.resolveActivityInfo(pm, intent.getFlags());
if (activityInfo.exported) {
doSomething();
}
EDIT: the point of this question is that ResolveActivity will return a componentName even if activityInfo.exported==false AND it's not from your own package - which makes it unlaunchable, and surprised me cause the intent was resolved and yet unlaunchable.
ActivityNotFound exception is thrown when a call to startActivity(Intent) or one of its variants fails because an Activity can not be found to execute the given Intent. For example, if you’re trying to send an email, but there is no app on your device that could process ACTION_SEND intent action, ActivityNotFound will be thrown.
A way to avoid the exception is to do the following:
final ComponentName componentName = intent.resolveActivity(pm);
if (componentName != null) {
try {
context.startActivity(intent);
} catch (ActivityNotFoundException ex) {
// Notify the user?
}
}
I have seen some of example where other application can start my application by package name. Due to security reason I want to prevent this kind of access for other application.
I want to prevent this (Open another application from your own (intent)) kind of acess
Edit
For Example, If thirdparty application knows my application's package name they can launch my app from their application like this way,
Intent i;
PackageManager manager = getPackageManager();
try {
i = manager.getLaunchIntentForPackage("app package name");
if (i == null)
throw new PackageManager.NameNotFoundException();
i.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(i);
} catch (PackageManager.NameNotFoundException e) {
}
Now to prevent this, i have added export = "false" in my launching activity as well as added permission to lauching activity. Now due to this, it is preventing thirdparty app to launch my application but android OS launcher is also not able to launch application.
I imagine if you don't provide the launch intent in your Android manifest, other apps (including your homescreen) won't be able to launch your app.
You can try these attributes in manifest:
http://developer.android.com/guide/topics/manifest/activity-element.html#exported
http://developer.android.com/guide/topics/manifest/service-element.html#exported
http://developer.android.com/guide/topics/manifest/receiver-element.html#exported
http://developer.android.com/guide/topics/manifest/provider-element.html#exported
As also mentioned in those links, you can try another approach by using permission with the protectionLevel = signature
http://developer.android.com/guide/topics/manifest/permission-element.html#plevel
I hope below solution by comparing package name will help you protecting your activity to be launched by other app.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ComponentName componentName = this.getCallingActivity();
if(componentName == null) {
finish();
} else if("<intended package name>".equals(componentName.getPackageName())) {
finish();
} else {
String data = getIntent().getDataString();
...
}
}
}
Above solution is base on below assumption:
Only one app with a particular package name can exist on Google Play.
If a user tries to install an app whose package name already exists on the device, the installation either will fail or will overwrite the previously installed app.
I have an app 'A'. I am opening another app 'B''s video player and playing a video using an intent URI call like so
String intentURI = "B://this/123";
try {
intent = Intent.parseUri(intentURI, Intent.URI_INTENT_SCHEME);
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
Logger.appendInfoLog("Something went wrong with B", TAG);
e.printStackTrace();
Logger.appendErrorLog(e.getMessage(), TAG);
finish();
}
startActivity(intent);
Now the necessary condition is for that app 'B' to be open in the background for this to work.If the app is closed(killed by Android or manually) or it has crashed,this throws an error.
Is there a way to open that app 'B' first or check its running status and then make the intent URI call. I will not get control back from that app and once I go to the other app I dont have any control on it until the user presses the back button to return to my app.
UPDATE:
I want to start app 'B' first and then call the intent programmatically. Is this possible
UPDATE
I Ran the Catlog app to check what message comes up in app B. It just shows file 123.file (The one i am trying to play in the app B's video player) not found, but when the app is running in the background it goes through fine. It also shows a warning
java.lang.NullPointerException: PrintLn needs a message
and then it says
Activity displayed, but mediaplayer.is not playingVideo
Also the other app is written in flash and packaged as a native app on adobe air
I have an app 'A'. I am opening another app 'B''s video player and playing a video using an intent URI call like so
No, you are not. You can tell that by reading the code -- there is no startActivity() call in that code block.
Now the necessary condition is for that app 'B' to be open in the background for this to work.If the app is closed(killed by Android or manually) or it has crashed,this throws an error.
Then apparently app B has a bug. Please contact the author of app B for assistance.
You can get a list of running apps easily.
ActivityManager manager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> processes = manager.getRunningAppProcesses();
And you can launch apps just as easily.
Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage("com.package....");
startActivity(LaunchIntent);
You can't, however, launch an app into background, so this might not solve your issue.
You don't need to open that app 'B' first. Just check if that app is running with:
// Get running processes
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningProcesses = manager.getRunningAppProcesses();
So now you have all the running processes in runningProcesses. Just iterate over the values to find out if your app 'B' is running. An example of this iteration can be found here:
ActivityManager am = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE);
List l = am.getRunningAppProcesses();
Iterator i = l.iterator();
PackageManager pm = this.getPackageManager();
while(i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo)(i.next());
try {
CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(info.processName, PackageManager.GET_META_DATA));
Log.w("LABEL", c.toString());
}catch(Exception e) {
//Name Not FOund Exception
}
}
Define the intent listener inside of your manifest file.
See the docs for details.
Basically, what you would do is in your AndroidManifest.xml of App B (the app you want to start with the Intent), add a section like:
<receiver android:name=".MyIntentReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Then inside of your MyIntentReceiver class, you would define the code to handle the intent.
public class MyIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
// handle intent here
}
}
I think your problem is that Intent.parseUri() returns an Intent with the action ACTION_VIEW (see http://developer.android.com/reference/android/content/Intent.html#parseUri%28java.lang.String,%20int%29). And from your code, I gather that android does not recognize that it actually has to start activity B for this. ACTION_VIEW is generic, so id does what seems to be most appropriate. If activity B does not fall into that category (probably not the standard video viewing app), it' will not get launched. I would suggest the following:
Find out how to launch activity B (e.g. Intent i = new Intent.("com.packageB.ActivityB"); or similar. Developer should be able to tell you.
Use i.setData() to set the data of your intent to your file.
Use startActivity()
For step 2, there may be other ways Activity B needs the Uri passed. You can get this information from the developer as well.
Using startActivity rids you of having to check whether App B is running. Something that Android does anyway.
I think it is possible to start another apk from your own, just check this answer. The problem is that if you dont know their uri, it will be hard to do what you propose.
Now you can either ask the developers for the proper names or take a look at your own risk (i don't know about its legality).
I'm trying to start the preferences activity in the native messenger client from my application. in AOSP Mms.apk does not have an intent filter setup on that activity. Regardless I'm trying to find a work around to launch the user into that screen.
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(ComponentName.unflattenFromString("com.android.mms/com.android.mms.ui.MessagingPreferenceActivity"));
intent.addCategory("android.intent.category.LAUNCHER");
try {
startActivity(intent);
} catch (Exception e) {
AppUtils.alertError(this, error);
}
I'm receiving
java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.android.mms/.ui.MessagingPreferenceActivity } from ProcessRecord{406e2738 674:com.handmark.genericapp/10034} (pid=674, uid=10034) requires null
Any thoughts?
What you want is not possible. That activity is not exported (at least in the source code showing in Google Code Search), so you cannot start it, except by rewriting the app as part of your own custom firmware.
Also, bear in mind that this app may or may not exist on any given device.