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 @summary Updating Tray Icon popup menu does not update menu items on Mac OS X 28 @run main/manual UpdatePopupMenu 29 */ 30 31 import java.awt.SystemTray; 32 import java.awt.TrayIcon; 33 import java.awt.PopupMenu; 34 import java.awt.MenuItem; 35 import java.awt.Image; 36 import java.awt.Graphics2D; 37 import java.awt.Color; 38 import java.awt.image.BufferedImage; 39 import java.awt.RenderingHints; 40 import java.awt.AWTException; 41 import java.awt.Button; 42 import java.awt.Frame; 43 import java.awt.GridBagConstraints; 44 import java.awt.GridBagLayout; 45 import java.awt.Panel; 46 import java.awt.TextArea; 47 import java.awt.event.ActionEvent; 48 import java.awt.event.ActionListener; 49 50 public class UpdatePopupMenu implements ActionListener { 51 52 private static final int imageSize = 32; 53 private static final int imageInset = 4; 54 private static GridBagLayout layout; 55 private static Panel mainControlPanel; 56 private static Panel resultButtonPanel; 57 private static TextArea instructionTextArea; 58 private static Button passButton; 59 private static Button failButton; 60 private static Frame mainFrame; 61 private static Thread mainThread = null; 62 private static boolean testPassed = false; 63 private static boolean isInterrupted = false; 64 private static final int testTimeOut = 300000; 65 66 private Image createSystemTrayIconImage() { 67 final BufferedImage trayImage = new BufferedImage( 68 imageSize, 69 imageSize, 70 BufferedImage.TYPE_INT_ARGB); 71 72 final Graphics2D imageGraphics = (Graphics2D) trayImage.getGraphics(); 73 74 imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 75 RenderingHints.VALUE_ANTIALIAS_ON); 76 77 imageGraphics.setColor(new Color(255, 255, 255, 0)); 78 imageGraphics.fillRect(0, 0, trayImage.getWidth(), 79 trayImage.getHeight()); 80 81 imageGraphics.setColor(Color.green); 82 83 int imageWidth = trayImage.getWidth() - 2 * imageInset; 84 int imageHeight = trayImage.getHeight() - 2 * imageInset; 85 86 imageGraphics.fillOval(imageInset, imageInset, imageWidth, imageHeight); 87 imageGraphics.setColor(Color.darkGray); 88 imageGraphics.drawOval(imageInset, imageInset, imageWidth, imageHeight); 89 90 return trayImage; 91 } 92 93 private PopupMenu createPopupMenu(final TrayIcon trayIcon, 94 final int menuCount) { 95 96 final PopupMenu trayIconPopupMenu = new PopupMenu(); 97 98 for (int i = 1; i <= menuCount; i++) { 99 final String popupMenuItemText = "MenuItem_" + i; 100 101 final MenuItem popupMenuItem = new MenuItem(popupMenuItemText); 102 103 popupMenuItem.addActionListener(new ActionListener() { 104 @Override 105 public void actionPerformed(final ActionEvent ae) { 106 trayIcon.setPopupMenu(createPopupMenu(trayIcon, 107 menuCount + 1)); 108 } 109 }); 110 111 trayIconPopupMenu.add(popupMenuItem); 112 } 113 114 return trayIconPopupMenu; 115 } 116 117 private void createSystemTrayIcons() { 118 119 final TrayIcon trayIcon = new TrayIcon(createSystemTrayIconImage()); 120 trayIcon.setImageAutoSize(true); 121 trayIcon.setToolTip("Update Popup Menu items"); 122 123 try { 124 trayIcon.setPopupMenu(createPopupMenu(trayIcon, 2)); 125 SystemTray.getSystemTray().add(trayIcon); 126 127 } catch (AWTException ex) { 128 throw new RuntimeException("System Tray cration failed"); 129 } 130 } 131 132 private void createInstructionUI() { 133 mainFrame = new Frame("Updating TrayIcon Popup Menu Item Test"); 134 layout = new GridBagLayout(); 135 mainControlPanel = new Panel(layout); 136 resultButtonPanel = new Panel(layout); 137 138 GridBagConstraints gbc = new GridBagConstraints(); 139 String instructions 140 = "INSTRUCTIONS:" 141 + "\n 1. Click on the System Tray Icon" 142 + "\n 2. Click on any of the displayed Menu items" 143 + "\n 3. Repeat step 1 and count the number of items in the " 144 + "Menu" 145 + "\n 4. The number of items in the Menu should increase by 1" 146 + "\n 5. Repeating steps 1, 2 and 3 should not break 4th step" 147 + "\n 6. Click Fail if the 4th step is broken, Otherwise " 148 + "click Pass "; 149 150 instructionTextArea = new TextArea(); 151 instructionTextArea.setText(instructions); 152 instructionTextArea.setEnabled(false); 153 instructionTextArea.setBackground(Color.white); 154 155 gbc.gridx = 0; 156 gbc.gridy = 0; 157 gbc.fill = GridBagConstraints.HORIZONTAL; 158 mainControlPanel.add(instructionTextArea, gbc); 159 160 passButton = new Button("Pass"); 161 passButton.setName("Pass"); 162 passButton.addActionListener(this); 163 164 failButton = new Button("Fail"); 165 failButton.setName("Fail"); 166 failButton.addActionListener(this); 167 168 gbc.gridx = 0; 169 gbc.gridy = 0; 170 resultButtonPanel.add(passButton, gbc); 171 gbc.gridx = 1; 172 gbc.gridy = 0; 173 resultButtonPanel.add(failButton, gbc); 174 gbc.gridx = 0; 175 gbc.gridy = 1; 176 mainControlPanel.add(resultButtonPanel, gbc); 177 178 mainFrame.add(mainControlPanel); 179 mainFrame.pack(); 180 mainFrame.setVisible(true); 181 } 182 183 @Override 184 public void actionPerformed(ActionEvent ae) { 185 if (ae.getSource() instanceof Button) { 186 Button btn = (Button) ae.getSource(); 187 switch (btn.getName()) { 188 case "Pass": 189 testPassed = true; 190 isInterrupted = true; 191 mainThread.interrupt(); 192 break; 193 194 case "Fail": 195 testPassed = false; 196 isInterrupted = true; 197 mainThread.interrupt(); 198 break; 199 } 200 } 201 } 202 203 private static void cleanUp() { 204 mainFrame.dispose(); 205 } 206 207 public static void main(final String[] args) throws Exception { 208 if (SystemTray.isSupported()) { 209 210 UpdatePopupMenu updatePopupMenu = new UpdatePopupMenu(); 211 updatePopupMenu.createInstructionUI(); 212 updatePopupMenu.createSystemTrayIcons(); 213 214 mainThread = Thread.currentThread(); 215 try { 216 mainThread.sleep(testTimeOut); 217 } catch (InterruptedException ex) { 218 if (!testPassed) { 219 throw new RuntimeException("Updating TrayIcon popup menu" 220 + " items FAILED"); 221 } 222 } finally { 223 cleanUp(); 224 } 225 226 if (!isInterrupted) { 227 throw new RuntimeException("Test Timed out after " 228 + testTimeOut / 1000 + " seconds"); 229 } 230 231 } else { 232 System.out.println("System Tray is not supported on this platform"); 233 } 234 } 235 }