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