Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / mobile_setup.js
blobf1b8e25aa66aa3cb21ea39f7cf84058854afd930
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() {
9   }
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 +
32                                     '/activation.html';
33   MobileSetup.PORTAL_OFFLINE_PAGE_URL = MobileSetup.EXTENSION_PAGE_URL +
34                                         '/portal_offline.html';
35   MobileSetup.REDIRECT_POST_PAGE_URL = MobileSetup.EXTENSION_PAGE_URL +
36                                        '/redirect.html';
38   MobileSetup.prototype = {
39     // Mobile device information.
40     deviceInfo_: null,
41     frameName_: '',
42     initialized_: false,
43     fakedTransaction_: false,
44     paymentShown_: false,
45     frameLoadError_: 0,
46     frameLoadIgnored_: true,
47     carrierPageUrl_: null,
48     spinnerInt_: -1,
49     // UI states.
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?');
61         return;
62       }
63       this.initialized_ = true;
64       self = this;
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);
75       });
77       $('closeButton').addEventListener('click', function(e) {
78         $('finalStatus').classList.add('hidden');
79       });
81       // Kick off activation process.
82       chrome.send('startActivation');
83     },
85     startSpinner_: function() {
86       this.stopSpinner_();
87       this.spinnerInt_ = setInterval(mobile.MobileSetup.drawProgress, 100);
88     },
90     stopSpinner_: function() {
91       if (this.spinnerInt_ != -1) {
92         clearInterval(this.spinnerInt_);
93         this.spinnerInt_ = -1;
94       }
95     },
97     onFrameLoaded_: function(success) {
98       chrome.send('paymentPortalLoad', [success ? 'ok' : 'failed']);
99     },
101     loadPaymentFrame_: function(deviceInfo) {
102       if (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);
111         } else {
112           this.frameLoadIgnored_ = false;
113           $(this.frameName_).contentWindow.location.href =
114               deviceInfo.payment_url;
115         }
116       }
117     },
119     onMessageReceived_: function(e) {
120       if (e.origin !=
121               this.deviceInfo_.payment_url.substring(0, e.origin.length) &&
122           e.origin != MobileSetup.EXTENSION_PAGE_URL)
123         return;
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]);
133       }
134     },
136     changeState_: function(deviceInfo) {
137       var newState = deviceInfo.state;
138       if (this.state_ == newState)
139         return;
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) {
144         return;
145       }
147       // Map handler state to UX.
148       var simpleActivationFlow =
149           (deviceInfo.activation_type == 'NonCellular' ||
150            deviceInfo.activation_type == 'OTA');
151       switch (newState) {
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)
160             break;
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_();
172           break;
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)
178             break;
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_();
190           break;
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');
202           }
203           this.loadPaymentFrame_(deviceInfo);
204           break;
205         case MobileSetup.PLAN_ACTIVATION_WAITING_FOR_CONNECTION:
206           var statusHeaderText;
207           var carrierPage;
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') {
213             statusHeaderText =
214                 loadTimeData.getString('connecting_header');
215             carrierPage = MobileSetup.ACTIVATION_PAGE_URL;
216           }
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_();
226           break;
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');
234           this.stopSpinner_();
235           this.paymentShown_ = true;
236           break;
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_);
250           this.stopSpinner_();
251           break;
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');
263           this.stopSpinner_();
264           break;
265       }
266       this.state_ = newState;
267     },
269     setCarrierPage_: function(url) {
270       if (this.carrierPageUrl_ == url)
271         return;
272       this.carrierPageUrl_ = url;
273       $('carrierPage').contentWindow.location.href = url;
274     },
276     updateDeviceStatus_: function(deviceInfo) {
277       this.changeState_(deviceInfo);
278     },
280     portalFrameLoadError_: function(errorCode) {
281       if (this.frameLoadIgnored_)
282         return;
283       console.log('Portal frame load error detected: ', errorCode);
284       this.frameLoadError_ = errorCode;
285     },
287     portalFrameLoadCompleted_: function() {
288       if (this.frameLoadIgnored_)
289         return;
290       console.log('Portal frame load completed!');
291       this.onFrameLoaded_(this.frameLoadError_ == 0);
292     },
294     sendPostFrame_: function(frameUrl) {
295       var msg = { type: 'postFrame' };
296       $(this.frameName_).contentWindow.postMessage(msg, frameUrl);
297     },
299     sendDeviceInfo_: function() {
300       var msg = {
301         type: 'deviceInfoMsg',
302         domain: document.location,
303         payload: {
304           'carrier': this.deviceInfo_.carrier,
305           'MEID': this.deviceInfo_.MEID,
306           'IMEI': this.deviceInfo_.IMEI,
307           'MDN': this.deviceInfo_.MDN
308         }
309       };
310       $(this.frameName_).contentWindow.postMessage(msg,
311           this.deviceInfo_.payment_url);
312     }
314   };
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;
343       ctx.beginPath();
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);
348       ctx.closePath();
349       ctx.fillStyle = 'rgba(240, 30, 29, ' + opacity + ')';
350       ctx.fill();
351     }
352   };
354   MobileSetup.deviceStateChanged = function(deviceInfo) {
355     MobileSetup.getInstance().updateDeviceStatus_(deviceInfo);
356   };
358   MobileSetup.portalFrameLoadError = function(errorCode) {
359     MobileSetup.getInstance().portalFrameLoadError_(errorCode);
360   };
362   MobileSetup.portalFrameLoadCompleted = function() {
363     MobileSetup.getInstance().portalFrameLoadCompleted_();
364   };
366   MobileSetup.loadPage = function() {
367     mobile.MobileSetup.getInstance().initialize('paymentForm',
368         mobile.MobileSetup.ACTIVATION_PAGE_URL);
369   };
371   // Export
372   return {
373     MobileSetup: MobileSetup
374   };
377 document.addEventListener('DOMContentLoaded', mobile.MobileSetup.loadPage);