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
.localStrings_
= new LocalStrings();
40 MobileSetup
.prototype = {
41 // Mobile device information.
45 fakedTransaction_
: false,
48 frameLoadIgnored_
: true,
49 carrierPageUrl_
: null,
52 state_
: MobileSetup
.PLAN_ACTIVATION_UNKNOWN
,
53 STATE_UNKNOWN_
: 'unknown',
54 STATE_CONNECTING_
: 'connecting',
55 STATE_ERROR_
: 'error',
56 STATE_PAYMENT_
: 'payment',
57 STATE_ACTIVATING_
: 'activating',
58 STATE_CONNECTED_
: 'connected',
60 initialize: function(frame_name
, carrierPage
) {
61 if (this.initialized_
) {
62 console
.log('calling initialize() again?');
65 this.initialized_
= true;
67 this.frameName_
= frame_name
;
69 cr
.ui
.dialogs
.BaseDialog
.OK_LABEL
=
70 MobileSetup
.localStrings_
.getString('ok_button');
71 cr
.ui
.dialogs
.BaseDialog
.CANCEL_LABEL
=
72 MobileSetup
.localStrings_
.getString('cancel_button');
73 this.confirm_
= new cr
.ui
.dialogs
.ConfirmDialog(document
.body
);
75 window
.addEventListener('message', function(e
) {
76 self
.onMessageReceived_(e
);
79 $('closeButton').addEventListener('click', function(e
) {
80 $('finalStatus').classList
.add('hidden');
83 // Kick off activation process.
84 chrome
.send('startActivation');
87 startSpinner_: function() {
89 this.spinnerInt_
= setInterval(mobile
.MobileSetup
.drawProgress
, 100);
92 stopSpinner_: function() {
93 if (this.spinnerInt_
!= -1) {
94 clearInterval(this.spinnerInt_
);
95 this.spinnerInt_
= -1;
99 onFrameLoaded_: function(success
) {
100 chrome
.send('paymentPortalLoad', [success
? 'ok' : 'failed']);
103 loadPaymentFrame_: function(deviceInfo
) {
105 this.frameLoadError_
= 0;
106 this.deviceInfo_
= deviceInfo
;
107 if (deviceInfo
.post_data
&& deviceInfo
.post_data
.length
) {
108 this.frameLoadIgnored_
= true;
109 $(this.frameName_
).contentWindow
.location
.href
=
110 MobileSetup
.REDIRECT_POST_PAGE_URL
+
111 '?post_data=' + escape(deviceInfo
.post_data
) +
112 '&formUrl=' + escape(deviceInfo
.payment_url
);
114 this.frameLoadIgnored_
= false;
115 $(this.frameName_
).contentWindow
.location
.href
=
116 deviceInfo
.payment_url
;
121 onMessageReceived_: function(e
) {
123 this.deviceInfo_
.payment_url
.substring(0, e
.origin
.length
) &&
124 e
.origin
!= MobileSetup
.EXTENSION_PAGE_URL
)
127 if (e
.data
.type
== 'requestDeviceInfoMsg') {
128 this.sendDeviceInfo_();
129 } else if (e
.data
.type
== 'framePostReady') {
130 this.frameLoadIgnored_
= false;
131 this.sendPostFrame_(e
.origin
);
132 } else if (e
.data
.type
== 'reportTransactionStatusMsg') {
133 console
.log('calling setTransactionStatus from onMessageReceived_');
134 chrome
.send('setTransactionStatus', [e
.data
.status
]);
138 changeState_: function(deviceInfo
) {
139 var newState
= deviceInfo
.state
;
140 if (this.state_
== newState
)
143 // The mobile setup is already in its final state.
144 if (this.state_
== MobileSetup
.PLAN_ACTIVATION_DONE
||
145 this.state_
== MobileSetup
.PLAN_ACTIVATION_ERROR
) {
149 // Map handler state to UX.
151 case MobileSetup
.PLAN_ACTIVATION_PAGE_LOADING
:
152 case MobileSetup
.PLAN_ACTIVATION_START
:
153 case MobileSetup
.PLAN_ACTIVATION_DELAY_OTASP
:
154 case MobileSetup
.PLAN_ACTIVATION_START_OTASP
:
155 case MobileSetup
.PLAN_ACTIVATION_RECONNECTING
:
156 case MobileSetup
.PLAN_ACTIVATION_RECONNECTING_PAYMENT
:
157 // Activation page should not be shown for devices that are activated
158 // over non cellular network.
159 if (deviceInfo
.activate_over_non_cellular_network
)
162 $('statusHeader').textContent
=
163 MobileSetup
.localStrings_
.getString('connecting_header');
164 $('auxHeader').textContent
=
165 MobileSetup
.localStrings_
.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 devices that are activated
177 // over non cellular network.
178 if (deviceInfo
.activate_over_non_cellular_network
)
181 $('statusHeader').textContent
=
182 MobileSetup
.localStrings_
.getString('activating_header');
183 $('auxHeader').textContent
=
184 MobileSetup
.localStrings_
.getString('please_wait');
185 $('paymentForm').classList
.add('hidden');
186 $('finalStatus').classList
.add('hidden');
187 this.setCarrierPage_(MobileSetup
.ACTIVATION_PAGE_URL
);
188 $('systemStatus').classList
.remove('hidden');
189 $('canvas').classList
.remove('hidden');
190 this.startSpinner_();
192 case MobileSetup
.PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING
:
193 // Activation page should not be shown for devices that are activated
194 // over non cellular network.
195 if (!deviceInfo
.activate_over_non_cellular_network
) {
196 $('statusHeader').textContent
=
197 MobileSetup
.localStrings_
.getString('connecting_header');
198 $('auxHeader').textContent
= '';
199 $('paymentForm').classList
.add('hidden');
200 $('finalStatus').classList
.add('hidden');
201 this.setCarrierPage_(MobileSetup
.ACTIVATION_PAGE_URL
);
202 $('systemStatus').classList
.remove('hidden');
203 $('canvas').classList
.remove('hidden');
205 this.loadPaymentFrame_(deviceInfo
);
207 case MobileSetup
.PLAN_ACTIVATION_WAITING_FOR_CONNECTION
:
208 $('statusHeader').textContent
=
209 MobileSetup
.localStrings_
.getString('portal_unreachable_header');
210 $('auxHeader').textContent
= '';
211 $('auxHeader').classList
.add('hidden');
212 $('paymentForm').classList
.add('hidden');
213 $('finalStatus').classList
.add('hidden');
214 $('systemStatus').classList
.remove('hidden');
215 this.setCarrierPage_(MobileSetup
.PORTAL_OFFLINE_PAGE_URL
);
216 $('canvas').classList
.remove('hidden');
217 this.startSpinner_();
219 case MobileSetup
.PLAN_ACTIVATION_SHOWING_PAYMENT
:
220 $('statusHeader').textContent
= '';
221 $('auxHeader').textContent
= '';
222 $('finalStatus').classList
.add('hidden');
223 $('systemStatus').classList
.add('hidden');
224 $('paymentForm').classList
.remove('hidden');
225 $('canvas').classList
.add('hidden');
227 this.paymentShown_
= true;
229 case MobileSetup
.PLAN_ACTIVATION_DONE
:
230 $('statusHeader').textContent
= '';
231 $('auxHeader').textContent
= '';
232 $('finalHeader').textContent
=
233 MobileSetup
.localStrings_
.getString('completed_header');
234 $('finalMessage').textContent
=
235 MobileSetup
.localStrings_
.getString('completed_text');
236 $('systemStatus').classList
.add('hidden');
237 $('closeButton').classList
.remove('hidden');
238 $('finalStatus').classList
.remove('hidden');
239 $('canvas').classList
.add('hidden');
240 $('closeButton').classList
.toggle('hidden', !this.paymentShown_
);
241 $('paymentForm').classList
.toggle('hidden', !this.paymentShown_
);
244 case MobileSetup
.PLAN_ACTIVATION_ERROR
:
245 $('statusHeader').textContent
= '';
246 $('auxHeader').textContent
= '';
247 $('finalHeader').textContent
=
248 MobileSetup
.localStrings_
.getString('error_header');
249 $('finalMessage').textContent
= deviceInfo
.error
;
250 $('systemStatus').classList
.add('hidden');
251 $('canvas').classList
.add('hidden');
252 $('closeButton').classList
.toggle('hidden', !this.paymentShown_
);
253 $('paymentForm').classList
.toggle('hidden', !this.paymentShown_
);
254 $('finalStatus').classList
.remove('hidden');
258 this.state_
= newState
;
261 setCarrierPage_: function(url
) {
262 if (this.carrierPageUrl_
== url
)
264 this.carrierPageUrl_
= url
;
265 $('carrierPage').contentWindow
.location
.href
= url
;
268 updateDeviceStatus_: function(deviceInfo
) {
269 this.changeState_(deviceInfo
);
272 portalFrameLoadError_: function(errorCode
) {
273 if (this.frameLoadIgnored_
)
275 console
.log('Portal frame load error detected: ', errorCode
);
276 this.frameLoadError_
= errorCode
;
279 portalFrameLoadCompleted_: function() {
280 if (this.frameLoadIgnored_
)
282 console
.log('Portal frame load completed!');
283 this.onFrameLoaded_(this.frameLoadError_
== 0);
286 sendPostFrame_: function(frameUrl
) {
287 var msg
= { type
: 'postFrame' };
288 $(this.frameName_
).contentWindow
.postMessage(msg
, frameUrl
);
291 sendDeviceInfo_: function() {
293 type
: 'deviceInfoMsg',
294 domain
: document
.location
,
296 'carrier': this.deviceInfo_
.carrier
,
297 'MEID': this.deviceInfo_
.MEID
,
298 'IMEI': this.deviceInfo_
.IMEI
,
299 'MDN': this.deviceInfo_
.MDN
302 $(this.frameName_
).contentWindow
.postMessage(msg
,
303 this.deviceInfo_
.payment_url
);
308 MobileSetup
.drawProgress = function() {
309 var ctx
= canvas
.getContext('2d');
310 ctx
.clearRect(0, 0, canvas
.width
, canvas
.height
);
312 var segmentCount
= Math
.min(12, canvas
.width
/ 1.6); // Number of segments
313 var rotation
= 0.75; // Counterclockwise rotation
315 // Rotate canvas over time
316 ctx
.translate(canvas
.width
/ 2, canvas
.height
/ 2);
317 ctx
.rotate(Math
.PI
* 2 / (segmentCount
+ rotation
));
318 ctx
.translate(-canvas
.width
/ 2, -canvas
.height
/ 2);
320 var gap
= canvas
.width
/ 24; // Gap between segments
321 var oRadius
= canvas
.width
/ 2; // Outer radius
322 var iRadius
= oRadius
* 0.618; // Inner radius
323 var oCircumference
= Math
.PI
* 2 * oRadius
; // Outer circumference
324 var iCircumference
= Math
.PI
* 2 * iRadius
; // Inner circumference
325 var oGap
= gap
/ oCircumference
; // Gap size as fraction of outer ring
326 var iGap
= gap
/ iCircumference
; // Gap size as fraction of inner ring
327 var oArc
= Math
.PI
* 2 * (1 / segmentCount
- oGap
); // Angle of outer arcs
328 var iArc
= Math
.PI
* 2 * (1 / segmentCount
- iGap
); // Angle of inner arcs
330 for (i
= 0; i
< segmentCount
; i
++) { // Draw each segment
331 var opacity
= Math
.pow(1.0 - i
/ segmentCount
, 3.0);
332 opacity
= (0.15 + opacity
* 0.8); // Vary from 0.15 to 0.95
333 var angle
= - Math
.PI
* 2 * i
/ segmentCount
;
336 ctx
.arc(canvas
.width
/ 2, canvas
.height
/ 2, oRadius
,
337 angle
- oArc
/ 2, angle
+ oArc
/ 2, false);
338 ctx
.arc(canvas
.width
/ 2, canvas
.height
/ 2, iRadius
,
339 angle
+ iArc
/ 2, angle
- iArc
/ 2, true);
341 ctx
.fillStyle
= 'rgba(240, 30, 29, ' + opacity
+ ')';
346 MobileSetup
.deviceStateChanged = function(deviceInfo
) {
347 MobileSetup
.getInstance().updateDeviceStatus_(deviceInfo
);
350 MobileSetup
.portalFrameLoadError = function(errorCode
) {
351 MobileSetup
.getInstance().portalFrameLoadError_(errorCode
);
354 MobileSetup
.portalFrameLoadCompleted = function() {
355 MobileSetup
.getInstance().portalFrameLoadCompleted_();
358 MobileSetup
.loadPage = function() {
359 mobile
.MobileSetup
.getInstance().initialize('paymentForm',
360 mobile
.MobileSetup
.ACTIVATION_PAGE_URL
);
365 MobileSetup
: MobileSetup
369 document
.addEventListener('DOMContentLoaded', mobile
.MobileSetup
.loadPage
);