blob: d8ccf5b9bce80d8e42dea4c4b4602eafcae2c807 [file] [log] [blame]
// Copyright (c) 2012 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.
var localStrings = new LocalStrings();
cr.define('diag', function() {
/**
* Encapsulated handling of the diagnostics page.
*/
function DiagPage() {}
cr.addSingletonGetter(DiagPage);
/*
* Remove all children nodes for an element.
* @param {element} parent of the elements to be removed.
*/
function removeChildren(element) {
element.textContent = '';
}
/**
* List of network adapter types.
*/
DiagPage.AdapterType = [
{adapter: 'wifi', name: localStrings.getString('wifi'), kind: 'wifi'},
{adapter: 'ethernet', name: localStrings.getString('ethernet1'),
kind: 'ethernet'},
{adapter: 'ethernet2', name: localStrings.getString('ethernet2'),
kind: 'ethernet'},
{adapter: 'cellular', name: localStrings.getString('3g'), kind: '3g'},
];
/**
* List of network adapter status.
* The numeric value assigned to each status reflects how healthy the network
* adapter is.
*
* @enum {int}
*/
DiagPage.AdapterStatus = {
NOT_FOUND: 0,
DISABLED: 1,
NO_IP: 2,
VALID_IP: 3
};
/**
* List of ping test status.
* The numeric value assigned to each status reflects how much progress has
* been made for the ping test.
*
* @enum {int}
*/
DiagPage.PingTestStatus = {
NOT_STARTED: 0,
IN_PROGRESS: 1,
FAILED: 2,
SUCCEEDED: 3
};
/**
* Image elements for icons.
*/
DiagPage.FailIconElement = document.createElement('img');
DiagPage.TickIconElement = document.createElement('img');
DiagPage.FailIconElement.setAttribute('src', 'chrome://diagnostics/fail.png');
DiagPage.TickIconElement.setAttribute('src', 'chrome://diagnostics/tick.png');
DiagPage.prototype = {
/**
* Perform initial setup.
*/
initialize: function() {
// Reset the diag page state.
this.reset_();
// Register event handlers.
$('connectivity-refresh').addEventListener('click', function() {
if (!this.getNetifStatusInProgress_)
this.reset_();
}.bind(this));
},
/**
* Resets the diag page state.
*/
reset_: function() {
// Initialize member variables.
this.activeAdapter_ = -1;
this.adapterStatus_ = new Array();
if (!this.pingTestStatus_ ||
this.pingTestStatus_ != DiagPage.PingTestStatus.IN_PROGRESS) {
this.pingTestStatus_ = DiagPage.PingTestStatus.NOT_STARTED;
}
// Initialize the UI with "loading" message.
$('loading').hidden = false;
$('choose-adapter').hidden = true;
removeChildren($('adapter-selection'));
removeChildren($('connectivity-status'));
// Call into Chrome to get network interfaces status.
chrome.send('getNetworkInterfaces');
this.getNetifStatusInProgress_ = true;
},
/**
* Updates the connectivity status with the device information.
* @param {Object} deviceStatus Dictionary of network adapter status.
*/
setDeviceStatus: function(deviceStatus) {
// Hide the "loading" message and show the "choose-adapter" message.
$('loading').hidden = true;
$('choose-adapter').hidden = false;
// Reset all adapters status.
var adapterLookup = {};
for (var i = 0; i < DiagPage.AdapterType.length; i++) {
this.adapterStatus_[i] = DiagPage.AdapterStatus.NOT_FOUND;
adapterLookup[DiagPage.AdapterType[i].adapter] = i;
}
// Update adapter status from data.
var foundValidIp = false;
for (var devicePath in deviceStatus) {
var device = deviceStatus[devicePath];
var type = device['Type'];
var idx = adapterLookup[type];
if (idx == null) {
console.warning('Unexpected adapter type: ' + type);
continue;
}
// Special case for multiple ethernet adapters.
if (type == 'ethernet' &&
this.adapterStatus_[idx] != DiagPage.AdapterStatus.NOT_FOUND) {
type = 'ethernet2';
idx = adapterLookup[type];
}
this.adapterStatus_[idx] = device['Powered'] == true ?
DiagPage.AdapterStatus.NO_IP : DiagPage.AdapterStatus.DISABLED;
var ipconfigs = device['ipconfigs'];
for (var ipconfigPath in ipconfigs) {
var ipconfig = ipconfigs[ipconfigPath];
if (ipconfig['Address']) {
this.adapterStatus_[idx] = DiagPage.AdapterStatus.VALID_IP;
foundValidIp = true;
}
}
}
// If we have valid IP, start ping test.
if (foundValidIp &&
this.pingTestStatus_ == DiagPage.PingTestStatus.NOT_STARTED) {
this.pingTestStatus_ == DiagPage.PingTestStatus.IN_PROGRESS;
chrome.send('testICMP', [String('8.8.8.8')]);
}
// Update UI
this.updateAdapterSelection_();
this.updateConnectivityStatus_();
// Clear the getNetifStatusInProgress flag.
this.getNetifStatusInProgress_ = false;
},
/**
* Updates the ICMP connectivity status.
* @param {Object} testICMPStatus Dictionary of ICMP connectivity status.
*/
setTestICMPStatus_: function(testICMPStatus) {
// Update the ping test state.
for (var prop in testICMPStatus) {
var status = testICMPStatus[prop];
if (status.sent && status.recvd && status.sent == status.recvd)
this.pingTestStatus_ = DiagPage.PingTestStatus.SUCCEEDED;
else
this.pingTestStatus_ = DiagPage.PingTestStatus.FAILED;
break;
}
// Update UI
this.updateConnectivityStatus_();
},
/**
* Gets the HTML radio input element id for a network adapter.
* @private
*/
getAdapterElementId_: function(adapter) {
return 'adapter-' + DiagPage.AdapterType[adapter].adapter;
},
/**
* Gets the most active adapter based on their status.
* @private
*/
getActiveAdapter_: function() {
var activeAdapter = -1;
var activeAdapterStatus = DiagPage.AdapterStatus.NOT_FOUND;
for (var i = 0; i < DiagPage.AdapterType.length; i++) {
var status = this.adapterStatus_[i];
if (status == DiagPage.AdapterStatus.NOT_FOUND)
continue;
if (activeAdapter == -1 || status > activeAdapterStatus) {
activeAdapter = i;
activeAdapterStatus = status;
}
}
return activeAdapter;
},
/**
* Update the adapter selection section.
* @private
*/
updateAdapterSelection_: function() {
// Determine active adapter.
if (this.activeAdapter_ == -1)
this.activeAdapter_ = this.getActiveAdapter_();
// Clear adapter selection section.
var adapterSelectionElement = $('adapter-selection');
removeChildren(adapterSelectionElement);
// Create HTML radio input elements.
for (var i = 0; i < DiagPage.AdapterType.length; i++) {
if (this.adapterStatus_[i] == DiagPage.AdapterStatus.NOT_FOUND)
continue;
var radioElement = document.createElement('input');
var elementId = this.getAdapterElementId_(i);
radioElement.setAttribute('type', 'radio');
radioElement.setAttribute('name', 'adapter');
radioElement.setAttribute('id', elementId);
if (i == this.activeAdapter_)
radioElement.setAttribute('checked', 'true');
radioElement.onclick = function(adapter) {
this.activeAdapter_ = adapter;
this.updateConnectivityStatus_();
}.bind(this, i);
var labelElement = document.createElement('label');
labelElement.setAttribute('for', elementId);
labelElement.appendChild(radioElement);
labelElement.appendChild(
document.createTextNode(DiagPage.AdapterType[i].name));
adapterSelectionElement.appendChild(labelElement);
adapterSelectionElement.appendChild(document.createElement('br'));
}
},
/**
* Update the connectivity status for the specified network interface.
* @private
*/
updateConnectivityStatus_: function() {
var adapter = this.activeAdapter_;
var status = this.adapterStatus_[adapter];
var name = DiagPage.AdapterType[adapter].name;
var kind = DiagPage.AdapterType[adapter].kind;
// Status messages for individual tests.
var connectivityStatusElement = $('connectivity-status');
var testStatusElements = new Array();
removeChildren(connectivityStatusElement);
for (var i = 0; i < 3; i++) {
testStatusElements[i] = document.createElement('div');
connectivityStatusElement.appendChild(testStatusElements[i]);
}
testStatusElements[0].innerHTML =
localStrings.getStringF('testing-hardware', name);
testStatusElements[1].innerHTML =
localStrings.getString('testing-connection-to-router');
testStatusElements[2].innerHTML =
localStrings.getString('testing-connection-to-internet');
// Error and recommendation messages may be inserted in test status
// elements.
var errorElement = document.createElement('div');
var recommendationElement = document.createElement('div');
errorElement.className = 'test-error';
recommendationElement.className = 'recommendation';
testStatusElements[0].className = 'test-performed';
if (status == DiagPage.AdapterStatus.DISABLED) {
errorElement.appendChild(DiagPage.FailIconElement.cloneNode());
errorElement.appendChild(document.createTextNode(
localStrings.getStringF('adapter-disabled', name)));
recommendationElement.innerHTML =
localStrings.getStringF('enable-adapter', name);
connectivityStatusElement.insertBefore(errorElement,
testStatusElements[1]);
connectivityStatusElement.insertBefore(recommendationElement,
testStatusElements[1]);
testStatusElements[1].className = 'test-pending';
testStatusElements[2].className = 'test-pending';
} else {
testStatusElements[0].appendChild(DiagPage.TickIconElement.cloneNode());
testStatusElements[1].className = 'test-performed';
if (status == DiagPage.AdapterStatus.NO_IP) {
errorElement.appendChild(DiagPage.FailIconElement.cloneNode());
errorElement.appendChild(document.createTextNode(
localStrings.getStringF('adapter-no-ip', name)));
recommendationElement.innerHTML =
localStrings.getStringF('fix-no-ip-' + kind);
connectivityStatusElement.insertBefore(errorElement,
testStatusElements[2]);
connectivityStatusElement.insertBefore(recommendationElement,
testStatusElements[2]);
testStatusElements[2].className = 'test-pending';
} else {
testStatusElements[1].appendChild(
DiagPage.TickIconElement.cloneNode());
testStatusElements[2].className = 'test-performed';
if (this.pingTestStatus_ == DiagPage.PingTestStatus.NOT_STARTED ||
this.pingTestStatus_ == DiagPage.PingTestStatus.IN_PROGRESS) {
// TODO(hshi): make the ellipsis below i18n-friendly.
testStatusElements[2].innerHTML += '...';
} else {
if (this.pingTestStatus_ == DiagPage.PingTestStatus.FAILED) {
errorElement.appendChild(DiagPage.FailIconElement.cloneNode());
errorElement.appendChild(document.createTextNode(
localStrings.getString('gateway-not-connected-to-internet')));
recommendationElement.innerHTML =
localStrings.getStringF('fix-gateway-connection');
connectivityStatusElement.appendChild(errorElement);
connectivityStatusElement.appendChild(recommendationElement);
} else {
testStatusElements[2].appendChild(
DiagPage.TickIconElement.cloneNode());
}
}
}
}
}
};
DiagPage.setDeviceStatus = function(deviceStatus) {
DiagPage.getInstance().setDeviceStatus(deviceStatus);
}
DiagPage.setTestICMPStatus = function(testICMPStatus) {
DiagPage.getInstance().setTestICMPStatus_(testICMPStatus);
}
// Export
return {
DiagPage: DiagPage
};
});
/**
* Initialize the DiagPage upon DOM content loaded.
*/
document.addEventListener('DOMContentLoaded', function() {
diag.DiagPage.getInstance().initialize();
});