IAB, onActivityResult() and the strange message "startActivity called from non-Activity context" - android

I am using OpenIAB to support in app purchasing in my app (OpenIAB uses google code to implement IAP for Google Play Store). The problem is that, sometimes, when i call launchPurchaseFlow(), the method onActivityResult() of my FragmentActivity is not called. Checking the logs, i have found that when this happens there is always the following msg:
W/ActivityManager( 319): startActivity called from non-Activity
context: forcing Intent.FLAG_ACTIVITY_NEW_TASK for: Intent {
cmp=com.android.vending/com.google.android.finsky.billing.lightpurchase.IabV3Activity
(has extras) }
When this happens, i have to close the app. Usually it start working again after some time (i have absolutely no clue of why is it so).
I don't know why this message show up, since the context is obviously my activity (and in fact it works most of time). I have to say that the .apk installed on my device is an updated verion with respect to the apk uploaded in the beta version of the developer console and that i am using my google developer account to test IAP. This implies that i cannot make any real buy. However, this is not important, since i am testing the app.
These are my questions:
Is it true that starting an activity for result with
FLAG_ACTIVITY_NEW_TASK prevents onActivityResult() to be called?
How do you explain that message?
Regarding the first question, i have tested with launchMode=singleTask and the behaviour is the same of launchMode=singleTop.

Related

context.startActivity in broadcast receiver sometimes not working (targetSDK 19 on an SDK 27 device)

I call startActivity in an implicit broadcast receiver's onReceive function under certain very limited circumstances.
Intent transactionIntent = new Intent(context, TransactionActivity.class);
transactionIntent.putExtra(Constants.Extras.ORDER_ID, orderId);
transactionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(transactionIntent);
I have logs before this line and logs in the onCreate function of the activity. Some customers are reporting random instances of this activity not creating itself. I can see in the logs that startActivity is called and onCreate is not. One of them I know for sure is an Android 8.1 Oreo device. My target SDK is 19 (vast majority are old devices, this is not an app on the Play store). I can also tell the Background activity toggle in the system settings for the app is not switched off so that is not the problem.
What situations can this happen (extreme memory pressure?) and how can I capture it to verify what is going on?
EDIT:
The app is not crashing (no crashes logged for this version of the app, and it does nothing but setContentView before logging the activity creation). I don't think device sleep is an issue because I am targeting pre M, doze mode etc. doesn't come in to play. The user was also using the app a few seconds before this call to startActivity failed, and 30 seconds later they were using the app as well, so that window doesn't seem likely large enough to allow for any kind of sleep or wake lock issues. I also don't think the user could have managed to swipe the app out of memory between the app calling startActivity and onCreate, this is happening sporadically (for this one user is happened 1 out of 6 times).
The app is a for a busy, mains connected Point of Sale device.

Avoid Screen Overlay Detected for service that uses SYSTEM_ALERT_WINDOW

My app main usage is overlay, the overlay is running from a service.
Android Security add the nice "Screen Overlay Detected"
I want to avoid "Screen Overlay Detected" when user tries to change permissions. so... I've add an AccessiblityService that detects:
if ( event.getPackageName().equals("com.google.android.packageinstaller") ){
stopService(myServiceIntent);
}
However, even now I see this message popping. (when my service is stopped...).
I saw Twilight does it without problem.
What am I missing?
p.s. - I've also tried building a signed apk but saw exact same behavior.
It seems I've been able to resolve this.
a) stopService isn't assured your service will be stopped.
as described here :
It will not be destroyed until all of these bindings are removed. See > the Service documentation for more details on a service's lifecycle.
b) I was able to kill my service by sending intent that called stopSelf().
However process killing/starting can be slow.
c) Best resolution: so it seems Android checks for view visibility. no need to kill services or do anything more complicated.
Current way I'm doing it:
- AccessibilityService (already used by my app) monitor "com.google.android.packageinstaller" though it can be refined to class: "com.android.packageinstaller.permission.ui.ManagePermissionsActivity"
Once detected in this class, we send Intent to "duck", and when we're out, we send another intent that we're back on.
The service handles those calls by:
[ourView].setVisibility(View.INVISIBLE); // when permission settings shown
[ourView].setVisibility(View.VISIBLE); // when normal flow
As long as Android 6.x is buggy on some devices where this "overlay alert" is displayed without any reason (on 2 to 5% of the devices according to my analytics data), the best solution is to avoid the whole permission process by defining the targetSdk to 22. Take care that you can't downgrade the target sdk for a new version or this will induce a INSTALL_FAILED_PERMISSION_DOWNGRADE error when the user updates requiring an unisntall/install of the app.

