1 /*
   2  * Copyright (c) 2007, 2014, 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 import java.awt.*;
  25 import java.awt.event.*;
  26 import java.awt.image.BufferedImage;
  27 
  28 /*
  29  * @test
  30  * @summary Check if ActionEvent triggered when a TrayIcon is double
  31  *          (single, on Mac) clicked is visible by an AWTEventListener
  32  *          added to the Toolkit. It also checks if all listeners are
  33  *          triggered when multiple AWTEventListeners and ActionListeners
  34  *          are added.
  35  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
  36  * @library ../../../../lib/testlibrary ../
  37  * @compile/module=java.desktop java/awt/Helper.java
  38  * @build ExtendedRobot SystemTrayIconHelper
  39  * @run main ActionEventMask
  40  */
  41 
  42 public class ActionEventMask {
  43 
  44     private Image image;
  45 
  46     TrayIcon icon;
  47     ExtendedRobot robot;
  48 
  49     boolean actionPerformed = false;
  50     boolean listenersInvoked = false;
  51     Object actionLock = new Object();
  52     Object listenersLock = new Object();
  53     static boolean isMacOS = false;
  54     static final int clickDelay = 50;
  55 
  56     ActionListener[] listeners;
  57     boolean[] listenerStatus;
  58 
  59     Object lLock = new Object();
  60     boolean doTest, listenerAdded;
  61     Button b1;
  62 
  63     public static void main(String[] args) throws Exception {
  64         if (! SystemTray.isSupported()) {
  65             System.out.println("SystemTray not supported on the platform under test. " +
  66                                "Marking the test passed");
  67         } else {
  68             if (System.getProperty("os.name").toLowerCase().startsWith("mac")) {
  69                 isMacOS = true;
  70             }
  71             new ActionEventMask().doTest();
  72         }
  73     }
  74 
  75     public ActionEventMask() throws Exception {
  76         EventQueue.invokeAndWait(this::initializeGUI);
  77     }
  78 
  79     void initializeGUI() {
  80         SystemTray tray = SystemTray.getSystemTray();
  81         icon = new TrayIcon(new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB), "Sample Icon");
  82 
  83         Toolkit.getDefaultToolkit().addAWTEventListener(event -> {
  84             if (doTest) {
  85                 System.out.println("ActionListener AWTEventListener");
  86                 if (! icon.equals(event.getSource())) {
  87                     throw new RuntimeException("FAIL: ActionEvent not triggered for icon");
  88                 }
  89                 actionPerformed = true;
  90                 synchronized (actionLock) {
  91                     try {
  92                         actionLock.notifyAll();
  93                     } catch (Exception e) {
  94                     }
  95                 }
  96             }
  97         }, AWTEvent.ACTION_EVENT_MASK);
  98 
  99         try {
 100             tray.add(icon);
 101         } catch (AWTException e) {
 102             throw new RuntimeException(e);
 103         }
 104 
 105         listeners = new ActionListener[3];
 106         listenerStatus = new boolean[3];
 107         for (int i = 0; i < listeners.length; i++) {
 108             final int index = i;
 109             listeners[i] = event -> {
 110                 listenerStatus[index] = true;
 111                 System.out.println("ActionListener listeners[" + index + "]");
 112                 for (int j = 0; j < listenerStatus.length; j++) {
 113                     if (! listenerStatus[j]) {
 114                         break;
 115                     }
 116                     listenersInvoked = true;
 117                     synchronized (listenersLock) {
 118                         try {
 119                             listenersLock.notifyAll();
 120                         } catch (Exception e) {
 121                         }
 122                     }
 123                 }
 124             };
 125         }
 126 
 127         Frame frame = new Frame("Test frame");
 128         b1 = new Button("Add ActionListener");
 129         b1.addActionListener(event -> {
 130             for (int i = 0; i < listeners.length; i++) {
 131                 icon.addActionListener(listeners[i]);
 132             }
 133             listenerAdded = true;
 134             synchronized (lLock) {
 135                 try {
 136                     lLock.notifyAll();
 137                 } catch (Exception e) {
 138                 }
 139             }
 140         });
 141         frame.setLayout(new FlowLayout());
 142         frame.add(b1);
 143         frame.setSize(200, 200);
 144         frame.addWindowListener(new WindowAdapter() {
 145             public void windowClosing(WindowEvent event) {
 146                 System.err.println("User closed the window");
 147                 System.exit(1);
 148             }
 149         });
 150         frame.setVisible(true);
 151     }
 152 
 153     private void doTest() throws Exception {
 154 
 155         robot = new ExtendedRobot();
 156 
 157         Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon);
 158         if (iconPosition == null)
 159             throw new RuntimeException("Unable to find the icon location!");
 160 
 161         robot.mouseMove(iconPosition.x, iconPosition.y);
 162         robot.waitForIdle();
 163 
 164         actionPerformed = false;
 165         doTest = true;
 166 
 167         if(isMacOS) {
 168             robot.click(InputEvent.BUTTON3_MASK);
 169         }else{
 170             robot.mousePress(InputEvent.BUTTON1_MASK);
 171             robot.delay(clickDelay);
 172             robot.mouseRelease(InputEvent.BUTTON1_MASK);
 173             robot.delay(clickDelay);
 174             robot.mousePress(InputEvent.BUTTON1_MASK);
 175             robot.delay(clickDelay);
 176             robot.mouseRelease(InputEvent.BUTTON1_MASK);
 177         }
 178 
 179         if (! actionPerformed) {
 180             synchronized (actionLock) {
 181                 try {
 182                     actionLock.wait(3000);
 183                 } catch (Exception e) {
 184                 }
 185             }
 186         }
 187         if (! actionPerformed)
 188             throw new RuntimeException("FAIL: AWTEventListener not notified when TrayIcon " +
 189                                "is "+(isMacOS ? "" :"double ")+ "clicked");
 190 
 191         doTest = false;
 192         listenerAdded = false;
 193         robot.mouseMove(b1.getLocationOnScreen().x + b1.getSize().width / 2,
 194                         b1.getLocationOnScreen().y + b1.getSize().height / 2);
 195         robot.waitForIdle();
 196         robot.click();
 197 
 198         if (! listenerAdded) {
 199             synchronized (lLock) {
 200                 try {
 201                     lLock.wait(3000);
 202                 } catch (Exception e) {
 203                 }
 204             }
 205         }
 206         if (! listenerAdded)
 207             throw new RuntimeException("FAIL: ActionListener could not be added at runtime. " +
 208                                "b1 did not trigger ActionEvent");
 209 
 210         doTest = true;
 211         actionPerformed = false;
 212         robot.mouseMove(iconPosition.x, iconPosition.y);
 213         robot.waitForIdle();
 214 
 215         if(isMacOS) {
 216             robot.click(InputEvent.BUTTON3_MASK);
 217         }else{
 218             robot.mousePress(InputEvent.BUTTON1_MASK);
 219             robot.delay(clickDelay);
 220             robot.mouseRelease(InputEvent.BUTTON1_MASK);
 221             robot.delay(clickDelay);
 222             robot.mousePress(InputEvent.BUTTON1_MASK);
 223             robot.delay(clickDelay);
 224             robot.mouseRelease(InputEvent.BUTTON1_MASK);
 225         }
 226 
 227         if (! listenersInvoked) {
 228             synchronized (listenersLock) {
 229                 try {
 230                     listenersLock.wait(3000);
 231                 } catch (Exception e) {
 232                 }
 233             }
 234         }
 235         if (! listenersInvoked) {
 236             System.err.println("FAIL: All the listeners not invoked!");
 237             for (int i = 0; i < listenerStatus.length; i++)
 238                 throw new RuntimeException("Listener[" + i + "] invoked: " + listenerStatus[i]);
 239         }
 240         if (! actionPerformed) {
 241             synchronized (actionLock) {
 242                 try {
 243                     actionLock.wait(3000);
 244                 } catch (Exception e) {
 245                 }
 246             }
 247         }
 248         if (! actionPerformed)
 249             throw new RuntimeException("FAIL: AWTEventListener not notified when TrayIcon " +
 250                     "is "+(isMacOS? "" : "double ")+ "clicked. A set of listeners were added after it");
 251 
 252     }
 253 }