The process of the service is killed after the application is removed from the application tray
Here is a workaround I came across and works well for re-starting a service if its process is killed on closing the application. In your service, add the following code.
I came across this workaround in this thread.
@Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
Seems to be a bug that the process of the application is killed. There is no point for a service to run if its process is killed.
Tray icon does not disappear on killing process
There is no solution to this problem. If you kill process with task manager, it does not receive termination notification, and hence can not remove its icon from the tray. Try avoiding killing process this way. You can use net start/stop
to kill a service or services.msc
GUI.
App isn't killed when removed from recent tasks when using service
You are talking about the OS Process hosting your application, and not the "task" (which is an Android construct). Android is responsible to killing OS processes and reclaiming them. It does it when it wants to, if it wants to, and you have no control over this. You cannot assume that your OS Process will be killed in any specific case.
You need to write your code in such a way that you can deal with anything that happens.
NotifyIcon remains in Tray even after application closing but disappears on Mouse Hover
The only solution that worked for me was to use the Closed event and hide and dispose of the icon.
icon.BalloonTipClosed += (sender, e) => {
var thisIcon = (NotifyIcon)sender;
thisIcon.Visible = false;
thisIcon.Dispose();
};
How to close WPF system tray application from another app?
As most of the time, I had to figure it out myself.
Here's how.
First: we have the process. The process has no main window, no windows at all, so all communication with windows is off the table. But the process has threads. And the threads have their message queue, though it's accessible with Win32 API.
So here's the receiving end:
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application {
// (...)
/// <summary>
/// Sent as a signal that a window or an application should terminate.
/// </summary>
const uint WM_CLOSE = 0x0010;
/// <summary>
/// Retrieves a message from the calling thread's message queue. The function dispatches incoming sent messages until a posted message is available for retrieval.
/// </summary>
/// <param name="lpMsg">MSG structure that receives message information from the thread's message queue.</param>
/// <param name="hWnd">A handle to the window whose messages are to be retrieved. The window must belong to the current thread. Use <see cref="IntPtr.Zero"/> to retrieve thread message.</param>
/// <param name="wMsgFilterMin">The integer value of the lowest message value to be retrieved.</param>
/// <param name="wMsgFilterMax">The integer value of the highest message value to be retrieved.</param>
/// <returns>Non-zero for any message but WM_QUIT, zero for WM_QUIT, -1 for error.</returns>
[DllImport("user32.dll")]
static extern int GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
/// <summary>
/// Waits indefinitely for a specific thread message.
/// </summary>
/// <param name="signal">Signal, message value.</param>
private void WaitForSignal(uint signal) => GetMessage(out var msg, IntPtr.Zero, signal, signal);
/// <summary>
/// WPF application startup.
/// </summary>
/// <param name="e">Event arguments.</param>
protected override async void OnStartup(StartupEventArgs e) {
base.OnStartup(e);
// ... initialization code ...
await Task.Run(() => WaitForSignal(WM_CLOSE));
Shutdown();
}
// (...)
}
Sending end:
/// <summary>
/// Demo.
/// </summary>
class Program {
/// <summary>
/// Sent as a signal that a window or an application should terminate.
/// </summary>
const uint WM_CLOSE = 0x0010;
/// <summary>
/// Posts a message to the message queue of the specified thread. It returns without waiting for the thread to process the message.
/// </summary>
/// <param name="threadId">The identifier of the thread to which the message is to be posted.</param>
/// <param name="msg">The type of message to be posted.</param>
/// <param name="wParam">Additional message-specific information.</param>
/// <param name="lParam">Additional message-specific information.</param>
/// <returns></returns>
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostThreadMessage(uint threadId, uint msg, IntPtr wParam, IntPtr lParam);
/// <summary>
/// Closes a windowless application pointed with process name.
/// </summary>
/// <param name="processName">The name of the process to close.</param>
static void CloseWindowless(string processName) {
foreach (var process in Process.GetProcessesByName(processName)) {
using (process) {
foreach (ProcessThread thread in process.Threads) PostThreadMessage((uint)thread.Id, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
}
}
/// <summary>
/// Main application entry point.
/// </summary>
/// <param name="args">Command line arguments.</param>
static void Main(string[] args) => CloseWindowless("MyAppName");
}
And the voodoo magic behind: P/Invoke part is pretty obvious. What's more interesting is WPF Application
.OnStartup
override behavior.
If the method is synchronous and does not exit, the application hangs.
If it's marked asynchronous however, it doesn't have to exit. It waits indefinitely for anything awaitable. This is exactly what we needed, because we can invoke Shutdown()
only from the main UI thread. We cannot block that thread, so we have to wait for messages on another thread. We send the WM_CLOSE to all process threads, so it will get it. When it ends, the Shutdown
method is called from the main thread and that's it.
What's best in this solution it doesn't need System.Windows.Forms reference.
Related Topics
How to Detect When the User Has Changed the Clock Time on Their Device
Android Detect Done Key Press for Onscreen Keyboard
Load an Image from Assets Folder
Disabling Android O Auto-Fill Service for an Application
Filter Listview with Arrayadapter
How to Open Standard Google Map Application from My Application
How to Detect System Information Like Os or Device Type
Sending Data from Nested Fragments to Parent Fragment
Android Vector Drawable App:Srccompat Not Showing Images
Apply Custom Filters to Camera Output
Which Android Ide Is Better - Android Studio or Eclipse
How to Call Methods of a Service from Activity
Android - How to Enable Autostart Option Programmatically in Xiaomi Devices
Android Google Maps, How to Make Each Marker Infowindow Open Different Activity
How to Use Holo.Light Theme, and Fall Back to 'Light' on Pre-Honeycomb Devices