Home | History | Annotate | Download | only in chromeos
      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 
      6 cr.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 
    369 document.addEventListener('DOMContentLoaded', mobile.MobileSetup.loadPage);
    370