1 /* 2 * Copyright (c) 2015, 2018, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package robottest; 26 27 import java.io.File; 28 import java.io.FileInputStream; 29 import java.io.FileOutputStream; 30 import java.nio.Buffer; 31 import java.nio.IntBuffer; 32 import javafx.animation.AnimationTimer; 33 import javafx.collections.FXCollections; 34 import javafx.collections.ObservableList; 35 import javafx.event.ActionEvent; 36 import javafx.event.EventHandler; 37 import javafx.geometry.BoundingBox; 38 import javafx.geometry.Bounds; 39 import javafx.scene.Group; 40 import javafx.scene.Scene; 41 import javafx.scene.control.Button; 42 import javafx.scene.control.Label; 43 import javafx.scene.control.ListView; 44 import javafx.scene.control.TextField; 45 import javafx.scene.input.KeyCode; 46 import javafx.scene.input.MouseButton; 47 import javafx.scene.image.Image; 48 import javafx.scene.image.ImageView; 49 import javafx.scene.image.PixelReader; 50 import javafx.scene.image.WritableImage; 51 import javafx.scene.image.WritablePixelFormat; 52 import javafx.scene.layout.GridPane; 53 import javafx.scene.layout.Pane; 54 import javafx.scene.layout.VBox; 55 import javafx.scene.paint.Color; 56 import javafx.scene.robot.Robot; 57 import javafx.scene.shape.Rectangle; 58 import javafx.stage.Popup; 59 import javafx.stage.Stage; 60 61 public class RobotBuilder { 62 //Variable used by "RobotTest" section 63 private final Rectangle rec1 = new Rectangle(50, 50, 40, 160); 64 private Popup screenShot; 65 66 private static RobotBuilder instance; 67 68 // protected TestRobot {} 69 70 public static RobotBuilder getInstance() { 71 if (instance==null) 72 instance = new RobotBuilder(); 73 return instance; 74 } 75 76 /** 77 * The method updates globalScene with robot tests 78 * @param globalScene the global Scene 79 * @param mainBox the Box to insert into 80 * @param robotStage the Robot Stage 81 */ 82 void robotTest(final Scene globalScene, final VBox mainBox, 83 final Stage robotStage) { 84 Label l = new Label("Robot features Demo"); 85 Group lGroup = new Group(l); 86 lGroup.setLayoutX(400); 87 lGroup.setLayoutY(10); 88 89 //Rectangle's coordinates 90 final int recX = 50; 91 final int recY = 50; 92 93 Group allGroup = new Group(); 94 rec1.setFill(Color.RED); 95 Rectangle rec2 = new Rectangle(recX + 40, recY, 40, 160); 96 rec2.setFill(Color.BLUE); 97 Rectangle rec3 = new Rectangle(recX + 80, recY, 40, 160); 98 rec3.setFill(Color.YELLOW); 99 Rectangle rec4 = new Rectangle(recX + 120, recY, 40, 160); 100 rec4.setFill(Color.GREEN); 101 102 GridPane grid = new GridPane(); 103 grid.setVgap(50); 104 grid.setHgap(20); 105 grid.setLayoutX(recX + 300); 106 grid.setLayoutY(recY + 50); 107 108 final TextField result1 = new TextField("Result"); 109 result1.setEditable(false); 110 Button screenTestBtn = new Button("Robot Get Screen Capture Test"); 111 screenTestBtn.setOnAction(new EventHandler<ActionEvent>() { 112 @Override public void handle(ActionEvent e) { 113 screenShot = robotScreenTest(result1, robotStage); 114 } 115 }); 116 117 grid.setConstraints(screenTestBtn, 0, 0); 118 grid.getChildren().add(screenTestBtn); 119 grid.setConstraints(result1, 1, 0); 120 grid.getChildren().add(result1); 121 122 final TextField result2 = new TextField("Result"); 123 result2.setEditable(false); 124 Button pixelTestBtn = new Button("Robot Get Pixel Color Test"); 125 pixelTestBtn.setOnAction(new EventHandler<ActionEvent>() { 126 @Override public void handle(ActionEvent e) { 127 robotPixelTest(result2, robotStage); 128 } 129 }); 130 131 grid.setConstraints(pixelTestBtn, 0, 1); 132 grid.getChildren().add(pixelTestBtn); 133 grid.setConstraints(result2, 1, 1); 134 grid.getChildren().add(result2); 135 136 //KeyPressRelesase 137 final TextField writeField = new TextField(""); 138 Group writeFieldGroup = new Group(writeField); 139 writeFieldGroup.setLayoutX(recX); 140 writeFieldGroup.setLayoutY(recY + 200); 141 142 final TextField result3 = new TextField("Result"); 143 result3.setEditable(false); 144 145 Button keyTestBtn = new Button("Robot Key Press/Release Test"); 146 keyTestBtn.setOnAction(new EventHandler<ActionEvent>() { 147 @Override public void handle(ActionEvent e) { 148 robotKeyTest(writeField, result3); 149 } 150 }); 151 152 grid.setConstraints(keyTestBtn, 0, 2); 153 grid.getChildren().add(keyTestBtn); 154 grid.setConstraints(result3, 1, 2); 155 grid.getChildren().add(result3); 156 157 //Mouse wheel 158 final ListView<String> sv = new ListView<String>(); 159 ObservableList<String> items =FXCollections.observableArrayList ( 160 "a", "b", "c", "d", "e", "f", "g", "h", "i"); 161 sv.setItems(items); 162 sv.setPrefWidth(100); 163 sv.setPrefHeight(100); 164 165 Group svGroup = new Group(sv); 166 svGroup.setLayoutX(recX); 167 svGroup.setLayoutY(recY + 250); 168 169 final TextField result4 = new TextField("Result"); 170 result4.setEditable(false); 171 172 Button wheelTestBtn = new Button("Robot Mouse Press/Release/Wheel Test"); 173 wheelTestBtn.setOnAction(new EventHandler<ActionEvent>() { 174 @Override public void handle(ActionEvent e) { 175 robotWheelTest(sv, result4, robotStage); 176 } 177 }); 178 179 grid.setConstraints(wheelTestBtn, 0, 3); 180 grid.getChildren().add(wheelTestBtn); 181 grid.setConstraints(result4, 1, 3); 182 grid.getChildren().add(result4); 183 184 Button btn = new Button("Back"); 185 btn.setOnAction(new EventHandler<ActionEvent>() { 186 @Override public void handle(ActionEvent e) { 187 if ((screenShot != null) && (screenShot.isShowing())) { 188 screenShot.hide(); 189 } 190 globalScene.setRoot(mainBox); 191 } 192 }); 193 Group btnGroup = new Group(btn); 194 btnGroup.setLayoutX(450); 195 btnGroup.setLayoutY(450); 196 197 allGroup.getChildren().addAll(rec1, rec2, rec3, rec4, grid, lGroup, btnGroup, 198 writeFieldGroup, svGroup); 199 globalScene.setRoot(allGroup); 200 } 201 202 203 public void robotKeyTest(final TextField field, final TextField result) { 204 field.requestFocus(); 205 new AnimationTimer() { 206 long startTime = System.nanoTime(); 207 @Override 208 public void handle(long now) { 209 if (now > startTime + 3000000000l){ 210 stop(); 211 field.setText("Failed"); 212 } else if (field.isFocused()) { 213 stop(); 214 final Robot robot = new Robot(); 215 robot.keyPress(KeyCode.T); 216 robot.keyRelease(KeyCode.T); 217 robot.keyPress(KeyCode.E); 218 robot.keyRelease(KeyCode.E); 219 robot.keyPress(KeyCode.S); 220 robot.keyRelease(KeyCode.S); 221 robot.keyPress(KeyCode.T); 222 robot.keyRelease(KeyCode.T); 223 new AnimationTimer() { 224 long startTime = System.nanoTime(); 225 @Override 226 public void handle(long now) { 227 if (now > startTime + 3000000000l){ 228 stop(); 229 result.setText("Failed"); 230 } else if ((field.getText()).equals("test")) { 231 stop(); 232 result.setText("Passed"); 233 } 234 } 235 }.start(); 236 } 237 } 238 }.start(); 239 } 240 241 public void robotWheelTest(final ListView<String> lv, final TextField result, 242 Stage currentStage) { 243 //Caclulation of ListView minimal coordinates 244 Bounds bounds = lv.localToScreen(new BoundingBox(0, 0, 245 lv.getBoundsInParent().getWidth(), 246 lv.getBoundsInParent().getHeight())); 247 int x = 10 + (int) bounds.getMinX(); 248 int y = 10 + (int) bounds.getMinY(); 249 250 final Robot robot = new Robot(); 251 robot.mouseMove(x, y); 252 robot.mousePress(MouseButton.PRIMARY); 253 robot.mouseRelease(MouseButton.PRIMARY); 254 255 new AnimationTimer() { 256 long startTime = System.nanoTime(); 257 @Override 258 public void handle(long now) { 259 if (now > startTime + 3000000000l){ 260 stop(); 261 result.setText("Failed"); 262 } else if (lv.isFocused()) { 263 stop(); 264 robot.mouseWheel(-5); 265 robot.mousePress(MouseButton.PRIMARY); 266 robot.mouseRelease(MouseButton.PRIMARY); 267 new AnimationTimer() { 268 long startTime = System.nanoTime(); 269 @Override 270 public void handle(long now) { 271 if (now > startTime + 3000000000l){ 272 stop(); 273 result.setText("Scroll Down Failed"); 274 } else if (!lv.getSelectionModel(). 275 selectedItemProperty().getValue(). 276 equals("a")) { 277 stop(); 278 result.setText("Scroll Down Passed"); 279 } 280 } 281 }.start(); 282 } 283 } 284 }.start(); 285 } 286 287 public void robotPixelTest(final TextField result, Stage currentStage) { 288 Bounds bounds = rec1.localToScreen(new BoundingBox(0, 0, 289 rec1.getBoundsInParent().getWidth(), 290 rec1.getBoundsInParent().getHeight())); 291 int x = 53 + (int) bounds.getMinX(); 292 int y = 53 + (int) bounds.getMinY(); 293 int answer = assertPixelEquals(x, y, Color.RED) + 294 assertPixelEquals(x + 40, y, Color.BLUE) + 295 assertPixelEquals(x + 80, y, Color.YELLOW) + 296 assertPixelEquals(x + 120, y, Color.GREEN); 297 if (answer == 4) { 298 result.setText("Passed"); 299 } else { 300 result.setText("Failed"); 301 } 302 303 } 304 305 static int colorToRGB(Color c) { 306 int r = (int) Math.round(c.getRed() * 255.0); 307 int g = (int) Math.round(c.getGreen() * 255.0); 308 int b = (int) Math.round(c.getBlue() * 255.0); 309 return 0xff000000 | (r << 16) | (g << 8) | b; 310 } 311 312 public int assertPixelEquals(int x, int y, Color expected) { 313 final Robot robot = new Robot(); 314 int pixel = colorToRGB(robot.getPixelColor(x, y)); 315 int expectedPixel = colorToRGB(expected); 316 if (checkColor(pixel, expected)) { 317 return 1; 318 } else { 319 System.out.println("Expected color 0x" + Integer.toHexString(expectedPixel) + 320 " at " + x + "," + y + " but found 0x" + Integer.toHexString(pixel)); 321 } 322 return 0; 323 } 324 325 private boolean checkColor(int value, Color expected) { 326 double tolerance = 0.07; 327 double ered = expected.getRed(); 328 double egrn = expected.getGreen(); 329 double eblu = expected.getBlue(); 330 331 double vred = ((value & 0xff0000) >> 16) / 255.0; 332 double vgrn = ((value & 0x00ff00) >> 8) / 255.0; 333 double vblu = ((value & 0x0000ff)) / 255.0; 334 335 double dred = Math.abs(ered - vred); 336 double dgrn = Math.abs(egrn - vgrn); 337 double dblu = Math.abs(eblu - vblu); 338 339 if (dred <= tolerance && dgrn <= tolerance && dblu <= tolerance) { 340 return true; 341 } 342 343 return false; 344 } 345 346 public Popup robotScreenTest(final TextField result, Stage stage) { 347 Bounds bounds = rec1.localToScreen(new BoundingBox(0, 0, 348 rec1.getBoundsInParent().getWidth(), 349 rec1.getBoundsInParent().getHeight())); 350 351 int x = 50 + (int) bounds.getMinX(); 352 int y = 50 + (int) bounds.getMinY(); 353 boolean correct = true; 354 final Robot robot = new Robot(); 355 int width = 160; 356 int height = 160; 357 int[] intArr = new int[width * height]; 358 PixelReader pixelReader = robot.getScreenCapture(null, x, y, width, height).getPixelReader(); 359 WritablePixelFormat<IntBuffer> format = WritablePixelFormat.getIntArgbInstance(); 360 pixelReader.getPixels(0, 0, width, height, format, intArr, 0, width); 361 String filename= "scrCapture.bmp"; 362 File file = new File(filename); 363 try { 364 if (!file.exists()) { 365 file.createNewFile(); 366 } 367 BMPOutputStream bmp = new BMPOutputStream(new FileOutputStream(filename), intArr, width, height); 368 } catch (Exception e) {} 369 370 371 for (int i = width; i <= height*(height-1); i += width) { 372 for (int j = 1; j <= 38; j ++){ 373 if (!checkColor(intArr[j+i],Color.RED)) { 374 System.out.println(" pixel("+j+","+(i/width)+") "+ 375 Integer.toHexString(intArr[j+i])+" != "+ 376 Integer.toHexString(colorToRGB(Color.RED))); 377 correct = false; 378 } 379 } 380 for (int j = 41; j <= 78; j ++){ 381 if (!checkColor(intArr[j+i],Color.BLUE)) { 382 System.out.println(" pixel("+j+","+(i/width)+") "+ 383 Integer.toHexString(intArr[j+i])+" != "+ 384 Integer.toHexString(colorToRGB(Color.BLUE))); 385 correct = false; 386 } 387 } 388 for (int j = 81; j <= 118; j ++){ 389 if (!checkColor(intArr[j+i],Color.YELLOW)) { 390 System.out.println(" pixel("+j+","+(i/width)+") "+ 391 Integer.toHexString(intArr[j+i])+" != "+ 392 Integer.toHexString(colorToRGB(Color.YELLOW))); 393 correct = false; 394 } 395 } 396 for (int j = 121; j <= 158; j ++){ 397 if (!checkColor(intArr[j+i],Color.GREEN)) { 398 System.out.println(" pixel("+j+","+(i/width)+") "+ 399 Integer.toHexString(intArr[j+i])+" != "+ 400 Integer.toHexString(colorToRGB(Color.GREEN))); 401 correct = false; 402 } 403 } 404 } 405 if (correct) { 406 result.setText("Passed"); 407 } else { 408 result.setText("Failed"); 409 } 410 return showImage(stage, width, height, result); 411 } 412 413 private Popup showImage(Stage stage, int width, int height, TextField tf) { 414 int frame = 70; 415 Rectangle rec = new Rectangle(width + frame, height + frame); 416 FileInputStream os = null; 417 final File file = new File("scrCapture.bmp"); 418 try { 419 os = new FileInputStream(file); 420 } catch (Exception e) {} 421 422 final Popup popup = new Popup(); 423 ImageView iv = new ImageView(new Image(os)); 424 iv.setLayoutX(frame/2); 425 iv.setLayoutY(frame/2); 426 427 rec.setFill(Color.WHITE); 428 rec.setStroke(Color.BLACK); 429 Button exit = new Button("x"); 430 exit.setOnAction(new EventHandler<ActionEvent>() { 431 @Override public void handle(ActionEvent e) { 432 if (file.exists()&&tf.getText().equals("Passed")) { 433 file.deleteOnExit(); 434 } 435 popup.hide(); 436 } 437 }); 438 exit.setLayoutX(width + frame/2); 439 Pane popupPane = new Pane(rec, iv, exit); 440 popup.setX(stage.getX() + 550); 441 popup.setY(stage.getY() + 430); 442 popup.getContent().addAll(popupPane); 443 popup.show(stage); 444 return popup; 445 } 446 }