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 MenuItem popupMenuItem = new MenuItem("MenuItem_" + i);
 100 
 101             popupMenuItem.addActionListener(new ActionListener() {
 102                 @Override
 103                 public void actionPerformed(final ActionEvent ae) {
 104                     trayIcon.setPopupMenu(createPopupMenu(trayIcon,
 105                             menuCount + 1));
 106                 }
 107             });
 108 
 109             trayIconPopupMenu.add(popupMenuItem);
 110         }
 111 
 112         return trayIconPopupMenu;
 113     }
 114 
 115     private void createSystemTrayIcons() {
 116 
 117         final TrayIcon trayIcon = new TrayIcon(createSystemTrayIconImage());
 118         trayIcon.setImageAutoSize(true);
 119         trayIcon.setToolTip("Update Popup Menu items");
 120 
 121         try {
 122             trayIcon.setPopupMenu(createPopupMenu(trayIcon, 2));
 123             SystemTray.getSystemTray().add(trayIcon);
 124 
 125         } catch (AWTException ex) {
 126             throw new RuntimeException("System Tray cration failed");
 127         }
 128     }
 129 
 130     private void createInstructionUI() {
 131         mainFrame = new Frame("Updating TrayIcon Popup Menu Item Test");
 132         layout = new GridBagLayout();
 133         mainControlPanel = new Panel(layout);
 134         resultButtonPanel = new Panel(layout);
 135 
 136         GridBagConstraints gbc = new GridBagConstraints();
 137         String instructions
 138                 = "INSTRUCTIONS:"
 139                 + "\n   1. Click on the System Tray Icon"
 140                 + "\n   2. Click on any of the displayed Menu items"
 141                 + "\n   3. Repeat step 1 and count the number of items in the "
 142                 + "Menu"
 143                 + "\n   4. The number of items in the Menu should increase by 1"
 144                 + "\n   5. Repeating steps 1, 2 and 3 should not break 4th step"
 145                 + "\n   6. Click Fail if the 4th step is broken, Otherwise "
 146                 + "click Pass ";
 147 
 148         instructionTextArea = new TextArea();
 149         instructionTextArea.setText(instructions);
 150         instructionTextArea.setEnabled(false);
 151         instructionTextArea.setBackground(Color.white);
 152 
 153         gbc.gridx = 0;
 154         gbc.gridy = 0;
 155         gbc.fill = GridBagConstraints.HORIZONTAL;
 156         mainControlPanel.add(instructionTextArea, gbc);
 157 
 158         passButton = new Button("Pass");
 159         passButton.setName("Pass");
 160         passButton.addActionListener(this);
 161 
 162         failButton = new Button("Fail");
 163         failButton.setName("Fail");
 164         failButton.addActionListener(this);
 165 
 166         gbc.gridx = 0;
 167         gbc.gridy = 0;
 168         resultButtonPanel.add(passButton, gbc);
 169         gbc.gridx = 1;
 170         gbc.gridy = 0;
 171         resultButtonPanel.add(failButton, gbc);
 172         gbc.gridx = 0;
 173         gbc.gridy = 1;
 174         mainControlPanel.add(resultButtonPanel, gbc);
 175 
 176         mainFrame.add(mainControlPanel);
 177         mainFrame.pack();
 178         mainFrame.setVisible(true);
 179     }
 180 
 181     @Override
 182     public void actionPerformed(ActionEvent ae) {
 183         if (ae.getSource() instanceof Button) {
 184             Button btn = (Button) ae.getSource();
 185             switch (btn.getName()) {
 186                 case "Pass":
 187                     testPassed = true;
 188                     isInterrupted = true;
 189                     mainThread.interrupt();
 190                     break;
 191 
 192                 case "Fail":
 193                     testPassed = false;
 194                     isInterrupted = true;
 195                     mainThread.interrupt();
 196                     break;
 197             }
 198         }
 199     }
 200 
 201     private static void cleanUp() {
 202         mainFrame.dispose();
 203     }
 204 
 205     public static void main(final String[] args) throws Exception {
 206         if (SystemTray.isSupported()) {
 207 
 208             UpdatePopupMenu updatePopupMenu = new UpdatePopupMenu();
 209             updatePopupMenu.createInstructionUI();
 210             updatePopupMenu.createSystemTrayIcons();
 211 
 212             mainThread = Thread.currentThread();
 213             try {
 214                 mainThread.sleep(testTimeOut);
 215             } catch (InterruptedException ex) {
 216                 if (!testPassed) {
 217                     throw new RuntimeException("Updating TrayIcon popup menu"
 218                             + " items FAILED");
 219                 }
 220             } finally {
 221                 cleanUp();
 222             }
 223 
 224             if (!isInterrupted) {
 225                 throw new RuntimeException("Test Timed out after "
 226                         + testTimeOut / 1000 + " seconds");
 227             }
 228 
 229         } else {
 230             System.out.println("System Tray is not supported on this platform");
 231         }
 232     }
 233 }