issue with resolving activity for an intent - resolveActivityInfo() - android

I am using resolveActivityInfo to determine if my app was set as a home launcher:
PackageManager pm = getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_HOME);
userHomePackage = intent.resolveActivityInfo(pm, 0).packageName;
userHomeActivityClass = intent.resolveActivityInfo(pm, 0).name;
currentHomeLauncherName = intent.resolveActivityInfo(pm, 0).loadLabel(pm).toString();
it works great on emulator and three android devices I have on hands.
Recently I started getting error reports from my users and error log shows that resolveActivityInfo is failing. This happens only on a few phones running on android 2.1 update 1 as I can see. I've received already many positive comments on my app and a few negative because of this issue.
Any advice what could be wrong?
java.lang.NullPointerException
at android.os.Parcel.readException(Parcel.java:1224)
at android.os.Parcel.readException(Parcel.java:1206)
at android.content.pm.IPackageManager$Stub$Proxy.resolveIntent(IPackageManager.java:1418)
at android.app.ApplicationContext$ApplicationPackageManager.resolveActivity(ApplicationContext.java:2046)
at android.content.Intent.resolveActivityInfo(Intent.java:3790)
at com.myapp.myappname.Launcher.setAsHomeApplicationBeforeFroyo(Launcher.java:336)
OR
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myapp.myappname/com.myapp.myappname.Launcher}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2497)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2513)
at android.app.ActivityThread.access$2200(ActivityThread.java:119)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1864)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4370)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:862)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at android.os.Parcel.readException(Parcel.java:1224)
at android.os.Parcel.readException(Parcel.java:1206)
at android.content.pm.IPackageManager$Stub$Proxy.resolveIntent(IPackageManager.java:1418)
at android.app.ApplicationContext$ApplicationPackageManager.resolveActivity(ApplicationContext.java:2046)
at android.content.Intent.resolveActivityInfo(Intent.java:3790)
at com.myapp.myappname.Launcher.showHomeChooserDialog(Launcher.java:141)
at com.myapp.myappname.Launcher.showNextActivity(Launcher.java:122)
at com.myapp.myappname.Launcher.onCreate(Launcher.java:59)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2460)
... 11 more
java.lang.NullPointerException
at android.os.Parcel.readException(Parcel.java:1224)
at android.os.Parcel.readException(Parcel.java:1206)
at android.content.pm.IPackageManager$Stub$Proxy.resolveIntent(IPackageManager.java:1418)
at android.app.ApplicationContext$ApplicationPackageManager.resolveActivity(ApplicationContext.java:2046)
at android.content.Intent.resolveActivityInfo(Intent.java:3790)
at com.myapp.myappname.Launcher.showHomeChooserDialog(Launcher.java:141)

Kevin from TeslaCoil Software here. Sorry for the delay in getting back to you. This is what I'm using to get the Home component in my apps:
public static ComponentName getHomeComponent(PackageManager PM) {
Intent home_intent = new Intent("android.intent.action.MAIN");
home_intent.addCategory("android.intent.category.HOME");
home_intent.addCategory("android.intent.category.DEFAULT");
ComponentName cn = home_intent.resolveActivity(PM);
if (cn == null)
Log.v(TAG, "[Default] package:null");
else
Log.v(TAG, "[Default] package:" + cn.getPackageName() + " class:" + cn.getClassName());
return cn;
}
resolveActivity doesn't normally return null, as it seems to return the resolver activity if there is no default set. But on some phones or something it might return null just to keep things interesting. Perhaps resolveActivityInfo calls resolveActivity but doesn't handle the null case properly.

