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);