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