1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 cr
.define('mobile', function() {
8 function MobileSetup() {
11 cr
.addSingletonGetter(MobileSetup
);
13 MobileSetup
.PLAN_ACTIVATION_UNKNOWN
= -2;
14 MobileSetup
.PLAN_ACTIVATION_PAGE_LOADING
= -1;
15 MobileSetup
.PLAN_ACTIVATION_START
= 0;
16 MobileSetup
.PLAN_ACTIVATION_TRYING_OTASP
= 1;
17 MobileSetup
.PLAN_ACTIVATION_INITIATING_ACTIVATION
= 3;
18 MobileSetup
.PLAN_ACTIVATION_RECONNECTING
= 4;
19 MobileSetup
.PLAN_ACTIVATION_WAITING_FOR_CONNECTION
= 5;
20 MobileSetup
.PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
= 6;
21 MobileSetup
.PLAN_ACTIVATION_SHOWING_PAYMENT
= 7;
22 MobileSetup
.PLAN_ACTIVATION_RECONNECTING_PAYMENT
= 8;
23 MobileSetup
.PLAN_ACTIVATION_DELAY_OTASP
= 9;
24 MobileSetup
.PLAN_ACTIVATION_START_OTASP
= 10;
25 MobileSetup
.PLAN_ACTIVATION_OTASP
= 11;
26 MobileSetup
.PLAN_ACTIVATION_DONE
= 12;
27 MobileSetup
.PLAN_ACTIVATION_ERROR
= 0xFF;
29 MobileSetup
.EXTENSION_PAGE_URL
=
30 'chrome-extension://iadeocfgjdjdmpenejdbfeaocpbikmab';
31 MobileSetup
.ACTIVATION_PAGE_URL
= MobileSetup
.EXTENSION_PAGE_URL
+
33 MobileSetup
.PORTAL_OFFLINE_PAGE_URL
= MobileSetup
.EXTENSION_PAGE_URL
+
34 '/portal_offline.html';
35 MobileSetup
.REDIRECT_POST_PAGE_URL
= MobileSetup
.EXTENSION_PAGE_URL
+
38 MobileSetup
.prototype = {
39 // Mobile device information.
43 fakedTransaction_
: false,
46 frameLoadIgnored_
: true,
47 carrierPageUrl_
: null,
50 state_
: MobileSetup
.PLAN_ACTIVATION_UNKNOWN
,
51 STATE_UNKNOWN_
: 'unknown',
52 STATE_CONNECTING_
: 'connecting',
53 STATE_ERROR_
: 'error',
54 STATE_PAYMENT_
: 'payment',
55 STATE_ACTIVATING_
: 'activating',
56 STATE_CONNECTED_
: 'connected',
58 initialize: function(frame_name
, carrierPage
) {
59 if (this.initialized_
) {
60 console
.log('calling initialize() again?');
63 this.initialized_
= true;
65 this.frameName_
= frame_name
;
67 cr
.ui
.dialogs
.BaseDialog
.OK_LABEL
=
68 loadTimeData
.getString('ok_button');
69 cr
.ui
.dialogs
.BaseDialog
.CANCEL_LABEL
=
70 loadTimeData
.getString('cancel_button');
71 this.confirm_
= new cr
.ui
.dialogs
.ConfirmDialog(document
.body
);
73 window
.addEventListener('message', function(e
) {
74 self
.onMessageReceived_(e
);
77 $('closeButton').addEventListener('click', function(e
) {
78 $('finalStatus').classList
.add('hidden');
81 // Kick off activation process.
82 chrome
.send('startActivation');
85 startSpinner_: function() {
87 this.spinnerInt_
= setInterval(mobile
.MobileSetup
.drawProgress
, 100);
90 stopSpinner_: function() {
91 if (this.spinnerInt_
!= -1) {
92 clearInterval(this.spinnerInt_
);
93 this.spinnerInt_
= -1;
97 onFrameLoaded_: function(success
) {
98 chrome
.send('paymentPortalLoad', [success
? 'ok' : 'failed']);
101 loadPaymentFrame_: function(deviceInfo
) {
103 this.frameLoadError_
= 0;
104 this.deviceInfo_
= deviceInfo
;
105 if (deviceInfo
.post_data
&& deviceInfo
.post_data
.length
) {
106 this.frameLoadIgnored_
= true;
107 $(this.frameName_
).contentWindow
.location
.href
=
108 MobileSetup
.REDIRECT_POST_PAGE_URL
+
109 '?post_data=' + escape(deviceInfo
.post_data
) +
110 '&formUrl=' + escape(deviceInfo
.payment_url
);
112 this.frameLoadIgnored_
= false;
113 $(this.frameName_
).contentWindow
.location
.href
=
114 deviceInfo
.payment_url
;
119 onMessageReceived_: function(e
) {
121 this.deviceInfo_
.payment_url
.substring(0, e
.origin
.length
) &&
122 e
.origin
!= MobileSetup
.EXTENSION_PAGE_URL
)
125 if (e
.data
.type
== 'requestDeviceInfoMsg') {
126 this.sendDeviceInfo_();
127 } else if (e
.data
.type
== 'framePostReady') {
128 this.frameLoadIgnored_
= false;
129 this.sendPostFrame_(e
.origin
);
130 } else if (e
.data
.type
== 'reportTransactionStatusMsg') {
131 console
.log('calling setTransactionStatus from onMessageReceived_');
132 chrome
.send('setTransactionStatus', [e
.data
.status
]);
136 changeState_: function(deviceInfo
) {
137 var newState
= deviceInfo
.state
;
138 if (this.state_
== newState
)
141 // The mobile setup is already in its final state.
142 if (this.state_
== MobileSetup
.PLAN_ACTIVATION_DONE
||
143 this.state_
== MobileSetup
.PLAN_ACTIVATION_ERROR
) {
147 // Map handler state to UX.
148 var simpleActivationFlow
=
149 (deviceInfo
.activation_type
== 'NonCellular' ||
150 deviceInfo
.activation_type
== 'OTA');
152 case MobileSetup
.PLAN_ACTIVATION_PAGE_LOADING
:
153 case MobileSetup
.PLAN_ACTIVATION_START
:
154 case MobileSetup
.PLAN_ACTIVATION_DELAY_OTASP
:
155 case MobileSetup
.PLAN_ACTIVATION_START_OTASP
:
156 case MobileSetup
.PLAN_ACTIVATION_RECONNECTING
:
157 case MobileSetup
.PLAN_ACTIVATION_RECONNECTING_PAYMENT
:
158 // Activation page should not be shown for the simple activation flow.
159 if (simpleActivationFlow
)
162 $('statusHeader').textContent
=
163 loadTimeData
.getString('connecting_header');
164 $('auxHeader').textContent
=
165 loadTimeData
.getString('please_wait');
166 $('paymentForm').classList
.add('hidden');
167 $('finalStatus').classList
.add('hidden');
168 this.setCarrierPage_(MobileSetup
.ACTIVATION_PAGE_URL
);
169 $('systemStatus').classList
.remove('hidden');
170 $('canvas').classList
.remove('hidden');
171 this.startSpinner_();
173 case MobileSetup
.PLAN_ACTIVATION_TRYING_OTASP
:
174 case MobileSetup
.PLAN_ACTIVATION_INITIATING_ACTIVATION
:
175 case MobileSetup
.PLAN_ACTIVATION_OTASP
:
176 // Activation page should not be shown for the simple activation flow.
177 if (simpleActivationFlow
)
180 $('statusHeader').textContent
=
181 loadTimeData
.getString('activating_header');
182 $('auxHeader').textContent
=
183 loadTimeData
.getString('please_wait');
184 $('paymentForm').classList
.add('hidden');
185 $('finalStatus').classList
.add('hidden');
186 this.setCarrierPage_(MobileSetup
.ACTIVATION_PAGE_URL
);
187 $('systemStatus').classList
.remove('hidden');
188 $('canvas').classList
.remove('hidden');
189 this.startSpinner_();
191 case MobileSetup
.PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
:
192 // Activation page should not be shown for the simple activation flow.
193 if (!simpleActivationFlow
) {
194 $('statusHeader').textContent
=
195 loadTimeData
.getString('connecting_header');
196 $('auxHeader').textContent
= '';
197 $('paymentForm').classList
.add('hidden');
198 $('finalStatus').classList
.add('hidden');
199 this.setCarrierPage_(MobileSetup
.ACTIVATION_PAGE_URL
);
200 $('systemStatus').classList
.remove('hidden');
201 $('canvas').classList
.remove('hidden');
203 this.loadPaymentFrame_(deviceInfo
);
205 case MobileSetup
.PLAN_ACTIVATION_WAITING_FOR_CONNECTION
:
206 var statusHeaderText
;
208 if (deviceInfo
.activation_type
== 'NonCellular') {
209 statusHeaderText
= loadTimeData
.getString(
210 'portal_unreachable_header');
211 carrierPage
= MobileSetup
.PORTAL_OFFLINE_PAGE_URL
;
212 } else if (deviceInfo
.activation_type
== 'OTA') {
214 loadTimeData
.getString('connecting_header');
215 carrierPage
= MobileSetup
.ACTIVATION_PAGE_URL
;
217 $('statusHeader').textContent
= statusHeaderText
;
218 $('auxHeader').textContent
= '';
219 $('auxHeader').classList
.add('hidden');
220 $('paymentForm').classList
.add('hidden');
221 $('finalStatus').classList
.add('hidden');
222 $('systemStatus').classList
.remove('hidden');
223 this.setCarrierPage_(carrierPage
);
224 $('canvas').classList
.remove('hidden');
225 this.startSpinner_();
227 case MobileSetup
.PLAN_ACTIVATION_SHOWING_PAYMENT
:
228 $('statusHeader').textContent
= '';
229 $('auxHeader').textContent
= '';
230 $('finalStatus').classList
.add('hidden');
231 $('systemStatus').classList
.add('hidden');
232 $('paymentForm').classList
.remove('hidden');
233 $('canvas').classList
.add('hidden');
235 this.paymentShown_
= true;
237 case MobileSetup
.PLAN_ACTIVATION_DONE
:
238 $('statusHeader').textContent
= '';
239 $('auxHeader').textContent
= '';
240 $('finalHeader').textContent
=
241 loadTimeData
.getString('completed_header');
242 $('finalMessage').textContent
=
243 loadTimeData
.getString('completed_text');
244 $('systemStatus').classList
.add('hidden');
245 $('closeButton').classList
.remove('hidden');
246 $('finalStatus').classList
.remove('hidden');
247 $('canvas').classList
.add('hidden');
248 $('closeButton').classList
.toggle('hidden', !this.paymentShown_
);
249 $('paymentForm').classList
.toggle('hidden', !this.paymentShown_
);
252 case MobileSetup
.PLAN_ACTIVATION_ERROR
:
253 $('statusHeader').textContent
= '';
254 $('auxHeader').textContent
= '';
255 $('finalHeader').textContent
=
256 loadTimeData
.getString('error_header');
257 $('finalMessage').textContent
= deviceInfo
.error
;
258 $('systemStatus').classList
.add('hidden');
259 $('canvas').classList
.add('hidden');
260 $('closeButton').classList
.toggle('hidden', !this.paymentShown_
);
261 $('paymentForm').classList
.toggle('hidden', !this.paymentShown_
);
262 $('finalStatus').classList
.remove('hidden');
266 this.state_
= newState
;
269 setCarrierPage_: function(url
) {
270 if (this.carrierPageUrl_
== url
)
272 this.carrierPageUrl_
= url
;
273 $('carrierPage').contentWindow
.location
.href
= url
;
276 updateDeviceStatus_: function(deviceInfo
) {
277 this.changeState_(deviceInfo
);
280 portalFrameLoadError_: function(errorCode
) {
281 if (this.frameLoadIgnored_
)
283 console
.log('Portal frame load error detected: ', errorCode
);
284 this.frameLoadError_
= errorCode
;
287 portalFrameLoadCompleted_: function() {
288 if (this.frameLoadIgnored_
)
290 console
.log('Portal frame load completed!');
291 this.onFrameLoaded_(this.frameLoadError_
== 0);
294 sendPostFrame_: function(frameUrl
) {
295 var msg
= { type
: 'postFrame' };
296 $(this.frameName_
).contentWindow
.postMessage(msg
, frameUrl
);
299 sendDeviceInfo_: function() {
301 type
: 'deviceInfoMsg',
302 domain
: document
.location
,
304 'carrier': this.deviceInfo_
.carrier
,
305 'MEID': this.deviceInfo_
.MEID
,
306 'IMEI': this.deviceInfo_
.IMEI
,
307 'MDN': this.deviceInfo_
.MDN
310 $(this.frameName_
).contentWindow
.postMessage(msg
,
311 this.deviceInfo_
.payment_url
);
316 MobileSetup
.drawProgress = function() {
317 var ctx
= canvas
.getContext('2d');
318 ctx
.clearRect(0, 0, canvas
.width
, canvas
.height
);
320 var segmentCount
= Math
.min(12, canvas
.width
/ 1.6); // Number of segments
321 var rotation
= 0.75; // Counterclockwise rotation
323 // Rotate canvas over time
324 ctx
.translate(canvas
.width
/ 2, canvas
.height
/ 2);
325 ctx
.rotate(Math
.PI
* 2 / (segmentCount
+ rotation
));
326 ctx
.translate(-canvas
.width
/ 2, -canvas
.height
/ 2);
328 var gap
= canvas
.width
/ 24; // Gap between segments
329 var oRadius
= canvas
.width
/ 2; // Outer radius
330 var iRadius
= oRadius
* 0.618; // Inner radius
331 var oCircumference
= Math
.PI
* 2 * oRadius
; // Outer circumference
332 var iCircumference
= Math
.PI
* 2 * iRadius
; // Inner circumference
333 var oGap
= gap
/ oCircumference
; // Gap size as fraction of outer ring
334 var iGap
= gap
/ iCircumference
; // Gap size as fraction of inner ring
335 var oArc
= Math
.PI
* 2 * (1 / segmentCount
- oGap
); // Angle of outer arcs
336 var iArc
= Math
.PI
* 2 * (1 / segmentCount
- iGap
); // Angle of inner arcs
338 for (i
= 0; i
< segmentCount
; i
++) { // Draw each segment
339 var opacity
= Math
.pow(1.0 - i
/ segmentCount
, 3.0);
340 opacity
= (0.15 + opacity
* 0.8); // Vary from 0.15 to 0.95
341 var angle
= - Math
.PI
* 2 * i
/ segmentCount
;
344 ctx
.arc(canvas
.width
/ 2, canvas
.height
/ 2, oRadius
,
345 angle
- oArc
/ 2, angle
+ oArc
/ 2, false);
346 ctx
.arc(canvas
.width
/ 2, canvas
.height
/ 2, iRadius
,
347 angle
+ iArc
/ 2, angle
- iArc
/ 2, true);
349 ctx
.fillStyle
= 'rgba(240, 30, 29, ' + opacity
+ ')';
354 MobileSetup
.deviceStateChanged = function(deviceInfo
) {
355 MobileSetup
.getInstance().updateDeviceStatus_(deviceInfo
);
358 MobileSetup
.portalFrameLoadError = function(errorCode
) {
359 MobileSetup
.getInstance().portalFrameLoadError_(errorCode
);
362 MobileSetup
.portalFrameLoadCompleted = function() {
363 MobileSetup
.getInstance().portalFrameLoadCompleted_();
366 MobileSetup
.loadPage = function() {
367 mobile
.MobileSetup
.getInstance().initialize('paymentForm',
368 mobile
.MobileSetup
.ACTIVATION_PAGE_URL
);
373 MobileSetup
: MobileSetup
377 document
.addEventListener('DOMContentLoaded', mobile
.MobileSetup
.loadPage
);