diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 664a7ac02da..ac9fd92ed5c 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -214,6 +214,7 @@ java/awt/TrayIcon/TrayIconPopup/TrayIconPopupClickTest.java 8150540 windows-all, java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java 8150540 windows-all java/awt/TrayIcon/MouseMoveTest.java 8203053 linux-all java/awt/TrayIcon/TrayIconKeySelectTest.java 8341557 windows-all +java/awt/TrayIcon/TrayIconTest.java 8341559 generic-all java/awt/Window/ShapedAndTranslucentWindows/SetShapeAndClick.java 8197936 macosx-all java/awt/Window/ShapedAndTranslucentWindows/SetShapeDynamicallyAndClick.java 8013450 macosx-all diff --git a/test/jdk/java/awt/TrayIcon/TrayIconTest.java b/test/jdk/java/awt/TrayIcon/TrayIconTest.java new file mode 100644 index 00000000000..c78f6c134fe --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/TrayIconTest.java @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Container; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Label; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.RenderingHints; +import java.awt.SystemTray; +import java.awt.TextField; +import java.awt.Toolkit; +import java.awt.TrayIcon; +import java.awt.TrayIcon.MessageType; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeEvent; +import java.util.HashMap; +import java.util.Map; +import jtreg.SkippedException; + +/* + * @test + * @key headful + * @bug 4310333 + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary A unit test for TrayIcon RFE + * @run main/manual TrayIconTest + */ + +public class TrayIconTest { + private static SystemTray tray; + static Frame frame = new Frame("TrayIcon Test"); + private static final String INSTRUCTIONS = """ + The test frame contains CheckboxGroup of tray icons. + A selected checkbox represents the TrayIcon (or null + TrayIcon) whose functionality is currently tested. + + If you are under Linux make sure your Application Panel has + System Tray (on Gnome it is called Notification Area). + + Perform all the cases (1-7) documented below. + + CASE 1: Testing ADD/REMOVE/PropertyChange functionality. + -------------------------------------------------------- + 1. Select null TrayIcon and pressAdd button: + - NullPointerException should be thrown. + 2. Select some of the valid TrayIcons and press Add button: + - The selected TrayIcon should appear in the SystemTray. + - PropertyChangeEvent should be fired (the property is + an array of TrayIcons added to the system tray). + 3. Press Add button again: + - IllegalArgumentException should be thrown. + - No PropertyChangeEvent should be fired. + 4. Press Remove button: + - The TrayIcon should disappear from the SystemTray. + - PropertyChangeEvent should be fired. + 5. Press Remove button again: + - It should have no effect. + - No PropertyChangeEvent should be fired. + 6. Add all the valid TrayIcons (by selecting everyone and pressing Add + button): + - All the TrayIcons should appear in the SystemTray. + - PropertyChangeEvent should be fired on each adding. + 7. Remove all the TrayIcons (again by selecting everyone and pressing + Remove): + - All the TrayIcons should disappear from the SystemTray. + - PropertyChangeEvent should be fired on each removing. + 8. Not for Windows! Remove the system tray (Notification Area) from + the desktop. Try to add some valid TrayIcon: + - AWTException should be thrown. + - No PropertyChangeEvent should be fired. + 9. Not for Windows! Add the system tray back to the desktop. Add all the + valid TrayIcons: + - All the TrayIcons should appear in the system tray. + - PropertyChangeEvent should be fired on each adding. + 11. Not for Windows! Remove the system tray from the desktop: + - All the TrayIcons should disappear. + - PropertyChangeEvent should be fired for each TrayIcon + removal. + - PropertyChangeEvent should be fired for SystemTray removal. + 12. Add the system tray and go to the next step. + - All the TrayIcons should appear again. + - PropertyChangeEvent should be fired for SystemTray addition. + - PropertyChangeEvent shouldn't be fired for TrayIcon removal. + + CASE 2: Testing RESIZE functionality. + ------------------------------------- + 1. Select some of the TrayIcons and add it. Then press resize button: + - The TrayIcon selected should be resized to fit the area it occupies. + 2. Press resize button again: + - The TrayIcon should be resized to the original size. + 3. Repeat the 1-2 steps for other TrayIcons: + - The TrayIcons should be resized appropriately. + + CASE 3: Testing EVENTS functionality + --------------------------------- + 1. Select some of the TrayIcons and add it. Select MouseEvent from the + group of checkboxes at the top-right of the test frame. + Click on the TrayIcon in the SystemTray: + - MOUSE_PRESSED MOUSE_RELEASED and MOUSE_CLICKED events should be + generated. + 2. Press mouse inside the TrayIcon dragging mouse and releasing it. + - Make sure that MOUSE_CLICKED event is not triggered. + 3. Click on the TrayIcon with different modification keys: + - there should be appropriate modifiers in the events. + 4. Keep clicking on the TrayIcon: + - there should be correct absolute coordinates in the events. + 5. Only for Windows! Focus the system tray using keyboard: + - press WIN key once to bring up the start menu then press ESC once to + close the menu the focus should be on the start button + - press TAB key for several times until you focus on the system + tray then use ARROW keys to move to the TrayIcon + - press ENTER or SPACE should trigger ACTION_PERFORMED message + make sure that mouse events are not triggered. + 6. Select MouseMotionEvent checkbox. Move mouse over the TrayIcon: + - MOUSE_MOVED event should be generated. It should contain + correct coordinates. + 7. Deselect both the checkboxes and then select AWTEventListener. + Click on the TrayIcon and then move mouse over it: + - Appropriate mouse events should be generated (catched by the + AWTEventListener). + 8. Deselect all the checkboxes and go to the following step. + + CASE 4: Testing DISPLAY MESSAGE functionality. + ---------------------------------------------- + 1. Select some of the TrayIcons and add it. Then press Display message + button: + - A balloon message should appear near the TrayIcon. + 2. After the message is displayed wait for some period: + - The message window should be closed automatically. + 3. Display the message again. Close it by pressing X in its top-right + corner: + - The message window should be closed immediately. + 4. Display the message again. Click inside it: + - The message should be closed an ACTION_PERFORMED event should be + generated with correct information and an Ok dialog should appear. + Close the dialog. + 5. Select a message type from the Type choice and display the message + again: + - It should contain an icon appropriate to the message type selected + or no icon if NONE is selected. + 6. Change the content of the Message and Caption text fields and + display the message: + - The message content should be changed in the accordance with the text + typed. + 7. Not for Windows! Type some too long or too short text for the Caption + and Message: + - The message should process the text correctly. The long text should + be cut. + 8. Not for Windows! Type null in the Message text field and display + the message: + - The message body should contain no text. + 9. Type null in the Caption text field and display the message: + - The message caption should contain no text. + 10. Type null in the both Message and Caption fields and display + the message: + - NullPointerException should be generated and no message should be + displayed. + 11. Try to hide the taskbar. Click Display message for several times. + Then restore the taskbar. Click on the TrayIcon: + - No message should appear. + Try to display the message once more: + - It should appear appropriately. + 12. Try to display the message for other TrayIcons: + - The messages should be displayed appropriately. + + CASE 5: Testing POPUP MENU functionality. + ----------------------------------------- + 1. Add some TrayIcon to the system tray. Press Set button in the + Popup menu test area. Trigger the popup menu for the TrayIcon with + the mouse: + - A popup menu should appear. Make sure it behaves properly. + - Make sure the 'duke.gif' image is animated while the popup menu is shown. + 2. Press Remove button for the popup menu and try to trigger it again: + - No popup menu should appear. + 3. Perform 1-2 steps for other TrayIcons: + - Make sure the popup menu behaves properly. + 4. Add more than one TrayIcons to the system tray. Press Set button in + the PopupMenu test area for some of the TrayIcon added. Trigger + the popup menu for this TrayIcon: + - A popup menu should appear properly. + 5. Try to set the popup menu to the same TrayIcon again: + - It should have no effect + 6. Try to set the popup menu for other TrayIcons you've added to the system + tray: + - for each one IllegalArgumentException should be thrown. + + CASE 6: Testing TOOLTIP functionality. + -------------------------------------- + 1. Type something in the Tooltip text field and press Set button. + Then move mouse cursor over the TrayIcon and wait for a second: + - A tooltip should appear containing the text typed. + 2. Show a tooltip again and keep your mouse over the TrayIcon for some period: + - The tooltip should disappear automatically. + 3. Show a tooltip again and leave the TrayIcon: + - The tooltip should disappear immediately. + 4. Type null in the Tooltip field and press set then move your + mouse to the SystemTray: + - The tooltip shouldn't appear. + 5. Type something too long in the Tooltip field and show the tooltip: + - The tooltip text should be cut. + + CASE 7: Testing ACTION functionality. + ------------------------------------- + 1. Add some TrayIcon to the system tray. Double click it with the left mouse + button: + - An ACTION_PERFORMED event should be generated. + 2. Double click the TrayIcon with the left mouse button several times: + - Several ACTION_PERFORMED events should be generated + - Make sure that the time-stamp of each event ('when' field) is increased. + + If all the above cases work as expected Press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + try { + PassFailJFrame.builder() + .title("TrayIconTest Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .rows(40) + .testUI(TrayIconTest::createAndShowUI) + .logArea(10) + .build() + .awaitAndCheck(); + + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + //Remove any remaining tray icons before ending the test. + TrayIcon[] icons = tray.getTrayIcons(); + for (TrayIcon icon : icons) { + tray.remove(icon); + } + } + }); + } + } + + private static Frame createAndShowUI() { + final TrayIconControl ctrl = new TrayIconControl(); + frame.setLayout(new BorderLayout()); + frame.add(ctrl.cont, BorderLayout.CENTER); + frame.setBackground(Color.LIGHT_GRAY); + + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + ctrl.dispose(); + } + }); + + frame.pack(); + return frame; + } + + private static class TrayIconControl { + final String RED_ICON = "RED ICON"; + final String BLUE_ICON = "BLUE ICON"; + final String GREEN_ICON = "GREEN ICON"; + + CheckboxGroup cbg = new CheckboxGroup(); + Button addButton = new PackedButton(" Add "); + Button remButton = new PackedButton("Remove"); + Button resizeButton = new PackedButton("Resize"); + Button balloonButton = new PackedButton("Display message"); + Choice balloonChoice = new Choice(); + String[] balloonTypes = new String[] { "ERROR", "WARNING", "INFO", "NONE" }; + + TextField balloonText = new TextField( + "A TrayIcon can generate various MouseEvents and" + + " supports adding corresponding listeners to receive" + + " notification of these events. TrayIcon processes" + + " some of the events by itself. For example," + + " by default, when the right-mouse click", 70); + TextField balloonCaption = new TextField("TrayIcon", 70); + + MessageType[] typeArr = new MessageType[] { MessageType.ERROR, MessageType.WARNING, + MessageType.INFO, MessageType.NONE }; + Checkbox mouseListenerCbox = new Checkbox("MouseEvent"); + Checkbox motionListenerCbox = new Checkbox(" MouseMotionEvent"); + Checkbox awtListenerCbox = new Checkbox(" AWTEventListener"); + TextField tipText = new TextField("TrayIcon", 50); + Button tipButton = new PackedButton("Set"); + Button setPopupButton = new PackedButton("Set"); + Button remPopupButton = new PackedButton("Remove"); + + PopupMenu popupMenu = new PopupMenu(); + + Map resToObjMap = new HashMap<>(); + + Container cont = new Container(); + + TrayIconControl() { + Toolkit.getDefaultToolkit().addAWTEventListener(e -> { + if (e.getSource() instanceof TrayIcon && awtListenerCbox.getState()) { + PassFailJFrame.log(e.toString()); + } + }, MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK | + ActionEvent.ACTION_EVENT_MASK); + + cont.setLayout(new GridLayout(4, 1)); + + Container raw1 = new Container(); + raw1.setLayout(new GridLayout(1, 4)); + cont.add(raw1); + + InsetsPanel cbgPanel = new InsetsPanel(); + cbgPanel.setLayout(new GridLayout(4, 1)); + Checkbox nullCbox = new Checkbox("null", cbg, true); + Checkbox redCbox = new Checkbox(RED_ICON, cbg, false); + Checkbox blueCbox = new Checkbox(BLUE_ICON, cbg, false); + Checkbox greenCbox = new Checkbox(GREEN_ICON, cbg, false); + cbgPanel.add(nullCbox); + cbgPanel.add(redCbox); + cbgPanel.add(blueCbox); + cbgPanel.add(greenCbox); + cbgPanel.addTo(raw1); + + InsetsPanel addremPanel = new InsetsPanel(); + addremPanel.setLayout(new BorderLayout()); + addremPanel.add(addButton.getParent(), BorderLayout.NORTH); + addremPanel.add(remButton.getParent(), BorderLayout.SOUTH); + addremPanel.addTo(raw1); + + InsetsPanel resizePanel = new InsetsPanel(); + resizePanel.add(resizeButton); + resizePanel.addTo(raw1); + + InsetsPanel lstPanel = new InsetsPanel(); + lstPanel.setLayout(new GridLayout(3, 1)); + lstPanel.add(mouseListenerCbox); + lstPanel.add(motionListenerCbox); + lstPanel.add(awtListenerCbox); + lstPanel.addTo(raw1); + + Container raw2 = new Container(); + raw2.setLayout(new BorderLayout()); + cont.add(raw2); + + InsetsPanel balloonPanel = new InsetsPanel(); + balloonPanel.setLayout(new BorderLayout()); + balloonPanel.add(balloonButton.getParent(), BorderLayout.NORTH); + Container bc = new Container(); + bc.setLayout(new FlowLayout()); + bc.add(new Label(" Type:")); + bc.add(balloonChoice); + balloonPanel.add(bc, BorderLayout.SOUTH); + balloonPanel.addTo(raw2, BorderLayout.WEST); + + InsetsPanel blnTextPanel = new InsetsPanel(); + blnTextPanel.setLayout(new GridLayout(2, 2)); + Container c1 = new Panel(); + c1.setLayout(new FlowLayout()); + blnTextPanel.add(c1); + c1.add(new Label("Message:")); + c1.add(balloonText); + + Container c2 = new Panel(); + c2.setLayout(new FlowLayout()); + blnTextPanel.add(c2); + c2.add(new Label("Caption:")); + c2.add(balloonCaption); + blnTextPanel.addTo(raw2, BorderLayout.CENTER); + + + Container raw3 = new Container(); + raw3.setLayout(new BorderLayout()); + cont.add(raw3); + + InsetsPanel popupPanel = new InsetsPanel(); + popupPanel.setLayout(new FlowLayout()); + popupPanel.add(new Label("Popup menu:")); + popupPanel.add(setPopupButton); + popupPanel.add(remPopupButton); + popupPanel.addTo(raw3); + + + Container raw4 = new Container(); + raw4.setLayout(new BorderLayout()); + cont.add(raw4); + + InsetsPanel tipPanel = new InsetsPanel(); + tipPanel.setLayout(new FlowLayout()); + tipPanel.add(new Label("Tooltip:")); + tipPanel.add(tipText); + tipPanel.add(tipButton); + tipPanel.addTo(raw4); + + addButton.addActionListener(e -> { + try { + tray.add(getCurIcon()); + } catch (NullPointerException npe) { + if (npe.getMessage() == null) { + PassFailJFrame.log("Probably wrong path to the images."); + throw npe; // if wrong images path was set + } + PassFailJFrame.log(npe.toString()); + } catch (IllegalArgumentException iae) { + PassFailJFrame.log(iae.toString()); + } catch (AWTException ise) { + PassFailJFrame.log(ise.toString()); + } + }); + remButton.addActionListener(e -> tray.remove(getCurIcon())); + + resizeButton.addActionListener( + e -> getCurIcon().setImageAutoSize(!getCurIcon().isImageAutoSize())); + + balloonButton.addActionListener(e -> { + String text = null, caption = null; + if (balloonText.getText().compareToIgnoreCase("null") != 0) { + text = balloonText.getText(); + } + if (balloonCaption.getText().compareToIgnoreCase("null") != 0) { + caption = balloonCaption.getText(); + } + try { + getCurIcon().displayMessage(caption, text, typeArr[balloonChoice.getSelectedIndex()]); + } catch (NullPointerException npe) { + PassFailJFrame.log(npe.toString()); + } + }); + + tipButton.addActionListener(e -> { + String tip = null; + if (tipText.getText().compareToIgnoreCase("null") != 0) { + tip = tipText.getText(); + } + getCurIcon().setToolTip(tip); + }); + + setPopupButton.addActionListener(e -> { + try { + getCurIcon().setPopupMenu(popupMenu); + } catch (IllegalArgumentException iae) { + PassFailJFrame.log(iae.toString()); + } + }); + + remPopupButton.addActionListener(e -> getCurIcon().setPopupMenu(null)); + for (String s: balloonTypes) { + balloonChoice.add(s); + } + + init(); + } + + void init() { + tray = SystemTray.getSystemTray(); + tray.addPropertyChangeListener("trayIcons", + e -> printPropertyChangeEvent(e)); + + tray.addPropertyChangeListener("systemTray", + e -> printPropertyChangeEvent(e)); + + configureTrayIcon(RED_ICON); + configureTrayIcon(BLUE_ICON); + configureTrayIcon(GREEN_ICON); + + for (String s: balloonTypes) { + popupMenu.add(new MenuItem(s)); + } + } + + void printPropertyChangeEvent(PropertyChangeEvent e) { + String name = e.getPropertyName(); + Object oldValue = e.getOldValue(); + Object newValue = e.getNewValue(); + + PassFailJFrame.log("PropertyChangeEvent[name=" + name + + ",oldValue=" + oldValue + ",newValue=" + newValue + "]"); + } + + void configureTrayIcon(String icon) { + Color color = Color.WHITE; + switch (icon) { + case "RED ICON" -> color = Color.RED; + case "BLUE ICON" -> color = Color.BLUE; + case "GREEN ICON" -> color = Color.GREEN; + } + Image image = createIcon(color); + TrayIcon trayIcon = new TrayIcon(image); + + trayIcon.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + if (mouseListenerCbox.getState()) + PassFailJFrame.log(e.toString()); + } + public void mouseReleased(MouseEvent e) { + if (mouseListenerCbox.getState()) + PassFailJFrame.log(e.toString()); + } + public void mouseClicked(MouseEvent e) { + if (mouseListenerCbox.getState()) + PassFailJFrame.log(e.toString()); + } + }); + trayIcon.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseMoved(MouseEvent e) { + if (motionListenerCbox.getState()) + PassFailJFrame.log(e.toString()); + } + }); + trayIcon.addActionListener(e -> PassFailJFrame.log(e.toString())); + + resToObjMap.remove(icon); + resToObjMap.put(icon, trayIcon); + } + + String getCurImgName() { + return cbg.getSelectedCheckbox().getLabel(); + } + + TrayIcon getCurIcon() { + return resToObjMap.get(getCurImgName()); + } + + public void dispose() { + tray.remove(getCurIcon()); + } + + private static Image createIcon(Color color) { + BufferedImage image = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setColor(color); + g.fillRect(0, 0, 16, 16); + g.dispose(); + return image; + } + + } + + private static class InsetsPanel extends Panel { + Container parent = new Container() { + public Insets getInsets() { + return new Insets(2, 2, 2, 2); + } + }; + + InsetsPanel() { + parent.setLayout(new BorderLayout()); + setBackground(new Color(240, 240, 240)); + } + + void addTo(Container c) { + parent.add(this); + c.add(parent); + } + + void addTo(Container c, String pos) { + parent.add(this); + c.add(parent, pos); + } + } + + private static class PackedButton extends Button { + Container parent = new Container(); + PackedButton(String l) { + super(l); + parent.setLayout(new FlowLayout()); + parent.add(this); + } + } +} +