did some research with android source and i tend to agree now with Commonsware that my code is right. I actually redesigned it 3 weeks ago to use packagemanager.resolveActivity instead of intent.resolveactivity:
this.pm = context.getPackageManager();
try {
Intent homeintent = new Intent(Intent.ACTION_MAIN);
homeintent.addCategory(Intent.CATEGORY_HOME);
homeintent.addCategory(Intent.CATEGORY_DEFAULT);// seems not needed here since This is a synonym for
// including
// the CATEGORY_DEFAULT in your supplied Intent per doc
this.resolveInfo = pm.resolveActivity(homeintent, PackageManager.MATCH_DEFAULT_ONLY);
ActivityInfo activityInfo = resolveInfo.activityInfo;
userHomeLauncherPackage = activityInfo.packageName;
userHomeLauncherClass = activityInfo.name;
userHomeLauncherName = activityInfo.loadLabel(pm).toString();
if (userHomeLauncherClass.contains("ResolverActivity"))
userHomeLauncherName = "";
} catch (Exception e) {
throw new Exception(e);
}
It did not help so still getting these errors occasionally...
Based on the source code,
ComponentName Intent.resolveActivity (PackageManager pm)
or
ActivityInfo Intent.resolveActivityInfo (PackageManager pm, int flags)
call the same method defined in android.app.ContextImpl class:
ResolveInfo info = pm.resolveActivity(this, PackageManager.MATCH_DEFAULT_ONLY)
and it is defined like:
#Override
public ResolveInfo resolveActivity(Intent intent, int flags) {
try {
return mPM.resolveIntent(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags);
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
}
so at this point i came to conclusion that I cannot do anything about this :(

Related

java.lang.NullPointerException at IabHelper.startSetup(IabHelper.java:266)

Anyone know how to fix this NullPointerException on the start of setup of the IabHelper?
java.lang.NullPointerException
at android.app.ApplicationPackageManager.queryIntentServicesAsUser(ApplicationPackageManager.java:559)
at android.app.ApplicationPackageManager.queryIntentServices(ApplicationPackageManager.java:571)
at IabHelper.startSetup(IabHelper.java:266)
at MyApplication.createIABHelper(MyApplication.java:256)
at MyApplication.onCreate(MyApplication.java:156)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1000)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4391)
at android.app.ActivityThread.access$1300(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1294)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5041)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:816)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:582)
at dalvik.system.NativeStart.main(NativeStart.java)
My IabHelper code is slightly modified because of other issues with it so here is the startSetup method:
public void startSetup(final OnIabSetupFinishedListener listener) {
// If already set up, can't do it again.
checkNotDisposed();
if (mSetupDone) throw new IllegalStateException("IAB helper is already set up.");
// Connection to IAB service
logDebug("Starting in-app billing setup.");
mServiceConn = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
logDebug("Billing service disconnected.");
mService = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (mDisposed) return;
logDebug("Billing service connected.");
mService = IInAppBillingService.Stub.asInterface(service);
String packageName = mContext.getPackageName();
try {
logDebug("Checking for in-app billing 3 support.");
// check for in-app billing v3 support
int response = mService.isBillingSupported(3, packageName, ITEM_TYPE_INAPP);
if (response != BILLING_RESPONSE_RESULT_OK) {
if (listener != null) listener.onIabSetupFinished(new IabResult(response,
"Error checking for billing v3 support."));
// if in-app purchases aren't supported, neither are subscriptions.
mSubscriptionsSupported = false;
return;
}
logDebug("In-app billing version 3 supported for " + packageName);
// check for v3 subscriptions support
response = mService.isBillingSupported(3, packageName, ITEM_TYPE_SUBS);
if (response == BILLING_RESPONSE_RESULT_OK) {
logDebug("Subscriptions AVAILABLE.");
mSubscriptionsSupported = true;
} else {
logDebug("Subscriptions NOT AVAILABLE. Response: " + response);
}
mSetupDone = true;
} catch (RemoteException e) {
if (listener != null) {
listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION,
"RemoteException while setting up in-app billing."));
}
e.printStackTrace();
return;
}
if (listener != null) {
listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful."));
}
}
};
Intent serviceIntent = getExplicitIapIntent();
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> intentServices = pm.queryIntentServices(serviceIntent, 0);
if (intentServices != null && !intentServices.isEmpty()) {
//this was replaced per this comment http://stackoverflow.com/a/24202135/704836
//if (!mContext.getPackageManager().queryIntentServices(serviceIntent, 0).isEmpty()) {
// service available to handle that Intent
mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
} else {
// no service available to handle that Intent
if (listener != null) {
listener.onIabSetupFinished(
new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE,
"Billing service unavailable on device."));
}
}
}
The NullPointerException is happening at List<ResolveInfo> intentServices = pm.queryIntentServices(serviceIntent, 0);
Any ideas?
Thanks.
EDIT: here is the code for getExplicitIapIntent:
/**
* From http://stackoverflow.com/a/26318757/704836
* #return
*/
private Intent getExplicitIapIntent() {
PackageManager pm = mContext.getPackageManager();
Intent implicitIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
implicitIntent.setPackage("com.android.vending");
List<ResolveInfo> resolveInfos = pm.queryIntentServices(implicitIntent, 0);
// Is somebody else trying to intercept our IAP call?
if (resolveInfos == null || resolveInfos.size() != 1) {
return null;
}
ResolveInfo serviceInfo = resolveInfos.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
Intent iapIntent = new Intent();
iapIntent.setComponent(component);
return iapIntent;
}
EDIT: I should also point out that according to crashlytics, 100% of the devices giving this error are rooted. So maybe it is something to do with people trying to get around having to pay for features.
EDIT: I tried passing null instead of serviceIntent and got the following exception:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Intent.resolveTypeIfNeeded(android.content.ContentResolver)' on a null object reference
at android.app.ApplicationPackageManager.queryIntentServicesAsUser(ApplicationPackageManager.java:644)
at android.app.ApplicationPackageManager.queryIntentServices(ApplicationPackageManager.java:656)
at IabHelper.startSetup(IabHelper.java:266)
On that exception the line numbers are different from the reports I've gotten, so I'm not certain it is the same.
EDIT: I think the exception I got on the last edit might be pretty much the same as the exception I am getting for 5.0.2 devices. Here is one of the 5.0.2 reports:
java.lang.NullPointerException
Attempt to invoke virtual method 'java.lang.String android.content.Intent.resolveTypeIfNeeded(android.content.ContentResolver)' on a null object reference
android.app.ApplicationPackageManager.queryIntentServicesAsUser (ApplicationPackageManager.java:645)
android.app.ApplicationPackageManager.queryIntentServices (ApplicationPackageManager.java:657)
IabHelper.startSetup (IabHelper.java:266)
EDIT: I went ahead and modified the code to throw an exception when serviceIntent is null and I've already had a few reports come back from my beta testers. All 100% rooted devices so I am guessing their devices don't have the correct com.android.vending.billing.InAppBillingService.BIND.
EDIT: Once the code was released the 100% rooted devices dropped to about 80%. Anyways I got a chance to troubleshoot with a user and it turned out that the getExplicitIntent method can return null sometimes under kitkat (not sure which other versions) so I went ahead and added an answer with how I changed the code.
Do you have the code to the method queryIntentServicesAsUser()? After taking a closer look, it seems like one of the variables you are sending the queryIntentServices could be causing the NullPointer.
So finally what is the right way to fix this problem? serviceIntent is null - that means someone wants to hack? And we let app crash in this situation?
I finally found a user getting a null intent who was not doing anything dodgy with in-app purchases. He was on kitkat. The fix was this:
if (OSUtils.lollipopOrHigher) {
serviceIntent = getExplicitIapIntent();
} else {
serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
}
Another option would be to check for null and then try the non lollipop method.

