1 /*
2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  @test
26  @bug 8147841
27  @key headful
28  @summary Updating Tray Icon popup menu does not update menu items on Mac OS X
29  @run main/manual UpdatePopupMenu
30  */
31 
32 import java.awt.SystemTray;
33 import java.awt.TrayIcon;
34 import java.awt.PopupMenu;
35 import java.awt.MenuItem;
36 import java.awt.Image;
37 import java.awt.Graphics2D;
38 import java.awt.Color;
39 import java.awt.image.BufferedImage;
40 import java.awt.RenderingHints;
41 import java.awt.AWTException;
42 import java.awt.Button;
43 import java.awt.Frame;
44 import java.awt.GridBagConstraints;
45 import java.awt.GridBagLayout;
46 import java.awt.Panel;
47 import java.awt.TextArea;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ActionListener;
50 
51 public class UpdatePopupMenu implements ActionListener {
52 
53     private static final int imageSize = 32;
54     private static final int imageInset = 4;
55     private static GridBagLayout layout;
56     private static Panel mainControlPanel;
57     private static Panel resultButtonPanel;
58     private static TextArea instructionTextArea;
59     private static Button passButton;
60     private static Button failButton;
61     private static Frame mainFrame;
62     private static Thread mainThread = null;
63     private static boolean testPassed = false;
64     private static boolean isInterrupted = false;
65     private static final int testTimeOut = 300000;
66 
createSystemTrayIconImage()67     private Image createSystemTrayIconImage() {
68         final BufferedImage trayImage = new BufferedImage(
69                 imageSize,
70                 imageSize,
71                 BufferedImage.TYPE_INT_ARGB);
72 
73         final Graphics2D imageGraphics = (Graphics2D) trayImage.getGraphics();
74 
75         imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
76                 RenderingHints.VALUE_ANTIALIAS_ON);
77 
78         imageGraphics.setColor(new Color(255, 255, 255, 0));
79         imageGraphics.fillRect(0, 0, trayImage.getWidth(),
80                 trayImage.getHeight());
81 
82         imageGraphics.setColor(Color.green);
83 
84         int imageWidth = trayImage.getWidth() - 2 * imageInset;
85         int imageHeight = trayImage.getHeight() - 2 * imageInset;
86 
87         imageGraphics.fillOval(imageInset, imageInset, imageWidth, imageHeight);
88         imageGraphics.setColor(Color.darkGray);
89         imageGraphics.drawOval(imageInset, imageInset, imageWidth, imageHeight);
90 
91         return trayImage;
92     }
93 
createPopupMenu(final TrayIcon trayIcon, final int menuCount)94     private PopupMenu createPopupMenu(final TrayIcon trayIcon,
95             final int menuCount) {
96 
97         final PopupMenu trayIconPopupMenu = new PopupMenu();
98 
99         for (int i = 1; i <= menuCount; ++i) {
100             final MenuItem popupMenuItem = new MenuItem("MenuItem_" + i);
101 
102             popupMenuItem.addActionListener(new ActionListener() {
103                 @Override
104                 public void actionPerformed(final ActionEvent ae) {
105                     trayIcon.setPopupMenu(createPopupMenu(trayIcon,
106                             menuCount + 1));
107                 }
108             });
109 
110             trayIconPopupMenu.add(popupMenuItem);
111         }
112 
113         return trayIconPopupMenu;
114     }
115 
createSystemTrayIcons()116     private void createSystemTrayIcons() {
117 
118         final TrayIcon trayIcon = new TrayIcon(createSystemTrayIconImage());
119         trayIcon.setImageAutoSize(true);
120         trayIcon.setToolTip("Update Popup Menu items");
121 
122         try {
123             trayIcon.setPopupMenu(createPopupMenu(trayIcon, 2));
124             SystemTray.getSystemTray().add(trayIcon);
125 
126         } catch (AWTException ex) {
127             throw new RuntimeException("System Tray cration failed");
128         }
129     }
130 
createInstructionUI()131     private void createInstructionUI() {
132         mainFrame = new Frame("Updating TrayIcon Popup Menu Item Test");
133         layout = new GridBagLayout();
134         mainControlPanel = new Panel(layout);
135         resultButtonPanel = new Panel(layout);
136 
137         GridBagConstraints gbc = new GridBagConstraints();
138         String instructions
139                 = "INSTRUCTIONS:"
140                 + "\n   1. Click on the System Tray Icon"
141                 + "\n   2. Click on any of the displayed Menu items"
142                 + "\n   3. Repeat step 1 and count the number of items in the "
143                 + "Menu"
144                 + "\n   4. The number of items in the Menu should increase by 1"
145                 + "\n   5. Repeating steps 1, 2 and 3 should not break 4th step"
146                 + "\n   6. Click Fail if the 4th step is broken, Otherwise "
147                 + "click Pass ";
148 
149         instructionTextArea = new TextArea();
150         instructionTextArea.setText(instructions);
151         instructionTextArea.setEnabled(false);
152         instructionTextArea.setBackground(Color.white);
153 
154         gbc.gridx = 0;
155         gbc.gridy = 0;
156         gbc.fill = GridBagConstraints.HORIZONTAL;
157         mainControlPanel.add(instructionTextArea, gbc);
158 
159         passButton = new Button("Pass");
160         passButton.setName("Pass");
161         passButton.addActionListener(this);
162 
163         failButton = new Button("Fail");
164         failButton.setName("Fail");
165         failButton.addActionListener(this);
166 
167         gbc.gridx = 0;
168         gbc.gridy = 0;
169         resultButtonPanel.add(passButton, gbc);
170         gbc.gridx = 1;
171         gbc.gridy = 0;
172         resultButtonPanel.add(failButton, gbc);
173         gbc.gridx = 0;
174         gbc.gridy = 1;
175         mainControlPanel.add(resultButtonPanel, gbc);
176 
177         mainFrame.add(mainControlPanel);
178         mainFrame.pack();
179         mainFrame.setVisible(true);
180     }
181 
182     @Override
actionPerformed(ActionEvent ae)183     public void actionPerformed(ActionEvent ae) {
184         if (ae.getSource() instanceof Button) {
185             Button btn = (Button) ae.getSource();
186             switch (btn.getName()) {
187                 case "Pass":
188                     testPassed = true;
189                     isInterrupted = true;
190                     mainThread.interrupt();
191                     break;
192 
193                 case "Fail":
194                     testPassed = false;
195                     isInterrupted = true;
196                     mainThread.interrupt();
197                     break;
198             }
199         }
200     }
201 
cleanUp()202     private static void cleanUp() {
203         mainFrame.dispose();
204     }
205 
main(final String[] args)206     public static void main(final String[] args) throws Exception {
207         if (SystemTray.isSupported()) {
208 
209             UpdatePopupMenu updatePopupMenu = new UpdatePopupMenu();
210             updatePopupMenu.createInstructionUI();
211             updatePopupMenu.createSystemTrayIcons();
212 
213             mainThread = Thread.currentThread();
214             try {
215                 mainThread.sleep(testTimeOut);
216             } catch (InterruptedException ex) {
217                 if (!testPassed) {
218                     throw new RuntimeException("Updating TrayIcon popup menu"
219                             + " items FAILED");
220                 }
221             } finally {
222                 cleanUp();
223             }
224 
225             if (!isInterrupted) {
226                 throw new RuntimeException("Test Timed out after "
227                         + testTimeOut / 1000 + " seconds");
228             }
229 
230         } else {
231             System.out.println("System Tray is not supported on this platform");
232         }
233     }
234 }
235