1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.webkit;
18 
19 import androidx.annotation.IntDef;
20 import androidx.annotation.RequiresFeature;
21 import androidx.annotation.RestrictTo;
22 
23 import org.jspecify.annotations.NonNull;
24 import org.jspecify.annotations.Nullable;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 import java.util.Objects;
29 
30 /**
31  * The Java representation of the HTML5 PostMessage event. See
32  * <a href="https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces">
33  *     https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces</a>
34  * for definition of a MessageEvent in HTML5.
35  */
36 public class WebMessageCompat {
37 
38     /**
39      * Indicates the payload of WebMessageCompat is String.
40      */
41     public static final int TYPE_STRING = 0;
42     /**
43      * Indicates the payload of WebMessageCompat is JavaScript ArrayBuffer.
44      */
45     public static final int TYPE_ARRAY_BUFFER = 1;
46     private final WebMessagePortCompat @Nullable [] mPorts;
47     private final @Nullable String mString;
48     private final byte @Nullable [] mArrayBuffer;
49     private final @Type int mType;
50 
51     /**
52      * Creates a WebMessage with String payload.
53      *
54      * @param data the string of the message.
55      */
WebMessageCompat(@ullable String data)56     public WebMessageCompat(@Nullable String data) {
57         this(data, null);
58     }
59 
60     /**
61      * Creates a WebMessage with String payload.
62      *
63      * @param data  the string data of the message.
64      * @param ports the ports that are sent with the message.
65      */
WebMessageCompat(@ullable String data, WebMessagePortCompat @Nullable [] ports)66     public WebMessageCompat(@Nullable String data, WebMessagePortCompat @Nullable [] ports) {
67         mString = data;
68         mArrayBuffer = null;
69         mPorts = ports;
70         mType = TYPE_STRING;
71     }
72 
73     /**
74      * Creates a WebMessage with JavaScript ArrayBuffer payload.
75      *
76      * @param arrayBuffer the array buffer data of the message.
77      */
78     @RequiresFeature(name = WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER,
79             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
WebMessageCompat(byte @NonNull [] arrayBuffer)80     public WebMessageCompat(byte @NonNull [] arrayBuffer) {
81         this(arrayBuffer, null);
82     }
83 
84     /**
85      * Creates a WebMessage with JavaScript ArrayBuffer payload.
86      *
87      * @param arrayBuffer the array buffer data of the message.
88      * @param ports       the ports that are sent with the message.
89      */
90     @RequiresFeature(name = WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER,
91             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
WebMessageCompat(byte @NonNull [] arrayBuffer, WebMessagePortCompat @Nullable [] ports)92     public WebMessageCompat(byte @NonNull [] arrayBuffer,
93             WebMessagePortCompat @Nullable [] ports) {
94         Objects.requireNonNull(arrayBuffer);
95         mArrayBuffer = arrayBuffer;
96         mString = null;
97         mPorts = ports;
98         mType = TYPE_ARRAY_BUFFER;
99     }
100 
101     /**
102      * Returns the payload type of the message.
103      *
104      * @return the payload type of WebMessageCompat.
105      */
getType()106     public @Type int getType() {
107         return mType;
108     }
109 
110     /**
111      * Returns the ArrayBuffer data of message. A ArrayBuffer or Transferable ArrayBuffer can be
112      * received from JavaScript. This should only be called when {@link #getType()} returns
113      * {@link #TYPE_ARRAY_BUFFER}. Example:
114      * <pre class="prettyprint">
115      * WebMessageCompat message = ... // The WebMessageCompat received or prepared.
116      * if (message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
117      *     byte[] arrayBuffer = message.getArrayBuffer();
118      *     // Access arrayBuffer data here.
119      * }
120      * </pre>
121      *
122      * @return ArrayBuffer payload data.
123      */
getArrayBuffer()124     public byte @NonNull [] getArrayBuffer() {
125         checkType(TYPE_ARRAY_BUFFER);
126         // Required for null check. ArrayBuffer is always non-null when mType == TYPE_ARRAY_BUFFER.
127         Objects.requireNonNull(mArrayBuffer);
128         return mArrayBuffer;
129     }
130 
131     /**
132      * Returns the String data of the message. This should only be called when {@link #getType()}
133      * returns {@link #TYPE_STRING}. Example:
134      * <pre class="prettyprint">
135      * WebMessageCompat message = ... // The WebMessageCompat received or prepared.
136      * if (message.getType() == WebMessageCompat.TYPE_STRING) {
137      *     String string = message.getData();
138      *     // Access string data here.
139      * }
140      * </pre>
141      *
142      * @return String payload data.
143      */
getData()144     public @Nullable String getData() {
145         checkType(TYPE_STRING);
146         return mString;
147     }
148 
149     /**
150      * Returns the ports that are sent with the message, or {@code null} if no port
151      * is sent.
152      */
getPorts()153     public WebMessagePortCompat @Nullable [] getPorts() {
154         return mPorts;
155     }
156 
typeToString(@ype int type)157     private @NonNull String typeToString(@Type int type) {
158         switch (type) {
159             case TYPE_STRING:
160                 return "String";
161             case TYPE_ARRAY_BUFFER:
162                 return "ArrayBuffer";
163             default:
164                 return "Unknown";
165         }
166     }
167 
checkType(@ype int typeForGetter)168     private void checkType(@Type int typeForGetter) {
169         if (typeForGetter != mType) {
170             throw new IllegalStateException("Wrong data accessor type detected. "
171                     + typeToString(mType) + " expected, but got " + typeToString(typeForGetter));
172         }
173     }
174 
175     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
176     @IntDef({TYPE_STRING, TYPE_ARRAY_BUFFER})
177     @Retention(RetentionPolicy.SOURCE)
178     public @interface Type {
179     }
180 }
181