• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4
5
6cr.define('mobile', function() {
7
8  function MobileSetup() {
9  }
10
11  cr.addSingletonGetter(MobileSetup);
12
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;
28
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';
37
38  MobileSetup.localStrings_ = new LocalStrings();
39
40  MobileSetup.prototype = {
41    // Mobile device information.
42    deviceInfo_: null,
43    frameName_: '',
44    initialized_: false,
45    fakedTransaction_: false,
46    paymentShown_: false,
47    frameLoadError_: 0,
48    frameLoadIgnored_: true,
49    carrierPageUrl_: null,
50    spinnerInt_: -1,
51    // UI states.
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',
59
60    initialize: function(frame_name, carrierPage) {
61      if (this.initialized_) {
62        console.log('calling initialize() again?');
63        return;
64      }
65      this.initialized_ = true;
66      self = this;
67      this.frameName_ = frame_name;
68
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);
74
75      window.addEventListener('message', function(e) {
76          self.onMessageReceived_(e);
77      });
78
79      $('closeButton').addEventListener('click', function(e) {
80        $('finalStatus').classList.add('hidden');
81      });
82
83      // Kick off activation process.
84      chrome.send('startActivation');
85    },
86
87    startSpinner_: function() {
88      this.stopSpinner_();
89      this.spinnerInt_ = setInterval(mobile.MobileSetup.drawProgress, 100);
90    },
91
92    stopSpinner_: function() {
93      if (this.spinnerInt_ != -1) {
94        clearInterval(this.spinnerInt_);
95        this.spinnerInt_ = -1;
96      }
97    },
98
99    onFrameLoaded_: function(success) {
100      chrome.send('paymentPortalLoad', [success ? 'ok' : 'failed']);
101    },
102
103    loadPaymentFrame_: function(deviceInfo) {
104      if (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);
113        } else {
114          this.frameLoadIgnored_ = false;
115          $(this.frameName_).contentWindow.location.href =
116              deviceInfo.payment_url;
117        }
118      }
119    },
120
121    onMessageReceived_: function(e) {
122      if (e.origin !=
123              this.deviceInfo_.payment_url.substring(0, e.origin.length) &&
124          e.origin != MobileSetup.EXTENSION_PAGE_URL)
125        return;
126
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]);
135      }
136    },
137
138    changeState_: function(deviceInfo) {
139      var newState = deviceInfo.state;
140      if (this.state_ == newState)
141        return;
142
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) {
146        return;
147      }
148
149      // Map handler state to UX.
150      switch (newState) {
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)
160            break;
161
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_();
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 devices that are activated
177          // over non cellular network.
178          if (deviceInfo.activate_over_non_cellular_network)
179            break;
180
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_();
191          break;
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');
204          }
205          this.loadPaymentFrame_(deviceInfo);
206          break;
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_();
218          break;
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');
226          this.stopSpinner_();
227          this.paymentShown_ = true;
228          break;
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_);
242          this.stopSpinner_();
243          break;
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');
255          this.stopSpinner_();
256          break;
257      }
258      this.state_ = newState;
259    },
260
261    setCarrierPage_: function(url) {
262      if (this.carrierPageUrl_ == url)
263        return;
264      this.carrierPageUrl_ = url;
265      $('carrierPage').contentWindow.location.href = url;
266    },
267
268    updateDeviceStatus_: function(deviceInfo) {
269      this.changeState_(deviceInfo);
270    },
271
272    portalFrameLoadError_: function(errorCode) {
273      if (this.frameLoadIgnored_)
274        return;
275      console.log('Portal frame load error detected: ', errorCode);
276      this.frameLoadError_ = errorCode;
277    },
278
279    portalFrameLoadCompleted_: function() {
280      if (this.frameLoadIgnored_)
281        return;
282      console.log('Portal frame load completed!');
283      this.onFrameLoaded_(this.frameLoadError_ == 0);
284    },
285
286    sendPostFrame_: function(frameUrl) {
287      var msg = { type: 'postFrame' };
288      $(this.frameName_).contentWindow.postMessage(msg, frameUrl);
289    },
290
291    sendDeviceInfo_: function() {
292      var msg = {
293        type: 'deviceInfoMsg',
294        domain: document.location,
295        payload: {
296          'carrier': this.deviceInfo_.carrier,
297          'MEID': this.deviceInfo_.MEID,
298          'IMEI': this.deviceInfo_.IMEI,
299          'MDN': this.deviceInfo_.MDN
300        }
301      };
302      $(this.frameName_).contentWindow.postMessage(msg,
303          this.deviceInfo_.payment_url);
304    }
305
306  };
307
308  MobileSetup.drawProgress = function() {
309    var ctx = canvas.getContext('2d');
310    ctx.clearRect(0, 0, canvas.width, canvas.height);
311
312    var segmentCount = Math.min(12, canvas.width / 1.6); // Number of segments
313    var rotation = 0.75; // Counterclockwise rotation
314
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);
319
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
329
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;
334
335      ctx.beginPath();
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);
340      ctx.closePath();
341      ctx.fillStyle = 'rgba(240, 30, 29, ' + opacity + ')';
342      ctx.fill();
343    }
344  };
345
346  MobileSetup.deviceStateChanged = function(deviceInfo) {
347    MobileSetup.getInstance().updateDeviceStatus_(deviceInfo);
348  };
349
350  MobileSetup.portalFrameLoadError = function(errorCode) {
351    MobileSetup.getInstance().portalFrameLoadError_(errorCode);
352  };
353
354  MobileSetup.portalFrameLoadCompleted = function() {
355    MobileSetup.getInstance().portalFrameLoadCompleted_();
356  };
357
358  MobileSetup.loadPage = function() {
359    mobile.MobileSetup.getInstance().initialize('paymentForm',
360        mobile.MobileSetup.ACTIVATION_PAGE_URL);
361  };
362
363  // Export
364  return {
365    MobileSetup: MobileSetup
366  };
367});
368
369document.addEventListener('DOMContentLoaded', mobile.MobileSetup.loadPage);
370