How can I see the application directly underneath a soft keyboard in Android?

I am developing a soft keyboard that pipes data (not text) to a receiving intent. Is there any way to see the application/activity that the keyboard is currently overlaying? I am trying to preselect the intent action chooser and develop custom rules to get the data to go to the right place.
Just thought I'd answer my own question for this one. Here is the code that returns the activity from the top of the stack.
public String PullTop() {
final PackageManager pm = getPackageManager();
//Get the Activity Manager Object
ActivityManager aManager =
(ActivityManager) self.getSystemService(ACTIVITY_SERVICE);
//Get the list of running Applications
List<ActivityManager.RunningAppProcessInfo> rapInfoList = aManager.getRunningAppProcesses();
//Iterate all running apps to get their details
for (ActivityManager.RunningAppProcessInfo rapInfo : rapInfoList) {
//error getting package name for this process so move on
if (rapInfo.pkgList.length == 0)
continue;
try {
PackageInfo pkgInfo = pm.getPackageInfo(rapInfo.pkgList[0], PackageManager.GET_ACTIVITIES);
Log.i("Package",pkgInfo.packageName);
return pkgInfo.packageName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
Log.d("", "NameNotFoundException :" + rapInfo.pkgList[0]);
}
}
return null;
}
To pipe the data to the right process just check for null and:
intent.setPackage(PullTop());

Intent extras only work on some devices

In my app I send some intent extras from one activity to another. But some users report back that these data are always zero - even though I can see the values are alright in the sending activity.
Here's the code of the sending activity:
Intent intent = new Intent();
intent.setClass(waypointListView.this, addWaypointActivity.class);
intent.putExtra("latitude", String.format("%9.6f", globLatitude));
intent.putExtra("longitude", String.format("%9.6f", globLongitude));
startActivityForResult(intent, ACTIVITY_ADD_WAYPOINT);
And this is how it's read in the new activity:
Intent myIntent = getIntent();
String latitudeStr = myIntent.getExtras().getString("latitude");
try{
globLatitude = Float.parseFloat(latitudeStr);
} catch(NumberFormatException nfe) {
globLatitude=0f;
}
String longitudeStr = myIntent.getExtras().getString("longitude");
try{
globLongitude = Float.parseFloat(longitudeStr);
} catch(NumberFormatException nfe) {
globLongitude=0f;
}
On both my devices it works fine, but I have 3 cases of customers complaining that it doesn't work (documented in video recordings).
Any suggestions?
I tried to change the code to use getFloatExtra() instead of getString and parse it to a float, and it solved the problem. I see this is a lot more efficient, but I still don't understand why the original solution worked on some devices but not on others.
Case closed!