How does buying an app to enable paid features of another app work?

There are apps (such as https://play.google.com/store/apps/details?id=com.teslacoilsw.launcher) that are free, but whose paid features can be enabled by buying another app (in this case, this one https://play.google.com/store/apps/details?id=com.teslacoilsw.launcher.prime)
How does this work?
My guess is that the free apps launches an explicit Intent and can detect if the app is present via a try/catch structure. The downside of this is that this could be easily circunvented by someone who creates an app with the same package name and specifies all possible Intent filters.
Is this how it works, or is it some other way?
There are various ways to do that. One way is to query a content provider which will be protected with a special permission.
I have released quite long ago on Github a library which helps doing this: Android Unlocker Library.
That's a good option if you are dealing with devices outside the Google ecosystem, however, from a developer experience, in-app purchases offer a much better user experience (and thus drive more sales) according to me.
The easiest way is to use startActivityForResult(...) from app A against an Activity of app B, that must be configured with an IntentFilter in order to be used from an outer app. Inside the B called activity you can also check who's calling with getCallingActivity(). You can find an example here.
Before starting the Activity, you can test that B is installed (using the PackageManager) or you can just start the activity and catch the Exception.
In the called Activity, you can check the signature of the calling package using the PackageManager.checkSignature(String,String) method. Pass the package name of A and B and if the signature matches, execute the logic.

GoogleMaps android app with GooglePlayServicesUtil.getErrorDialog()

So in the documentation here
http://developer.android.com/google/play-services/setup.html
it says to check the status of play services with isGooglePlayServicesAvailable() and then display the error dialog if it's not okay.
This seems to be working fine for me, the dialog showing it's not installed with a button that opens up the play store all seems okay. My question is specifically about the returned results in onActivityResult().
We have to pass a requestCode to getErrorDialog() and I get that back in onActivityResult just fine, but im more concerned with the resultCode returned. So far with all my testing I've gotten 0 (RESULT_CANCELLED). I was wondering if there was any way to know if the play services were installed successfully?
For now I'm handling it by just assuming that RESULT_CANCELLED means that they at least got to the play store and started downloading, and display another dialog that says "please restart this app once the play services complete installation" followed by a finish().
Is this the best way to handle it? or is there a case that I'm missing where it will return RESULT_OK and I can just continue onward with my app working without restarting it?
I must say that today I tried it, and I never got onActivityResult() called.
When dialog is cancelled, my OnCancelListener (getErrorDialog() parameter) is called, and when returning from PlayStore, whether installing Google Play Services or not, my app is destroyed.
Even more, when installing Google Play Services, onDestroy() is called when installation starts.
I think maybe this is an updated behaviour, and I think is consequent, because you can return from Play Store before background installation ends.
Nonetheless, I found a couple of links with sample code that may confirm in case onActivityResult() is called with RESULT_OK, it means that you can continue:
http://developer.android.com/training/location/activity-recognition.html
http://developer.android.com/training/location/retrieve-current.html
Hope it helps

Don't get Android Market INSTALL_REFERRER on Android 3.x

I implemented a BroadcastReceiver for the Android Market INSTALL_REFERRER Intent as
described here:
Get referrer after installing app from Android Market
It works fine for android devices earlier than 3.0 but it never seems to fire on Honeycomb devices. I've checked the logcat output during the install and after the app's first launch and I don't see any of my debug output which leads me to believe that the BroadcastReceiver isn't being run (I do see the output on pre-Honeycomb versions).
Can anyone out there confirm this problem?
Any idea how to make it work?
There's a new flag called FLAG_EXCLUDE_STOPPED_PACKAGES in 3.1:
If set, this intent will not match any components in packages that are currently stopped. If this is not set, then the default behavior is to include such applications in the result.
From the release notes for 3.1:
Note that the system adds FLAG_EXCLUDE_STOPPED_PACKAGES to all broadcast intents.
And also:
Applications are in a stopped state when they are first installed but are not yet launched and when they are manually stopped by the user (in Manage Applications).
Seems like this is breaking the behavior of INSTALL_REFERRER in 3.1+ devices as your app has not yet been launched and so can not receive the broadcast. Sadly I don't know of any way to make this work. Google could probably do something to fix this in their Market app (one way would be to just use FLAG_INCLUDE_STOPPED_PACKAGES though I'm not sure that would be a great idea, given the whole point of these new launch controls).
As i experienced the Broadcast Intent *INSTALL_REFERRER* is fired once before the Application is launched the first time If you don't catch it there, you'll never get it again

Categories

Resources