001package Torello.Browser.BrowserAPI; 002 003import java.util.*; 004import javax.json.*; 005import javax.json.stream.*; 006import java.io.*; 007 008import java.lang.reflect.Method; 009import java.lang.reflect.Parameter; 010import java.util.function.Function; 011 012import Torello.Browser.BrowserEvent; 013import Torello.Browser.JavaScriptAPI.*; 014import Torello.Browser.helper.*; 015 016import Torello.Java.Additional.*; 017import Torello.Java.JSON.*; 018 019import static Torello.Java.JSON.JFlag.*; 020 021import Torello.Java.StrCmpr; 022import Torello.JavaDoc.StaticFunctional; 023import Torello.JavaDoc.JDHeaderBackgroundImg; 024import Torello.JavaDoc.Excuse; 025 026/** 027 * <SPAN CLASS=COPIEDJDK><B>A domain for interacting with Cast, Presentation API, and Remote Playback API 028 * functionalities.</B></SPAN> 029 * 030 * <EMBED CLASS='external-html' DATA-FILE-ID=CODE_GEN_NOTE> 031 */ 032@StaticFunctional(Excused={"counter"}, Excuses={Excuse.CONFIGURATION}) 033@JDHeaderBackgroundImg(EmbedTagFileID="WOOD_PLANK_NOTE") 034public class Cast 035{ 036 // ******************************************************************************************** 037 // ******************************************************************************************** 038 // Class Header Stuff 039 // ******************************************************************************************** 040 // ******************************************************************************************** 041 042 043 // No Pubic Constructors 044 private Cast () { } 045 046 // These two Vector's are used by all the "Methods" exported by this class. java.lang.reflect 047 // is used to generate the JSON String's. It saves thousands of lines of Auto-Generated Code. 048 private static final Map<String, Vector<String>> parameterNames = new HashMap<>(); 049 private static final Map<String, Vector<Class<?>>> parameterTypes = new HashMap<>(); 050 051 // Some Methods do not take any parameters - for instance all the "enable()" and "disable()" 052 // I simply could not get ride of RAW-TYPES and UNCHECKED warnings... so there are now, 053 // offically, two empty-vectors. One for String's, and the other for Classes. 054 055 private static final Vector<String> EMPTY_VEC_STR = new Vector<>(); 056 private static final Vector<Class<?>> EMPTY_VEC_CLASS = new Vector<>(); 057 058 static 059 { 060 for (Method m : Cast.class.getMethods()) 061 { 062 // This doesn't work! The parameter names are all "arg0" ... "argN" 063 // It works for java.lang.reflect.Field, BUT NOT java.lang.reflect.Parameter! 064 // 065 // Vector<String> parameterNamesList = new Vector<>(); -- NOPE! 066 067 Vector<Class<?>> parameterTypesList = new Vector<>(); 068 069 for (Parameter p : m.getParameters()) parameterTypesList.add(p.getType()); 070 071 parameterTypes.put( 072 m.getName(), 073 (parameterTypesList.size() > 0) ? parameterTypesList : EMPTY_VEC_CLASS 074 ); 075 } 076 } 077 078 static 079 { 080 Vector<String> v = null; 081 082 v = new Vector<String>(1); 083 parameterNames.put("enable", v); 084 Collections.addAll(v, new String[] 085 { "presentationUrl", }); 086 087 parameterNames.put("disable", EMPTY_VEC_STR); 088 089 v = new Vector<String>(1); 090 parameterNames.put("setSinkToUse", v); 091 Collections.addAll(v, new String[] 092 { "sinkName", }); 093 094 v = new Vector<String>(1); 095 parameterNames.put("startDesktopMirroring", v); 096 Collections.addAll(v, new String[] 097 { "sinkName", }); 098 099 v = new Vector<String>(1); 100 parameterNames.put("startTabMirroring", v); 101 Collections.addAll(v, new String[] 102 { "sinkName", }); 103 104 v = new Vector<String>(1); 105 parameterNames.put("stopCasting", v); 106 Collections.addAll(v, new String[] 107 { "sinkName", }); 108 } 109 110 111 // ******************************************************************************************** 112 // ******************************************************************************************** 113 // Types - Static Inner Classes 114 // ******************************************************************************************** 115 // ******************************************************************************************** 116 117 /** <CODE>[No Description Provided by Google]</CODE> */ 118 public static class Sink 119 extends BaseType 120 implements java.io.Serializable 121 { 122 /** For Object Serialization. java.io.Serializable */ 123 protected static final long serialVersionUID = 1; 124 125 public boolean[] optionals() 126 { return new boolean[] { false, false, true, }; } 127 128 /** <CODE>[No Description Provided by Google]</CODE> */ 129 public final String name; 130 131 /** <CODE>[No Description Provided by Google]</CODE> */ 132 public final String id; 133 134 /** 135 * Text describing the current session. Present only if there is an active 136 * session on the sink. 137 * <BR /><B CLASS=Opt>OPTIONAL</B> 138 */ 139 public final String session; 140 141 /** 142 * Constructor 143 * 144 * @param name - 145 * 146 * @param id - 147 * 148 * @param session 149 * Text describing the current session. Present only if there is an active 150 * session on the sink. 151 * <BR /><B CLASS=Opt>OPTIONAL</B> 152 */ 153 public Sink(String name, String id, String session) 154 { 155 // Exception-Check(s) to ensure that if any parameters which are not declared as 156 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 157 158 if (name == null) THROWS.throwNPE("name"); 159 if (id == null) THROWS.throwNPE("id"); 160 161 this.name = name; 162 this.id = id; 163 this.session = session; 164 } 165 166 /** 167 * JSON Object Constructor 168 * @param jo A Json-Object having data about an instance of {@code 'Sink'}. 169 */ 170 public Sink (JsonObject jo) 171 { 172 this.name = ReadJSON.getString(jo, "name", false, true); 173 this.id = ReadJSON.getString(jo, "id", false, true); 174 this.session = ReadJSON.getString(jo, "session", true, false); 175 } 176 177 178 /** Checks whether {@code 'this'} equals an input Java-{@code Object} */ 179 public boolean equals(Object other) 180 { 181 if (this == other) return true; 182 if (other == null) return false; 183 if (other.getClass() != this.getClass()) return false; 184 185 Sink o = (Sink) other; 186 187 return 188 Objects.equals(this.name, o.name) 189 && Objects.equals(this.id, o.id) 190 && Objects.equals(this.session, o.session); 191 } 192 193 /** Generates a Hash-Code for {@code 'this'} instance */ 194 public int hashCode() 195 { 196 return 197 Objects.hashCode(this.name) 198 + Objects.hashCode(this.id) 199 + Objects.hashCode(this.session); 200 } 201 } 202 203 /** 204 * This is fired whenever the list of available sinks changes. A sink is a 205 * device or a software surface that you can cast to. 206 */ 207 public static class sinksUpdated 208 extends BrowserEvent 209 implements java.io.Serializable 210 { 211 /** For Object Serialization. java.io.Serializable */ 212 protected static final long serialVersionUID = 1; 213 214 public boolean[] optionals() 215 { return new boolean[] { false, }; } 216 217 /** <CODE>[No Description Provided by Google]</CODE> */ 218 public final Cast.Sink[] sinks; 219 220 /** 221 * Constructor 222 * 223 * @param sinks - 224 */ 225 public sinksUpdated(Cast.Sink[] sinks) 226 { 227 super("Cast", "sinksUpdated", 1); 228 229 // Exception-Check(s) to ensure that if any parameters which are not declared as 230 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 231 232 if (sinks == null) THROWS.throwNPE("sinks"); 233 234 this.sinks = sinks; 235 } 236 237 /** 238 * JSON Object Constructor 239 * @param jo A Json-Object having data about an instance of {@code 'sinksUpdated'}. 240 */ 241 public sinksUpdated (JsonObject jo) 242 { 243 super("Cast", "sinksUpdated", 1); 244 245 this.sinks = (jo.getJsonArray("sinks") == null) 246 ? null 247 : RJArrIntoStream.objArr(jo.getJsonArray("sinks"), null, 0, Cast.Sink.class).toArray(Cast.Sink[]::new); 248 249 } 250 251 252 /** Checks whether {@code 'this'} equals an input Java-{@code Object} */ 253 public boolean equals(Object other) 254 { 255 if (this == other) return true; 256 if (other == null) return false; 257 if (other.getClass() != this.getClass()) return false; 258 259 sinksUpdated o = (sinksUpdated) other; 260 261 return 262 Arrays.deepEquals(this.sinks, o.sinks); 263 } 264 265 /** Generates a Hash-Code for {@code 'this'} instance */ 266 public int hashCode() 267 { 268 return 269 Arrays.deepHashCode(this.sinks); 270 } 271 } 272 273 /** 274 * This is fired whenever the outstanding issue/error message changes. 275 * |issueMessage| is empty if there is no issue. 276 */ 277 public static class issueUpdated 278 extends BrowserEvent 279 implements java.io.Serializable 280 { 281 /** For Object Serialization. java.io.Serializable */ 282 protected static final long serialVersionUID = 1; 283 284 public boolean[] optionals() 285 { return new boolean[] { false, }; } 286 287 /** <CODE>[No Description Provided by Google]</CODE> */ 288 public final String issueMessage; 289 290 /** 291 * Constructor 292 * 293 * @param issueMessage - 294 */ 295 public issueUpdated(String issueMessage) 296 { 297 super("Cast", "issueUpdated", 1); 298 299 // Exception-Check(s) to ensure that if any parameters which are not declared as 300 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 301 302 if (issueMessage == null) THROWS.throwNPE("issueMessage"); 303 304 this.issueMessage = issueMessage; 305 } 306 307 /** 308 * JSON Object Constructor 309 * @param jo A Json-Object having data about an instance of {@code 'issueUpdated'}. 310 */ 311 public issueUpdated (JsonObject jo) 312 { 313 super("Cast", "issueUpdated", 1); 314 315 this.issueMessage = ReadJSON.getString(jo, "issueMessage", false, true); 316 } 317 318 319 /** Checks whether {@code 'this'} equals an input Java-{@code Object} */ 320 public boolean equals(Object other) 321 { 322 if (this == other) return true; 323 if (other == null) return false; 324 if (other.getClass() != this.getClass()) return false; 325 326 issueUpdated o = (issueUpdated) other; 327 328 return 329 Objects.equals(this.issueMessage, o.issueMessage); 330 } 331 332 /** Generates a Hash-Code for {@code 'this'} instance */ 333 public int hashCode() 334 { 335 return 336 Objects.hashCode(this.issueMessage); 337 } 338 } 339 340 341 // Counter for keeping the WebSocket Request ID's distinct. 342 private static int counter = 1; 343 344 /** 345 * Starts observing for sinks that can be used for tab mirroring, and if set, 346 * sinks compatible with |presentationUrl| as well. When sinks are found, a 347 * |sinksUpdated| event is fired. 348 * Also starts observing for issue messages. When an issue is added or removed, 349 * an |issueUpdated| event is fired. 350 * 351 * @param presentationUrl - 352 * <BR /><B CLASS=Opt>OPTIONAL</B> 353 * 354 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 355 * {@link Ret0}></CODE> 356 * 357 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 358 * browser receives the invocation-request. 359 * 360 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 361 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 362 * {@code >} to ensure the Browser Function has run to completion. 363 */ 364 public static Script<String, JsonObject, Ret0> enable(String presentationUrl) 365 { 366 final int webSocketID = 16000000 + counter++; 367 final boolean[] optionals = { true, }; 368 369 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 370 String requestJSON = WriteJSON.get( 371 parameterTypes.get("enable"), 372 parameterNames.get("enable"), 373 optionals, webSocketID, 374 "Cast.enable", 375 presentationUrl 376 ); 377 378 // This Remote Command does not have a Return-Value. 379 return new Script<> 380 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 381 } 382 383 /** 384 * Stops observing for sinks and issues. 385 * 386 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 387 * {@link Ret0}></CODE> 388 * 389 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 390 * browser receives the invocation-request. 391 * 392 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 393 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 394 * {@code >} to ensure the Browser Function has run to completion. 395 */ 396 public static Script<String, JsonObject, Ret0> disable() 397 { 398 final int webSocketID = 16001000 + counter++; 399 final boolean[] optionals = new boolean[0]; 400 401 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 402 String requestJSON = WriteJSON.get( 403 parameterTypes.get("disable"), 404 parameterNames.get("disable"), 405 optionals, webSocketID, 406 "Cast.disable" 407 ); 408 409 // This Remote Command does not have a Return-Value. 410 return new Script<> 411 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 412 } 413 414 /** 415 * Sets a sink to be used when the web page requests the browser to choose a 416 * sink via Presentation API, Remote Playback API, or Cast SDK. 417 * 418 * @param sinkName - 419 * 420 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 421 * {@link Ret0}></CODE> 422 * 423 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 424 * browser receives the invocation-request. 425 * 426 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 427 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 428 * {@code >} to ensure the Browser Function has run to completion. 429 */ 430 public static Script<String, JsonObject, Ret0> setSinkToUse(String sinkName) 431 { 432 // Exception-Check(s) to ensure that if any parameters which are not declared as 433 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 434 435 if (sinkName == null) THROWS.throwNPE("sinkName"); 436 437 final int webSocketID = 16002000 + counter++; 438 final boolean[] optionals = { false, }; 439 440 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 441 String requestJSON = WriteJSON.get( 442 parameterTypes.get("setSinkToUse"), 443 parameterNames.get("setSinkToUse"), 444 optionals, webSocketID, 445 "Cast.setSinkToUse", 446 sinkName 447 ); 448 449 // This Remote Command does not have a Return-Value. 450 return new Script<> 451 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 452 } 453 454 /** 455 * Starts mirroring the desktop to the sink. 456 * 457 * @param sinkName - 458 * 459 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 460 * {@link Ret0}></CODE> 461 * 462 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 463 * browser receives the invocation-request. 464 * 465 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 466 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 467 * {@code >} to ensure the Browser Function has run to completion. 468 */ 469 public static Script<String, JsonObject, Ret0> startDesktopMirroring(String sinkName) 470 { 471 // Exception-Check(s) to ensure that if any parameters which are not declared as 472 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 473 474 if (sinkName == null) THROWS.throwNPE("sinkName"); 475 476 final int webSocketID = 16003000 + counter++; 477 final boolean[] optionals = { false, }; 478 479 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 480 String requestJSON = WriteJSON.get( 481 parameterTypes.get("startDesktopMirroring"), 482 parameterNames.get("startDesktopMirroring"), 483 optionals, webSocketID, 484 "Cast.startDesktopMirroring", 485 sinkName 486 ); 487 488 // This Remote Command does not have a Return-Value. 489 return new Script<> 490 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 491 } 492 493 /** 494 * Starts mirroring the tab to the sink. 495 * 496 * @param sinkName - 497 * 498 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 499 * {@link Ret0}></CODE> 500 * 501 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 502 * browser receives the invocation-request. 503 * 504 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 505 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 506 * {@code >} to ensure the Browser Function has run to completion. 507 */ 508 public static Script<String, JsonObject, Ret0> startTabMirroring(String sinkName) 509 { 510 // Exception-Check(s) to ensure that if any parameters which are not declared as 511 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 512 513 if (sinkName == null) THROWS.throwNPE("sinkName"); 514 515 final int webSocketID = 16004000 + counter++; 516 final boolean[] optionals = { false, }; 517 518 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 519 String requestJSON = WriteJSON.get( 520 parameterTypes.get("startTabMirroring"), 521 parameterNames.get("startTabMirroring"), 522 optionals, webSocketID, 523 "Cast.startTabMirroring", 524 sinkName 525 ); 526 527 // This Remote Command does not have a Return-Value. 528 return new Script<> 529 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 530 } 531 532 /** 533 * Stops the active Cast session on the sink. 534 * 535 * @param sinkName - 536 * 537 * @return An instance of <CODE>{@link Script}<String, {@link JsonObject}, 538 * {@link Ret0}></CODE> 539 * 540 * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the 541 * browser receives the invocation-request. 542 * 543 * <BR /><BR />This Browser-Function <I>does not have</I> a return-value. You may choose to 544 * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0} 545 * {@code >} to ensure the Browser Function has run to completion. 546 */ 547 public static Script<String, JsonObject, Ret0> stopCasting(String sinkName) 548 { 549 // Exception-Check(s) to ensure that if any parameters which are not declared as 550 // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw. 551 552 if (sinkName == null) THROWS.throwNPE("sinkName"); 553 554 final int webSocketID = 16005000 + counter++; 555 final boolean[] optionals = { false, }; 556 557 // Convert Method Parameters into JSON. Build the JSON Request-Object (as a String) 558 String requestJSON = WriteJSON.get( 559 parameterTypes.get("stopCasting"), 560 parameterNames.get("stopCasting"), 561 optionals, webSocketID, 562 "Cast.stopCasting", 563 sinkName 564 ); 565 566 // This Remote Command does not have a Return-Value. 567 return new Script<> 568 (webSocketID, requestJSON, VOID_RETURN.NoReturnValues); 569 } 570 571}