|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 * http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 MARIONETTE_TIMEOUT = 10000; |
|
5 |
|
6 const CB_MESSAGE_SIZE_ETWS = 56; |
|
7 |
|
8 const CB_GSM_GEOGRAPHICAL_SCOPE_NAMES = [ |
|
9 "cell-immediate", |
|
10 "plmn", |
|
11 "location-area", |
|
12 "cell" |
|
13 ]; |
|
14 |
|
15 const CB_ETWS_WARNING_TYPE_NAMES = [ |
|
16 "earthquake", |
|
17 "tsunami", |
|
18 "earthquake-tsunami", |
|
19 "test", |
|
20 "other" |
|
21 ]; |
|
22 |
|
23 SpecialPowers.addPermission("cellbroadcast", true, document); |
|
24 SpecialPowers.addPermission("mobileconnection", true, document); |
|
25 |
|
26 let cbs = window.navigator.mozCellBroadcast; |
|
27 ok(cbs instanceof window.MozCellBroadcast, |
|
28 "mozCellBroadcast is instanceof " + cbs.constructor); |
|
29 |
|
30 let pendingEmulatorCmdCount = 0; |
|
31 function sendCellBroadcastMessage(pdu, callback) { |
|
32 pendingEmulatorCmdCount++; |
|
33 |
|
34 let cmd = "cbs pdu " + pdu; |
|
35 runEmulatorCmd(cmd, function(result) { |
|
36 pendingEmulatorCmdCount--; |
|
37 |
|
38 is(result[0], "OK", "Emulator response"); |
|
39 |
|
40 if (callback) { |
|
41 window.setTimeout(callback, 0); |
|
42 } |
|
43 }); |
|
44 } |
|
45 |
|
46 function buildHexStr(n, numSemiOctets) { |
|
47 let str = n.toString(16); |
|
48 ok(str.length <= numSemiOctets); |
|
49 while (str.length < numSemiOctets) { |
|
50 str = "0" + str; |
|
51 } |
|
52 return str; |
|
53 } |
|
54 |
|
55 function seq(end, begin) { |
|
56 let result = []; |
|
57 for (let i = begin || 0; i < end; i++) { |
|
58 result.push(i); |
|
59 } |
|
60 return result; |
|
61 } |
|
62 |
|
63 function repeat(func, array, oncomplete) { |
|
64 (function do_call(index) { |
|
65 let next = index < (array.length - 1) ? do_call.bind(null, index + 1) : oncomplete; |
|
66 func.apply(null, [array[index], next]); |
|
67 })(0); |
|
68 } |
|
69 |
|
70 function doTestHelper(pdu, nextTest, checkFunc) { |
|
71 cbs.addEventListener("received", function onreceived(event) { |
|
72 cbs.removeEventListener("received", onreceived); |
|
73 |
|
74 checkFunc(event.message); |
|
75 |
|
76 window.setTimeout(nextTest, 0); |
|
77 }); |
|
78 |
|
79 if (Array.isArray(pdu)) { |
|
80 repeat(sendCellBroadcastMessage, pdu); |
|
81 } else { |
|
82 sendCellBroadcastMessage(pdu); |
|
83 } |
|
84 } |
|
85 |
|
86 /** |
|
87 * Tests receiving Cell Broadcast messages, event instance type, all attributes |
|
88 * of CellBroadcastMessage exist. |
|
89 */ |
|
90 function testEtwsMessageAttributes() { |
|
91 log("Test ETWS Primary Notification message attributes"); |
|
92 |
|
93 cbs.addEventListener("received", function onreceived(event) { |
|
94 cbs.removeEventListener("received", onreceived); |
|
95 |
|
96 // Bug 838542: following check throws an exception and fails this case. |
|
97 // ok(event instanceof MozCellBroadcastEvent, |
|
98 // "event is instanceof " + event.constructor) |
|
99 ok(event, "event is valid"); |
|
100 |
|
101 let message = event.message; |
|
102 ok(message, "event.message is valid"); |
|
103 |
|
104 // Attributes other than `language` and `body` should always be assigned. |
|
105 ok(message.gsmGeographicalScope != null, "message.gsmGeographicalScope"); |
|
106 ok(message.messageCode != null, "message.messageCode"); |
|
107 ok(message.messageId != null, "message.messageId"); |
|
108 ok('language' in message, "message.language"); |
|
109 ok(message.language == null, "message.language"); |
|
110 ok('body' in message, "message.body"); |
|
111 ok(message.body == null, "message.body"); |
|
112 is(message.messageClass, "normal", "message.messageClass"); |
|
113 ok(message.timestamp != null, "message.timestamp"); |
|
114 ok(message.etws != null, "message.etws"); |
|
115 ok(message.etws.warningType != null, "message.etws.warningType"); |
|
116 ok(message.etws.emergencyUserAlert != null, |
|
117 "message.etws.emergencyUserAlert"); |
|
118 ok(message.etws.popup != null, "message.etws.popup"); |
|
119 ok(message.cdmaServiceCategory != null, "message.cdmaServiceCategory"); |
|
120 |
|
121 window.setTimeout(testReceiving_ETWS_GeographicalScope, 0); |
|
122 }); |
|
123 |
|
124 // Here we use a simple ETWS message for test. |
|
125 let pdu = buildHexStr(0, CB_MESSAGE_SIZE_ETWS * 2); // 6 octets |
|
126 sendCellBroadcastMessage(pdu); |
|
127 } |
|
128 |
|
129 function testReceiving_ETWS_GeographicalScope() { |
|
130 log("Test receiving ETWS Primary Notification - Geographical Scope"); |
|
131 |
|
132 function do_test(gs, nextTest) { |
|
133 // Here we use a simple ETWS message for test. |
|
134 let pdu = buildHexStr(((gs & 0x03) << 14), 4) |
|
135 + buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 2) * 2); |
|
136 |
|
137 doTestHelper(pdu, nextTest, function(message) { |
|
138 is(message.gsmGeographicalScope, CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[gs], |
|
139 "message.gsmGeographicalScope"); |
|
140 }); |
|
141 } |
|
142 |
|
143 repeat(do_test, seq(CB_GSM_GEOGRAPHICAL_SCOPE_NAMES.length), |
|
144 testReceiving_ETWS_MessageCode); |
|
145 } |
|
146 |
|
147 function testReceiving_ETWS_MessageCode() { |
|
148 log("Test receiving ETWS Primary Notification - Message Code"); |
|
149 |
|
150 // Message Code has 10 bits, and is ORed into a 16 bits 'serial' number. Here |
|
151 // we test every single bit to verify the operation doesn't go wrong. |
|
152 let messageCodesToTest = [ |
|
153 0x000, 0x001, 0x002, 0x004, 0x008, 0x010, 0x020, 0x040, |
|
154 0x080, 0x100, 0x200, 0x251 |
|
155 ]; |
|
156 |
|
157 function do_test(messageCode, nextTest) { |
|
158 let pdu = buildHexStr(((messageCode & 0x3FF) << 4), 4) |
|
159 + buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 2) * 2); |
|
160 |
|
161 doTestHelper(pdu, nextTest, function(message) { |
|
162 is(message.messageCode, messageCode, "message.messageCode"); |
|
163 }); |
|
164 } |
|
165 |
|
166 repeat(do_test, messageCodesToTest, testReceiving_ETWS_MessageId); |
|
167 } |
|
168 |
|
169 function testReceiving_ETWS_MessageId() { |
|
170 log("Test receiving ETWS Primary Notification - Message Identifier"); |
|
171 |
|
172 // Message Identifier has 16 bits, but no bitwise operation is needed. |
|
173 // Test some selected values only. |
|
174 let messageIdsToTest = [ |
|
175 0x0000, 0x0001, 0x0010, 0x0100, 0x1000, 0x1111, 0x8888, 0x8811 |
|
176 ]; |
|
177 |
|
178 function do_test(messageId, nextTest) { |
|
179 let pdu = buildHexStr(0, 4) |
|
180 + buildHexStr((messageId & 0xFFFF), 4) |
|
181 + buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 4) * 2); |
|
182 |
|
183 doTestHelper(pdu, nextTest, function(message) { |
|
184 is(message.messageId, messageId, "message.messageId"); |
|
185 }); |
|
186 } |
|
187 |
|
188 repeat(do_test, messageIdsToTest, testReceiving_ETWS_Timestamp); |
|
189 } |
|
190 |
|
191 function testReceiving_ETWS_Timestamp() { |
|
192 log("Test receiving ETWS Primary Notification - Timestamp"); |
|
193 |
|
194 // Here we use a simple ETWS message for test. |
|
195 let pdu = buildHexStr(0, 12); // 6 octets |
|
196 doTestHelper(pdu, testReceiving_ETWS_WarningType, function(message) { |
|
197 // Cell Broadcast messages do not contain a timestamp field (however, ETWS |
|
198 // does). We only check the timestamp doesn't go too far (60 seconds) here. |
|
199 let msMessage = message.timestamp.getTime(); |
|
200 let msNow = Date.now(); |
|
201 ok(Math.abs(msMessage - msNow) < (1000 * 60), "message.timestamp"); |
|
202 }); |
|
203 } |
|
204 |
|
205 function testReceiving_ETWS_WarningType() { |
|
206 log("Test receiving ETWS Primary Notification - Warning Type"); |
|
207 |
|
208 // Warning Type has 7 bits, and is ORed into a 16 bits 'WarningType' field. |
|
209 // Here we test every single bit to verify the operation doesn't go wrong. |
|
210 let warningTypesToTest = [ |
|
211 0x00, 0x01, 0x02, 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x41 |
|
212 ]; |
|
213 |
|
214 function do_test(warningType, nextTest) { |
|
215 let pdu = buildHexStr(0, 8) |
|
216 + buildHexStr(((warningType & 0x7F) << 9), 4) |
|
217 + buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 6) * 2); |
|
218 |
|
219 doTestHelper(pdu, nextTest, function(message) { |
|
220 ok(message.etws, "message.etws"); |
|
221 is(message.etws.warningType, CB_ETWS_WARNING_TYPE_NAMES[warningType], |
|
222 "message.etws.warningType"); |
|
223 }); |
|
224 } |
|
225 |
|
226 repeat(do_test, warningTypesToTest, testReceiving_ETWS_EmergencyUserAlert); |
|
227 } |
|
228 |
|
229 function doTestEmergencyUserAlert_or_Popup(name, mask, nextTest) { |
|
230 let pdu = buildHexStr(0, 8) |
|
231 + buildHexStr(mask, 4) |
|
232 + buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 6) * 2); |
|
233 doTestHelper(pdu, nextTest, function(message) { |
|
234 ok(message.etws != null, "message.etws"); |
|
235 is(message.etws[name], mask != 0, "message.etws." + name); |
|
236 }); |
|
237 } |
|
238 |
|
239 function testReceiving_ETWS_EmergencyUserAlert() { |
|
240 log("Test receiving ETWS Primary Notification - Emergency User Alert"); |
|
241 |
|
242 repeat(doTestEmergencyUserAlert_or_Popup.bind(null, "emergencyUserAlert"), |
|
243 [0x100, 0x000], testReceiving_ETWS_Popup); |
|
244 } |
|
245 |
|
246 function testReceiving_ETWS_Popup() { |
|
247 log("Test receiving ETWS Primary Notification - Popup"); |
|
248 |
|
249 repeat(doTestEmergencyUserAlert_or_Popup.bind(null, "popup"), |
|
250 [0x80, 0x000], cleanUp); |
|
251 } |
|
252 |
|
253 function cleanUp() { |
|
254 if (pendingEmulatorCmdCount > 0) { |
|
255 window.setTimeout(cleanUp, 100); |
|
256 return; |
|
257 } |
|
258 |
|
259 SpecialPowers.removePermission("mobileconnection", document); |
|
260 SpecialPowers.removePermission("cellbroadcast", true, document); |
|
261 |
|
262 finish(); |
|
263 } |
|
264 |
|
265 waitFor(testEtwsMessageAttributes, function() { |
|
266 return navigator.mozMobileConnections[0].voice.connected; |
|
267 }); |
|
268 |