JDK-6487080 : SystemTray does not report errors when SystemTray is unavailable
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2006-10-27
  • Updated: 2021-07-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
C:\Documents and Settings\Pat>java -version
java version "1.6.0-beta2"
Java(TM) SE Runtime Environment (build 1.6.0-beta2-b86)
Java HotSpot(TM) Client VM (build 1.6.0-beta2-b86, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
I have written a windows service in java using Java Service Wrapper (http://wrapper.tanukisoftware.org/doc/english/introduction.html).  This service needs to interact with the currently logged in user via an icon in the system tray.

The issue is that the icon is the system tray does not show up if the user is not logged when the service is started and no errors or exceptions are reported in the java code.

I think
   SystemTray tray = SystemTray.getSystemTray();

should throw and exception if the system tray is not available to the program.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Modify the paths in the source code to you enviroment.
create an icon file.
Compile the source code provided.
Configure Java Service Wrapper to install the service.
net start service_name.
At this point the icon will appear in the systemtray.
Reboot the computer.
Wait a few minutes to allow all the services to start.  If you login too quickly the icon will be in the systemtray because the systemtray was created before the service was actually started.
Login again; the icon will not be in the system tray but the service will be running.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Icon in system tray.
ACTUAL -
No icon in system tray.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/*
 * Main.java
 *
 * Created on October 19, 2006, 11:05 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package com.SM.systemtray;

import java.awt.AWTException;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Timer;
import java.util.TimerTask;


/**
 *
 * @author Pat
 */
public class Main {
    
    // To detect if system tray is available in c#
    // I copied this C# code off the web but have not verified
    //  that it works for this application or if it is a good solution.
    //  I included it here because it
    // might be useful to whoever gets to fix this.
    //  Pat Gioannini


    //Here is the code that tests whether the icon tray window is loaded. =)
    //
    //First interop the only funciton we need, FindWindow, like so:
    //
    //
    //[DllImport("user32.dll",EntryPoint="FindWindowEx")]
    //public static extern IntPtr FindWindowEx(IntPtr parentToLookFrom,IntPtr childToLookFrom,string className,IntPtr windowName);
    //
    //
    //Now whenever you need to check if the icon tray is loaded do this.
    //
    //
    ////find the handle to the whole taskbar
    ////First argument is the handle to desktop
    ////second is equal to null
    ////third is taskbar class name
    ////fourth is window name as null
    //
    //
    //IntPtr trayWindowHandle = FindWindowEx(IntPtr.Zero,IntPtr.Zero,"Shell_TrayWnd",IntPtr.Zero);
    //
    //
    ////find the handle to the specific part of taskbar
    ////first argument is handle to the taskbar
    ////second is null
    ////third is the class name of icon tray
    ////fourth is null
    //
    //
    //IntPtr notifyWindowHandle = FindWindowEx(trayWindowHandle,IntPtr.Zero,"TrayNotifyWnd",IntPtr.Zero);
    //
    //
    ////test if the handle was found
    //
    //
    //if(notifyWindowHandle.ToInt32() != 0)
    //{
    //        //then icon tray exists
    //
    //
    //}
    //
    //
    //else
    //{
    //        //it doesnt
    //
    //
    //}
    //
    
    
    
    
    /** Creates a new instance of Main */
    public Main() {
        
    };
    
    private GregorianCalendar shutdownTime;
    private Timer shutdownTimer = new Timer("Shutdown Timer");
    
    public void start() {
        int shutdown_hour = 21;
        int shutdown_minute = 00;
        int shutdown_second = 0;
        
        
        GregorianCalendar midnight_today = new GregorianCalendar();
        midnight_today.set(Calendar.HOUR_OF_DAY, 0);
        midnight_today.set(Calendar.MINUTE, 0);
        midnight_today.set(Calendar.SECOND, 0);
        System.err.println("Midnight is " + DateFormat.getDateTimeInstance().format(midnight_today.getTime()));
        
        shutdownTime = new GregorianCalendar();
        shutdownTime.set(Calendar.HOUR_OF_DAY, shutdown_hour);
        shutdownTime.set(Calendar.MINUTE, shutdown_minute);
        shutdownTime.set(Calendar.SECOND, shutdown_second);
        System.err.println("Shutdown time is " + DateFormat.getDateTimeInstance().format(shutdownTime.getTime()));
        
        GregorianCalendar current_time = new GregorianCalendar();
        
        if (current_time.getTime().getTime() > shutdownTime.getTime().getTime()) {
            System.err.println("Shutdown time has already passed for today");
        } else {
            shutdownTimer.schedule(new ShutdownTask(), shutdownTime.getTime());
        }
        
    }
    
    public void stop() {
        shutdownTimer.cancel();
        shutdownTimer.purge();
    }
    
    
    public void showTrayIcon() {
        final TrayIcon trayIcon;
       
        if (SystemTray.isSupported()) {
            
            SystemTray tray = SystemTray.getSystemTray();
            System.err.println("tray is " + tray);
            // I would expect either null or exception here if the systemtray
            // is unavailable for any reason.

            Image image = Toolkit.getDefaultToolkit().getImage("c:\\tray.gif");
            
            MouseListener mouseListener = new MouseListener() {
                
                public void mouseClicked(MouseEvent e) {
                    System.out.println("Tray Icon - Mouse clicked!");
                }
                
                public void mouseEntered(MouseEvent e) {
                    System.out.println("Tray Icon - Mouse entered!");
                }
                
                public void mouseExited(MouseEvent e) {
                    System.out.println("Tray Icon - Mouse exited!");
                }
                
                public void mousePressed(MouseEvent e) {
                    System.out.println("Tray Icon - Mouse pressed!");
                }
                
                public void mouseReleased(MouseEvent e) {
                    System.out.println("Tray Icon - Mouse released!");
                }
            };
            
            ActionListener exitListener = new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    System.out.println("Exiting...");
                    System.exit(0);
                }
            };
            
            
            ActionListener configureListener = new ActionListener() {
                ConfigureShutdownTimer dlg = new ConfigureShutdownTimer(null, true);
                
                public void actionPerformed(ActionEvent e) {
                    System.out.println("Configuring ...");
                    dlg.setTime(shutdownTime);
                    dlg.setVisible(true);
                    System.err.println(dlg.accepted());
                    if (dlg.accepted()) {
                        stop();
                        if (dlg.isShutdownEnabled()) {
                            start();
                        }
                    }
                }
            };
            
            
            MenuItem defaultItem = new MenuItem("Exit");
            defaultItem.addActionListener(exitListener);
            
            MenuItem ConfigureMenuItem = new MenuItem("Configure");
            ConfigureMenuItem.addActionListener(configureListener);
            
            PopupMenu popup = new PopupMenu();
            popup.add(defaultItem);
            popup.add(ConfigureMenuItem);
            
            
            trayIcon = new TrayIcon(image, "Tray Demo", popup);
            
            ActionListener actionListener = new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    trayIcon.displayMessage("Action Event",
                            "An Action Event Has Been Peformed!",
                            TrayIcon.MessageType.INFO);
                }
            };
            
            trayIcon.setImageAutoSize(true);
            trayIcon.addActionListener(actionListener);
            trayIcon.addMouseListener(mouseListener);
            
            try {
                tray.add(trayIcon);
            } catch (AWTException e) {
                System.err.println("TrayIcon could not be added.");
            }
        } else {
            System.err.println("System tray is not supported");
        }
        
    }
    
    
    private class ShutdownTask extends TimerTask {
        
        public void run() {
            String shutdown_command = "c:\\java programs\\systemtray\\dist\\reboot_cmd";
            GregorianCalendar current_time = new GregorianCalendar();
            System.err.println("Shutdown time has arrived" +  DateFormat.getDateTimeInstance().format(current_time.getTime()));
            try {
                
                
                String[] commands = {"cmd", "/c", "start", "\"Shutdown command\"", shutdown_command};
                Process p = Runtime.getRuntime().exec(commands);
                
                String line;
                BufferedReader input =
                        new BufferedReader
                        (new InputStreamReader(p.getInputStream()));
                while ((line = input.readLine()) != null) {
                    System.out.println(line);
                }
                input.close();
            } catch (Exception err) {
                err.printStackTrace();
            }
        }
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Main main = new Main();
        main.start();
        main.showTrayIcon();
    }
    
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Write the application as two program.  The first being the actual service and second being a user interface for the service.   This is not as good a solution because you have to arrange that all users get the gui app installed; even new accounts.

Comments
- this is an issue reported against 7(7u), - there are now affected version 9 filed for this issue - 7u issues are transferred to Sustaining Nevertheless if someone have a report against 9 - please reopen and add affectedVersion 9 or 7u specific escalations might be reopen to Sustaining
10-08-2014

- this is an issue reported against 7(7u), - there are now affected version 9 filed for this issue - 7u issues are transferred to Sustaining Nevertheless if someone have a report against 9 - please reopen and add affectedVersion 9 or 7u specific escalations might be reopen to Sustaining
10-08-2014

EVALUATION Currently, SystemTray implementation on Windows platform assumes that the system tray is always available to the application. That is not true for applications running as a service and should be corrected. There is no distinct Win32 API call to detect if the tray is available, however Shell_NotifyIcon function (used in Java) returns TRUE or FALSE value. I think that this return value may be used to detect the system tray availability.
30-10-2006