getPackageManager ().getInstalledPackages (PackageManager.GET_ACTIVITIES) returns null

If I call
PackageManager pm = getPackageManager () ;
List<PackageInfo> pis = pm.getInstalledPackages (PackageManager.GET_PROVIDERS) ;
I get a list of installed packages, including any provivders they declare (i.e, with pis[i].providers possibly being non-null).
However, if I include PackageManager.GET_ACITIVITIES among the flags, as in
PackageManager pm = getPackageManager () ;
List<PackageInfo> pis = pm.getInstalledPackages (PackageManager.GET_ACTIVITIES | PackageManager.GET_PROVIDERS) ;
I expect to get the "same" list of installed packages, but with pis[i].activities being non-null as well. But I don't, I get an empty list.
Is there something special about including PackageManager.GET_ACTIVITES among the flags that isn't mention in the documentation?
My current work around is to leave PackageManager.GET_ACTIVITIES out of the flags, then loop through the returned list as follows:
for (PackageInfo pi : pis) {
try {
PackageInfo tmp = pm.getPackageInfo (pi.packageName, PackageManager.GET_ACTIVITIES) ;
pi.activities = tmp.activities ;
}
catch (NameNotFoundException e) {
Log.e (TAG, e.getMessage ()) ;
}
But that seems like a real kludge.
The only mention I could find of getInstalledPackages (PackageManager.GET_ACTIVITIES) returning an empty list is here, but the problem in that case seems to have been something about calling getInstalledPackages() outside the main application thread and that is not the situation in my case.
p.s. this is the .602 VZW build of Gingerbread, in case that matters
I came across the same issue and found out a better workaround:
public void listAllActivities() throws NameNotFoundException
{
List<PackageInfo> packages = getPackageManager().getInstalledPackages(0);
for(PackageInfo pack : packages)
{
ActivityInfo[] activityInfo = getPackageManager().getPackageInfo(pack.packageName, PackageManager.GET_ACTIVITIES).activities;
Log.i("Pranay", pack.packageName + " has total " + ((activityInfo==null)?0:activityInfo.length) + " activities");
if(activityInfo!=null)
{
for(int i=0; i<activityInfo.length; i++)
{
Log.i("PC", pack.packageName + " ::: " + activityInfo[i].name);
}
}
}
}
Notice that I need to query PackageManager twice. Once using getPackageManager().getInstalledPackages(...) and again using getPackageManager().getPackageInfo(...)
I hope it helps.

Intent for app details page

My app relies heavily on a database for data and sometimes the database won't copy correctly, gets corrupted, or just throws a generic strop. Clearing the app data and then reopening the app seems to work well, but it's quite a chore to ask my users to dig through the settings pages, and I'm looking for a way to quickly get to the app details page (which shows the uninstall, move to SD, clear data etc.)
I've found the Settings.ACTION_APPLICATION_DETAILS_SETTINGS Intent action but get an ActivityNotFoundException when I try to launch it as described on my Desire Z. Can anyone help me out how to properly sort this?
Thanks
EDIT: As noted in the answers, this is only API9 and above, the code I now use if anyone wants it is below. Believe it works on API3 and above.
try {
Intent i = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(Uri.parse("package:com.espian.formulae"));
startActivity(i);
} catch (ActivityNotFoundException ex) {
Intent i = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(i);
}
I know that this is way too late answer but it may help someone. Based on the platform (froyo) source I make one function that opens a specific package's settings page. It works in the emulator but I never tried on a real device. I don't know if it works on API < 8 either.
Here it is:
public boolean startFroyoInstalledAppDetailsActivity(String packagename) {
boolean result = false;
Intent i = new Intent();
i.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
i.setAction(Intent.ACTION_VIEW);
i.putExtra("pkg", packagename);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
cx.startActivity(i);
result = true;
} catch (Exception ex) {
result = false;
}
return result;
}
Based on your code I also make a Gingerbread version which works on real devices with API levels 9, 10, 11, 12, 13, 14 and 15 but it can be called safely from API 8 however in this case it will return false.
Here it is:
public boolean startGingerbreadInstalledAppDetailsActivity(String packagename) {
boolean result = false;
Intent i = new Intent();
i.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(Uri.parse("package:" + packagename));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
cx.startActivity(i);
result = true;
} catch (Exception ex) {
result = false;
}
return result;
}
I'll post it as answer here in addition to my comment. That intent is only available as of API Level 9 (2.3). The Desire Z doesn't have 2.3... yet. ;)

Categories

Resources