I am developing an Android App with Xamarin Android.
I'm using the InAppBilling Plugin from James Montemagno.
When I call PurchaseAsync Method the PlayStore dialog opens. But in the background my app freezes and I dont get any result.
var purchase = await CrossInAppBilling.Current.PurchaseAsync(productId, ItemType.Subscription, "apppayload");
In the Sys Log theres a android.app.ServiceConnectionLeaked error:
02-17 22:13:05.434 LENOVO YT3-X50L Error 8031 ActivityThread android.app.ServiceConnectionLeaked: Activity md5742c3bd4cdfedb6330d25c53207d662c.ShopActivity has leaked ServiceConnection md57a6f08dbc6561d468b2675b2ac9edab2.InAppBillingImplementation_InAppBillingServiceConnection#2277a40 that was originally bound here
at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1092)
at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:986)
at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1303)
at android.app.ContextImpl.bindService(ContextImpl.java:1286)
at android.content.ContextWrapper.bindService(ContextWrapper.java:604)
at mono.android.view.View_OnClickListenerImplementor.n_onClick(Native Method)
at mono.android.view.View_OnClickListenerImplementor.onClick(View_OnClickListenerImplementor.java:30)
at android.view.View.performClick(View.java:5205)
at android.view.View$PerformClick.run(View.java:21164)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
I only get this error on LENOVO YT3-X50L. On Samsung phones it works fine...
ServiceConnectionLeaked
The CrossInAppBilling code does not take into consideration that your Activity can be killed/flushed from memory due to memory pressure/requirements and does not directly do anything to try to prevent it, it is up the app developer to determine when they need to take special action.
This is something I see a lot of in lower-end Android devices and the the new Android Oreo Go (<=1MB) test devices, but can happen on any device, but mostly noticeable on 2GB and lower devices.
Before calling any external code flush/release as much memory as possible
Focusing on releasing images is usually the largest payoff for memory reduction (restore them after the purchase is completed)
In cases of the Oreo Go 512MB devices I have had to go the extra mile and finish the current Activity, create a new blank/empty transient Activity and then call the external code (app billing, camera, etc) and upon completion, restore the original activity and bring it up to date with the new information externally obtained.
Note: profile your app and the activity first in order to focus your time.
Use your own Keep-Alive Service
Using Start/StopService and not Bind/UnBindService
Make it a Foreground Service
Note: This does not prevent the OS from killing/flushing your Activities/Services, it just provides a "hint" that it should not...
Note: Monitor the Importance state within the RunningAppProcessInfo to determine if your app is entering ReasonServiceInUse before you execute the external code.
Related
As part of some work I need to get done for Windows 10, I have written a code in C# that essentially detects every minute whether a PC is in screen saver mode or not, and it writes to a table in MySQL the relevant status ("PC in use" if the screen saver is off, "available PC" if the screen saver is on).
I did this using (full link if required - https://www.codeproject.com/Articles/17067/Controlling-The-Screen-Saver-With-C):
// Returns TRUE if the screen saver is actually running
public static bool GetScreenSaverRunning( )
{
bool isRunning = false;
SystemParametersInfo( SPI_GETSCREENSAVERRUNNING, 0,
ref isRunning, 0 );
return isRunning;
}
The code works flawlessly in console application mode (I made a loop to test it out over a minute with a check up on screen save status every 10 seconds), this means in MySQL the status was set correctly every time, depending on the screen save status at the moment of the check up.
The problem occurs when I use this code for a windows service. The service is installed correctly, the log on tab is set on Local System (I also tried with the logged in user instead, same results) and I allow the service to interact with the desktop, just in case, but the difference here is that no matter if the PC enters screen save or not, it always returns false on GetScreenSaverRunning(), thus setting the status of the PC in MySQL as "PC in use", even if the screen saver is on at the moment of check up.
I get the sense that the problem isn't in the code itself, since it works without any issues as a console application, but perhaps something behind the scenes. I tried to search here and on many other websites, haven't found anything related to such a problem.
Does anyone have any idea at all what might be the issue? Any help and/or suggestions will be greatly appreciated!
Thank you in advance.
(I could post the code if required, but it is pretty much straight forward and the main part of it, controlling the screen save detection, is taken from the website mentioned above, afterwards it's a simple if (GetScreenSaverRunning() == true) )
Ever since Vista, Services are barred from a Interactive Session. Even if they run under the same rights, they do not get a interactive Session. I would guess that is getting in the way here.
While you can overwrite this behavior in the Service settings, this is not adviseable for new code. Consider making this a Background Task started by the Task Sheduler instead.
Because the windows service runs in different session then the windows logon. You can't interact with the desktop related services unless you run the windows service in win logon session. There used to be an option in Windows service manager where you can set the properties to "Interact with desktop session" but I don't think that ever worked.
There's a work around to run the windows service using the win logo session.
See this helper class that can get the current logged on user session and interact with the desktop services. https://github.com/murrayju/CreateProcessAsUser/blob/master/ProcessExtensions/ProcessExtensions.cs
I use Appium for testing Android device in C#.
Every time i run a test case, i need to go to Main screen and then begin the use case. This can be achieved in two ways, using: LaunchApp and StartActivity function.
As far as i believe,
LaunchApp launches app again, that is killing the running app and start the app from the beginning. However i will end up in startup activity. This will free up memory space, so app will not go into stress or out of memory issues.
StartActivity will not kill the App, but switch to particular activity. Which will be same as real case testing.
Is my above statement true? or what is the exact difference between the both?
In general you got it right, but it worth to add more context here.
How it works:
launchApp() by default does the following:
checks if app installed
performs fast reset (including app stop, cache cleanup, etc.)
starts the app with launch activity
checks package + activity to match the ones you set in capabilities (appWaitPackage, appWaitActivity)
startActivity does the following:
runs command via adb shell to launch specified activity
checks package + activity to match the one you set as argument
Real life examples, e.g. app that has LoginActivity -> NavigationActivity -> WhateverActivity flow:
You were logged in to the app
a) launchApp() will clean the app and move you back to LoginActivity
b) startActivity(NavigationActivity) will just launch NavigationActivity, so you don't have to login to the app.
You were not logged in to the app
a) launchApp() will be same as in Q1
b) startActivity(NavigationActivity) will fail with Incorrect package and activity as app flow does not allow it.
I'm using startActivity before each test to get to start point, that helps to speedup tests suite by avoiding app reinstall and relogin multiple times.
I have a problem with the OpenFileDialog from Windows Forms (it does not matter if I use is in a console application, win forms or wpf) (C#).
I have a small test project with a button that, when pressed, will ask the user to select an image (using OpenFileDialog) and send its path to a process method. The process method is in c++ native code and accessed using c++ cli (CLR). This method send a request to a web service and waits for the response (the web service is local, so the response is fast).
The problem is this: if I press the button 2 times (select an image + processing and after it's finished I process another image), the 3rd time the window will not show, it gets stuck at ShowDialog.
If I run it from WPF it gives me this error:
DisconnectedContext occurred
Message: Managed Debugging Assistant 'DisconnectedContext' has detected a problem in 'd:\Project\WpfApplication1.vshost.exe'.
Additional information: Transition into COM context 0x1b09d5d0 for this RuntimeCallableWrapper failed with the following error: The object invoked has disconnected from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED)). This is typically because the COM context 0x1b09d5d0 where this RuntimeCallableWrapper was created has been disconnected or it is busy doing something else and cannot process the context transition. No proxy will be used to service the request on the COM component and calls will be made to the COM component directly. This may cause corruption or data loss. To avoid this problem, please ensure that all COM contexts/apartments/threads stay alive and are available for context transition, until the application is completely done with the RuntimeCallableWrappers that represents COM components that live inside them.
Any ideas how to solve this or what it means ?
I found the problem (it was not from the webservice communication): Somewhere in my native code I was uninitializing COM, but .NET UI needs COM to be up and running.
So all I had to do is remove the unitialization of COM from my native code.
I have an application that takes screenshots from the local computer.
This works since many years correctly until suddenly a colleague reported me that he got an "The handle is invalid" error from my application.
This error came from inside the .NET framework from Graphics.CopyFromScreen().
To work around this I replaced this function with C++ code using GetDC(GetDesktopWindow()) / GetDC(NULL) and BitBlt() to copy the screen into a bitmap. Now I got ERROR_INVALID_HANDLE.
This happens on Windows 7.
What is going on there ?
I can not investigate this problem on my own because I cannot reproduce it and my colleague is in another country.
I searched in Google and lots of people report this error.
But all posts that I found were from people who tried to take a screenshot from a client computer through ASP code on a server. I don't understand how people can have the strange desire to capture the client's computer from a website. It is obvious that this will not work.
But I could not find one single case where someone reports this problem from an application that cannot capture the screen of the SAME computer in the SAME session where the application itself is running.
After investigating more with my colleague and giving him ideas what he can try, he told me that he starts my application through a remote desktop session.
The remote desktop session creates a virtual desktop (you see for example that the desktop wallpaper is missing).
I told my colleague to install a VNC client to remote control the computer instead of a remote desktop session and now all works fine. He installed TightVNC which uses the REAL desktop user session instead of creating a virtual session and locking the screen of the machine.
So if anyone gets reports of "The handle is invalid" while taking a screen capture, ask your users if they use a remote desktop session.
To detect a remote desktop session in code you can write:
in C++:
if (GetSystemMetrics(SM_REMOTESESSION) > 0)
{
MessageBox(m_hWnd, L"This application may not work correctly in a remote desktop session", "Error", MB_ICONSTOP);
}
or in C#:
if (System.Windows.Forms.SystemInformation.TerminalServerSession)
{
Messagebox.Show("This application may not work correctly in a remote desktop session");
}
Note that the problem is not reproducible on all computers. When I test on my own Windows 7 it works. So there are probably any additional system settings or other factors that trigger the "The handle is invalid" error (service packs / hotfixes...?).
But my colleague reports that he has never seen the error again after he stopped using the remote desktop connection.
There are a few reasons this can happen but the underlying theme is that the desktop window isn't available when this method is called.
In addition to the reasons mentioned above, another reason this can happen is if this method is being called when the screen is locked.
The code for CopyFromScreen has this section:
int result = SafeNativeMethods.BitBlt(targetDC, destinationX, destinationY, destWidth, destHeight, screenDC, sourceX, sourceY, (int) copyPixelOperation);
//a zero result indicates a win32 exception has been thrown
if (result == 0) {
throw new Win32Exception();
}
It would seem to me that the safest course of action would be that if you make use of this function, make sure that you also write your code assuming that receiving a Win32Exception or an unavailable Desktop Window is a use case which must be handle so the application doesn't crash.
Background
The company I work on is developing a kiosk-like application for tablets running Windows 8 Pro (on desktop mode). The user shouldn't be able to access anything that isn't the application itself: charms will be disabled, the taskbar will be hidden behind the application, etc.
This also means the user shouldn't be able to change network settings, leaving the responsability to keep the device always connected to us. Up to now, I had success using the Mobile Broadband API to assure the device is connected whenever there's a mobile network available. It'll detect disconnect events and try to connect again.
The Problem
Although the user shouldn't be able to do it, I'm considering the case where the user follows this steps:
User opens right-side charm,
clicks on Settings,
clicks on Network,
clicks on More PC Settings,
clicks on Wireless, and
disables the mobile broadband device.
I would like to be able to revert this programmatically and enable it again.
The Attempts
I have tried some different ways to force 3G being reenabled. Most of them give me the same result: they supposedly enable the device without errors, but I still cannot use it. Enable-NetAdapter in Powershell doesn't throw errors, and the Enable method of Win32_NetworkAdapter appears to work, but no dice.
I thought maybe the method IMbnRadio::SetSoftwareRadioState could be what I'm after, but I can't get to it when the device is disabled. The method IMbnInterfaceManager::GetInterfaces throws a COMException claiming the element could not be found (HRESULT = 0x80070490).
MbnInterfaceManager mbnInterfaceManager = new MbnInterfaceManager();
IMbnInterfaceManager interfaceManager = (IMbnInterfaceManager)mbnInterfaceManager;
// The following line throws a COMException:
IMbnInterface[] interfaces = (IMbnInterface[])interfaceManager.GetInterfaces();
mobileInterface = interfaces[0];
mobileRadio = (IMbnRadio)mobileInterface;
uint requestId;
mobileRadio.SetSoftwareRadioState(MBN_RADIO.MBN_RADIO_ON, out requestId);
Is there a way to override user preferences set on "More PC Settings?"
I found a sketchy way to solve this. Keep in mind this is undocumented, wrong, shameless and immoral, and will probably break eventually. The client is aware of this, but prefers to keep the access to the OS limited.
The setting in case is saved in the Registry. At least in the computers I've checked, it's stored in HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}\0022 in a key named RadioOff.
The Airplane Mode setting is also stored in the Registry, but in a different place. It's at HKLM\SYSTEM\CurrentControlSet\Control\RadioManagement\SystemRadioState in a key named (Default).
After changing these keys and rebooting, everything seems to work fine. I'll repeat though: you really shouldn't be doing this, especially the Airplane Mode thing.