| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| cr.define('mobile', function() { |
| |
| // TODO(tbarzic): Share code with mobile_setup.js. |
| var EXTENSION_BASE_URL = |
| 'chrome-extension://iadeocfgjdjdmpenejdbfeaocpbikmab/'; |
| var REDIRECT_POST_PAGE_URL = EXTENSION_BASE_URL + 'redirect.html?autoPost=1'; |
| var PORTAL_OFFLINE_PAGE_URL = EXTENSION_BASE_URL + 'portal_offline.html'; |
| var INVALID_DEVICE_INFO_PAGE_URL = |
| EXTENSION_BASE_URL + 'invalid_device_info.html'; |
| |
| var NetworkState = { |
| UNKNOWN: 0, |
| PORTAL_REACHABLE: 1, |
| PORTAL_UNREACHABLE: 2 |
| }; |
| |
| var CarrierPageType = { |
| NOT_SET: 0, |
| PORTAL_OFFLINE: 1, |
| INVALID_DEVICE_INFO: 2 |
| }; |
| |
| var localStrings = new LocalStrings(); |
| |
| function PortalImpl() { |
| // Mobile device information. |
| this.deviceInfo_ = null; |
| this.spinnerInt_ = -1; |
| this.networkState_ = NetworkState.UNKNOWN; |
| this.portalFrameSet_ = false; |
| this.carrierPageType_ = CarrierPageType.NOT_SET; |
| } |
| |
| cr.addSingletonGetter(PortalImpl); |
| |
| PortalImpl.prototype = { |
| initialize: function() { |
| // Get network device info for which portal should be opened. |
| // For LTE networks, this will also start observing network connection |
| // state and raise |updatePortalReachability| messages when the portal |
| // reachability changes. |
| chrome.send('getDeviceInfo'); |
| }, |
| |
| updateDeviceInfo: function(deviceInfo) { |
| this.deviceInfo_ = deviceInfo; |
| this.updateState_(); |
| }, |
| |
| updateNetworkState: function(networkState) { |
| if (this.networkState_ == networkState) |
| return; |
| this.networkState_ = networkState; |
| |
| // If the device info is not yet set, the state will be updated on the |
| // device info update. |
| if (this.deviceInfo_) |
| this.updateState_(); |
| }, |
| |
| updateState_: function() { |
| if (!this.deviceInfo_ || this.networkState_ == NetworkState.UNKNOWN) |
| return; |
| |
| if (!this.isDeviceInfoValid_()) { |
| // If the device info is not valid, hide portalFrame and show system |
| // status displaying 'invalid device info' page. |
| this.setCarrierPage_(CarrierPageType.INVALID_DEVICE_INFO); |
| $('portalFrame').hidden = true; |
| $('systemStatus').hidden = false; |
| } else if (this.networkState_ != NetworkState.PORTAL_REACHABLE) { |
| // If the portal is not reachable, hide portalFrame and show system |
| // status displaying 'offline portal' page. |
| this.setCarrierPage_(CarrierPageType.PORTAL_OFFLINE); |
| $('portalFrame').hidden = true; |
| $('systemStatus').hidden = false; |
| } else { |
| // If the portal is reachable and device info is valid, set and show |
| // portalFrame; and hide system status displaying 'offline portal' page. |
| this.setPortalFrameIfNeeded_(this.deviceInfo_); |
| $('portalFrame').hidden = false; |
| $('systemStatus').hidden = true; |
| this.stopSpinner_(); |
| } |
| }, |
| |
| setCarrierPage_: function(type) { |
| // The page is already set, nothing to do. |
| if (type == this.carrierPageType_) |
| return; |
| |
| switch (type) { |
| case CarrierPageType.PORTAL_OFFLINE: |
| $('carrierPage').contentWindow.location.href = |
| PORTAL_OFFLINE_PAGE_URL; |
| $('statusHeader').textContent = |
| localStrings.getString('portal_unreachable_header'); |
| this.startSpinner_(); |
| break; |
| case CarrierPageType.INVALID_DEVICE_INFO: |
| $('carrierPage').contentWindow.location.href = |
| INVALID_DEVICE_INFO_PAGE_URL; |
| $('statusHeader').textContent = |
| localStrings.getString('invalid_device_info_header'); |
| this.stopSpinner_(); |
| break; |
| case CarrierPageType.NOT_SET: |
| $('carrierPage').contentWindow.location.href = 'about:blank'; |
| $('statusHeader').textContent = ''; |
| this.stopSpinner_(); |
| break; |
| default: |
| break; |
| } |
| |
| this.carrierPageType_ = type; |
| }, |
| |
| setPortalFrameIfNeeded_: function(deviceInfo) { |
| // The portal should be set only once. |
| if (this.portalFrameSet_) |
| return; |
| |
| var postData = ''; |
| if (deviceInfo.post_data && deviceInfo.post_data.length) |
| postData = '&post_data=' + encodeURIComponent(deviceInfo.post_data); |
| |
| $('portalFrame').contentWindow.location.href = REDIRECT_POST_PAGE_URL + |
| postData + '&formUrl=' + encodeURIComponent(deviceInfo.payment_url); |
| |
| this.portalFrameSet_ = true; |
| }, |
| |
| isDeviceInfoValid_: function() { |
| // Device info is valid if it has mdn which doesn't contain only '0's. |
| return this.deviceInfo_ && this.deviceInfo_.MDN && |
| this.deviceInfo_.MDN.match('[^0]'); |
| }, |
| |
| startSpinner_: function() { |
| this.stopSpinner_(); |
| this.spinnerInt_ = setInterval(this.drawProgress_.bind(this), 100); |
| }, |
| |
| stopSpinner_: function() { |
| if (this.spinnerInt_ != -1) { |
| clearInterval(this.spinnerInt_); |
| this.spinnerInt_ = -1; |
| } |
| // Clear the spinner canvas. |
| var ctx = canvas.getContext('2d'); |
| ctx.clearRect(0, 0, canvas.width, canvas.height); |
| }, |
| |
| drawProgress_: function() { |
| var ctx = canvas.getContext('2d'); |
| ctx.clearRect(0, 0, canvas.width, canvas.height); |
| |
| var segmentCount = Math.min(12, canvas.width / 1.6); // Number of segments |
| var rotation = 0.75; // Counterclockwise rotation |
| |
| // Rotate canvas over time |
| ctx.translate(canvas.width / 2, canvas.height / 2); |
| ctx.rotate(Math.PI * 2 / (segmentCount + rotation)); |
| ctx.translate(-canvas.width / 2, -canvas.height / 2); |
| |
| var gap = canvas.width / 24; // Gap between segments |
| var oRadius = canvas.width / 2; // Outer radius |
| var iRadius = oRadius * 0.618; // Inner radius |
| var oCircumference = Math.PI * 2 * oRadius; // Outer circumference |
| var iCircumference = Math.PI * 2 * iRadius; // Inner circumference |
| var oGap = gap / oCircumference; // Gap size as fraction of outer ring |
| var iGap = gap / iCircumference; // Gap size as fraction of inner ring |
| var oArc = Math.PI * 2 * (1 / segmentCount - oGap); // Angle of outer arcs |
| var iArc = Math.PI * 2 * (1 / segmentCount - iGap); // Angle of inner arcs |
| |
| for (i = 0; i < segmentCount; i++) { // Draw each segment |
| var opacity = Math.pow(1.0 - i / segmentCount, 3.0); |
| opacity = (0.15 + opacity * 0.8); // Vary from 0.15 to 0.95 |
| var angle = - Math.PI * 2 * i / segmentCount; |
| |
| ctx.beginPath(); |
| ctx.arc(canvas.width / 2, canvas.height / 2, oRadius, |
| angle - oArc / 2, angle + oArc / 2, false); |
| ctx.arc(canvas.width / 2, canvas.height / 2, iRadius, |
| angle + iArc / 2, angle - iArc / 2, true); |
| ctx.closePath(); |
| ctx.fillStyle = 'rgba(240, 30, 29, ' + opacity + ')'; |
| ctx.fill(); |
| } |
| } |
| }; |
| |
| function MobileSetupPortal() {} |
| |
| MobileSetupPortal.loadPage = function() { |
| PortalImpl.getInstance().initialize(); |
| }; |
| |
| MobileSetupPortal.onGotDeviceInfo = function(deviceInfo) { |
| PortalImpl.getInstance().updateDeviceInfo(deviceInfo); |
| }; |
| |
| MobileSetupPortal.onConnectivityChanged = function(portalReachable) { |
| PortalImpl.getInstance().updateNetworkState( |
| portalReachable ? NetworkState.PORTAL_REACHABLE : |
| NetworkState.PORTAL_UNREACHABLE); |
| }; |
| |
| // Export |
| return { |
| MobileSetupPortal: MobileSetupPortal |
| }; |
| }); |
| |
| document.addEventListener('DOMContentLoaded', |
| mobile.MobileSetupPortal.loadPage); |