Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
175
gaia/tv_apps/device-deck/js/bluetooth_cod_mapper.js
Executable file
175
gaia/tv_apps/device-deck/js/bluetooth_cod_mapper.js
Executable file
|
|
@ -0,0 +1,175 @@
|
|||
(function(exports) {
|
||||
'use strict';
|
||||
|
||||
// XXX: this module is copied and modified from
|
||||
// apps/settings/js/modules/bluetooth/bluetooth_cod_mapper.js
|
||||
// because it is not exposed as shared library and is in AMD style.
|
||||
// We might need to consolidate them in the future.
|
||||
var MinorDeviceClasses = {
|
||||
Computer: {
|
||||
0: 'computer', // Uncategorized, code for device not assigned
|
||||
1: 'computer', // Desktop workstation
|
||||
2: 'computer', // Server-class computer
|
||||
3: 'computer', // Laptop
|
||||
4: 'pda', // Handheld PC/PDA (clamshell)
|
||||
5: 'pda', // Palm-size PC/PDA
|
||||
6: 'computer', // Wearable computer (watch size)
|
||||
7: 'computer', // Tablet
|
||||
reserved: 'computer' // All other values reserved. Default type
|
||||
// 'computer' given for reserved case.
|
||||
},
|
||||
|
||||
Phone: {
|
||||
0: 'phone', // Uncategorized, code for device not assigned
|
||||
1: 'phone', // Cellular
|
||||
2: 'phone', // Cordless
|
||||
3: 'phone', // Smartphone
|
||||
4: 'modem', // Wired modem or voice gateway
|
||||
5: 'phone', // Common ISDN access
|
||||
reserved: 'phone' // All other values reserved. Default type
|
||||
// 'phone' given for reserved case.
|
||||
},
|
||||
|
||||
AudioVideo: {
|
||||
0: 'audio-card', // Uncategorized, code not assigned
|
||||
1: 'audio-card', // Wearable Headset Device
|
||||
2: 'audio-card', // Hands-free Device
|
||||
4: 'audio-input-microphone', // Microphone
|
||||
5: 'audio-card', // Loudspeaker
|
||||
6: 'audio-card', // Headphones
|
||||
7: 'audio-card', // Portable Audio
|
||||
8: 'audio-card', // Car audio
|
||||
9: 'audio-card', // Set-top box
|
||||
10: 'audio-card', // HiFi Audio Device
|
||||
11: 'camera-video', // VCR
|
||||
12: 'camera-video', // Video Camera
|
||||
13: 'camera-video', // Camcorder
|
||||
14: 'video-display', // Video Monitor
|
||||
15: 'video-display', // Video Display and Loudspeaker
|
||||
16: 'video-display', // Video Conferencing
|
||||
18: 'audio-card', // Gameing/Toy
|
||||
reserved: 'audio-card' // All other values reserved. Default type
|
||||
// 'audio-card' given for reserved case.
|
||||
},
|
||||
|
||||
Peripheral: {
|
||||
1: 'input-gaming', // Joystick
|
||||
2: 'input-gaming', // Gamepad
|
||||
16: 'input-keyboard', // Keyboard
|
||||
17: 'input-keyboard', // Keyboard
|
||||
18: 'input-keyboard', // Keyboard
|
||||
19: 'input-keyboard', // Keyboard
|
||||
20: 'input-keyboard', // Keyboard
|
||||
21: 'input-keyboard', // Keyboard
|
||||
22: 'input-keyboard', // Keyboard
|
||||
23: 'input-keyboard', // Keyboard
|
||||
24: 'input-keyboard', // Keyboard
|
||||
25: 'input-keyboard', // Keyboard
|
||||
26: 'input-keyboard', // Keyboard
|
||||
27: 'input-keyboard', // Keyboard
|
||||
28: 'input-keyboard', // Keyboard
|
||||
29: 'input-keyboard', // Keyboard
|
||||
30: 'input-keyboard', // Keyboard
|
||||
31: 'input-keyboard', // Keyboard
|
||||
32: 'input-mouse', // Pointing device
|
||||
33: 'input-mouse', // Pointing device
|
||||
34: 'input-mouse', // Pointing device
|
||||
35: 'input-mouse', // Pointing device
|
||||
36: 'input-mouse', // Pointing device
|
||||
37: 'input-tablet', // Digitizer tablet
|
||||
38: 'input-mouse', // Pointing device
|
||||
39: 'input-mouse', // Pointing device
|
||||
40: 'input-mouse', // Pointing device
|
||||
41: 'input-mouse', // Pointing device
|
||||
42: 'input-mouse', // Pointing device
|
||||
43: 'input-mouse', // Pointing device
|
||||
44: 'input-mouse', // Pointing device
|
||||
45: 'input-mouse', // Pointing device
|
||||
46: 'input-mouse', // Pointing device
|
||||
47: 'input-mouse' // Pointing device
|
||||
},
|
||||
|
||||
Imaging: {
|
||||
4: 'video-display', // Display, bit: XXX1XX
|
||||
8: 'camera-photo', // Camera, bit: XX1XXX
|
||||
16: 'scanner', // Scanner, bit: X1XXXX
|
||||
32: 'printer' // Printer, bit: 1XXXXX
|
||||
}
|
||||
};
|
||||
|
||||
var MajorDeviceClasses = {
|
||||
1: MinorDeviceClasses.Computer,
|
||||
2: MinorDeviceClasses.Phone,
|
||||
3: 'network-wireless', // LAN/Network Access Point Major Class
|
||||
4: MinorDeviceClasses.AudioVideo,
|
||||
5: MinorDeviceClasses.Peripheral,
|
||||
6: MinorDeviceClasses.Imaging
|
||||
};
|
||||
|
||||
var DeviceIconTable = {
|
||||
'computer': 'laptop',
|
||||
'pda': 'phone',
|
||||
'phone': 'phone',
|
||||
'modem': 'bluetooth', // need icon
|
||||
'audio-card': 'speaker',
|
||||
'audio-input-microphone': 'mic',
|
||||
'camera-video': 'recorder',
|
||||
'video-display': 'tv',
|
||||
'input-gaming': 'game',
|
||||
'input-keyboard': 'keyboard',
|
||||
'input-mouse': 'mouse',
|
||||
'input-tablet': 'bluetooth', // need icon
|
||||
'camera-photo': 'bluetooth', // need icon
|
||||
'scanner': 'bluetooth', // need icon
|
||||
'printer': 'bluetooth' // need icon
|
||||
};
|
||||
|
||||
exports.BluetoothCodMapper = {
|
||||
getDeviceType: function btcodm_getDeviceType(cod) {
|
||||
// Given an empty string to be default type.
|
||||
// Then, we won't show any icon for empty type.
|
||||
var deviceType = '';
|
||||
var majorDeviceClass = MajorDeviceClasses[cod.majorDeviceClass];
|
||||
if (typeof(majorDeviceClass) === 'object') {
|
||||
// drop in other Major Class
|
||||
deviceType = majorDeviceClass[cod.minorDeviceClass] ||
|
||||
majorDeviceClass.reserved || '';
|
||||
return deviceType;
|
||||
} else if (typeof(majorDeviceClass) === 'string') {
|
||||
// drop in LAN/Network Access Point Major Class
|
||||
return majorDeviceClass;
|
||||
} else if (cod.majorServiceClass & 0x100) {
|
||||
// Not in any Major Device Class which is defined in Gaia.
|
||||
// Ex: Wearable, Toy, Health.
|
||||
|
||||
// Since there is no icon to display wearable, toy, health devices,
|
||||
// file a bug 1163479[2] to define them for specification needed.
|
||||
// But some of these devices probably service 'Audio' per Bluetooth
|
||||
// specification[1].
|
||||
// Property 'type' may be missed due to CoD of major class is TOY(0x08).
|
||||
// But we need to assign 'type' as 'audio-card' if service class
|
||||
// is 'Audio'. This is for PTS test case TC_AG_COD_BV_02_I.
|
||||
// As HFP specification defines that service class is 'Audio' can
|
||||
// be considered as HFP HF.
|
||||
// [1]: HFP_SPEC_V16.pdf: A device implementing the HF role of HFP shall
|
||||
// set the "Audio" bit in the Service Class field.
|
||||
// [2]: Bug 1163479 - [Gaia][Bluetooth] Device icon definition for
|
||||
// wearable, toy, health(Major Device Class) devices.
|
||||
// (https://bugzilla.mozilla.org/show_bug.cgi?id=1163479)
|
||||
|
||||
// Major Service Class: Audio(Speaker, Microphone, Headset service, ...)
|
||||
deviceType = 'audio-card';
|
||||
return deviceType;
|
||||
} else {
|
||||
// Not in any Class which is defined in Gaia.
|
||||
return deviceType;
|
||||
}
|
||||
},
|
||||
|
||||
getIconName: function btcodm_getIconName(cod) {
|
||||
var humanReadableCod = this.getDeviceType(cod);
|
||||
return (DeviceIconTable[humanReadableCod] ?
|
||||
DeviceIconTable[humanReadableCod] : 'bluetooth');
|
||||
}
|
||||
};
|
||||
}(window));
|
||||
38
gaia/tv_apps/device-deck/js/bluetooth_loader.js
Executable file
38
gaia/tv_apps/device-deck/js/bluetooth_loader.js
Executable file
|
|
@ -0,0 +1,38 @@
|
|||
(function (exports) {
|
||||
'use strict';
|
||||
exports.BluetoothLoader = {
|
||||
// on b2g-desktop, we don't have mozBluetooth API, so we inject fake one
|
||||
// just to make sure we won't break TV build on b2g-desktop
|
||||
_fakeMozBluetooth: {
|
||||
addEventListener: function() {},
|
||||
defaultAdapter: {
|
||||
_discoveryHandle: {
|
||||
addEventListener: function() {}
|
||||
},
|
||||
|
||||
state: 'disabled',
|
||||
enable: function() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
disable: function() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
startDiscovery: function() {
|
||||
return Promise.resolve(this._discoveryHandle);
|
||||
},
|
||||
stopDiscovery: function() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getMozBluetooth: function() {
|
||||
if (navigator.mozBluetooth) {
|
||||
return navigator.mozBluetooth;
|
||||
} else {
|
||||
return this._fakeMozBluetooth;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}(window));
|
||||
97
gaia/tv_apps/device-deck/js/bluetooth_manager.js
Executable file
97
gaia/tv_apps/device-deck/js/bluetooth_manager.js
Executable file
|
|
@ -0,0 +1,97 @@
|
|||
/* globals evt, BluetoothLoader */
|
||||
(function(exports) {
|
||||
'use strict';
|
||||
|
||||
var BluetoothManager = function() {};
|
||||
|
||||
BluetoothManager.prototype = evt({
|
||||
_mozBluetooth: undefined,
|
||||
|
||||
_defaultAdapter: undefined,
|
||||
|
||||
_discoveryHandle: undefined,
|
||||
|
||||
_handleDeviceFound: undefined,
|
||||
|
||||
_handleBeforeUnload: undefined,
|
||||
|
||||
_deviceDeck: undefined,
|
||||
|
||||
init: function bm_init() {
|
||||
this._mozBluetooth = BluetoothLoader.getMozBluetooth();
|
||||
|
||||
this._handleDeviceFound = this.onDeviceFound.bind(this);
|
||||
|
||||
this._mozBluetooth.addEventListener('attributechanged',
|
||||
this.onAttributeChanged.bind(this));
|
||||
|
||||
this._defaultAdapter = this._mozBluetooth.defaultAdapter;
|
||||
},
|
||||
|
||||
onAttributeChanged: function bm_onAttributeChanged(evt) {
|
||||
var that = this;
|
||||
[].forEach.call(evt.attrs, function(attr, index) {
|
||||
if (attr === 'defaultAdapter') {
|
||||
that._defaultAdapter = that._mozBluetooth.defaultAdapter;
|
||||
that.fire('default-adapter-ready');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_keepDiscoveryHandle: function bm_keepDiscoveryHandle(handle) {
|
||||
this._discoveryHandle = handle;
|
||||
this._discoveryHandle.addEventListener('devicefound',
|
||||
this._handleDeviceFound);
|
||||
},
|
||||
|
||||
_startDiscovery: function bm_startDiscovery() {
|
||||
var that = this;
|
||||
if (!this._defaultAdapter) {
|
||||
return Promise.reject('default adapter doesn\'t exist');
|
||||
}
|
||||
|
||||
if (this._defaultAdapter.state !== 'enabled') {
|
||||
return this._defaultAdapter.enable().then(function() {
|
||||
return that._defaultAdapter.startDiscovery();
|
||||
}).then(this._keepDiscoveryHandle.bind(this));
|
||||
}
|
||||
|
||||
return this._defaultAdapter.startDiscovery().then(
|
||||
this._keepDiscoveryHandle.bind(this));
|
||||
},
|
||||
|
||||
_stopDiscovery: function bm_stopDiscovery() {
|
||||
if (!this._defaultAdapter) {
|
||||
return Promise.reject('default adapter doesn\'t exist');
|
||||
}
|
||||
|
||||
// force to stop anyway
|
||||
return this._defaultAdapter.stopDiscovery();
|
||||
},
|
||||
|
||||
safelyStartDiscovery: function bm_safelyStartDiscovery() {
|
||||
var that = this;
|
||||
if (!this._defaultAdapter) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
that.on('default-adapter-ready', function() {
|
||||
resolve(that._startDiscovery());
|
||||
});
|
||||
});
|
||||
}
|
||||
return this._startDiscovery();
|
||||
},
|
||||
|
||||
safelyStopDiscovery: function bn_safelyStopDiscovery() {
|
||||
return this._stopDiscovery().catch(function(reason) {
|
||||
console.warn('failed to stop discovery: ' + reason);
|
||||
});
|
||||
},
|
||||
|
||||
onDeviceFound: function bm_onDeviceFound(evt) {
|
||||
var device = evt.device;
|
||||
this.fire('device-found', device);
|
||||
}
|
||||
});
|
||||
|
||||
exports.BluetoothManager = BluetoothManager;
|
||||
}(window));
|
||||
143
gaia/tv_apps/device-deck/js/device_deck.js
Executable file
143
gaia/tv_apps/device-deck/js/device_deck.js
Executable file
|
|
@ -0,0 +1,143 @@
|
|||
/* global SpatialNavigator, SharedUtils, KeyNavigationAdapter,
|
||||
BluetoothManager, evt, BluetoothCodMapper */
|
||||
|
||||
(function(exports) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* DeviceDeck is the controller class of device-deck.
|
||||
*
|
||||
* @class DeviceDeck
|
||||
* @requires BluetoothManager
|
||||
* @requires KeyNavigationAdapter
|
||||
* @requires SpatialNavigator
|
||||
* @requires {@link http://bit.ly/1Ld0WYX|SmartButton}
|
||||
*/
|
||||
var DeviceDeck = function() {
|
||||
};
|
||||
|
||||
DeviceDeck.prototype = evt({
|
||||
_navigableElements: [],
|
||||
|
||||
_spatialNavigator: undefined,
|
||||
|
||||
_keyNavigationAdapter: undefined,
|
||||
|
||||
connectedDevicesList:
|
||||
document.getElementById('connected-devices-list'),
|
||||
|
||||
newlyFoundDeviceList:
|
||||
document.getElementById('newly-found-devices-list'),
|
||||
|
||||
_bluetoothManager: undefined,
|
||||
|
||||
/**
|
||||
* Initialize DeviceDeck. It means:
|
||||
* 1. initialize BlutoothManager and start discovery immediately
|
||||
* 2. initialize KeyNavigationAdapter
|
||||
* 3. Find all navigable elements and initialize SpatialNavigator
|
||||
*
|
||||
* And when it receives `device-found` event from BluetoothManager, it will
|
||||
* create {@link http://bit.ly/1Ld0WYX|SmartButton} for the device.
|
||||
*
|
||||
* @public
|
||||
* @method DeviceDeck#init
|
||||
*/
|
||||
init: function() {
|
||||
this._bluetoothManager = new BluetoothManager();
|
||||
this._bluetoothManager.init();
|
||||
this._bluetoothManager.safelyStartDiscovery();
|
||||
|
||||
this._bluetoothManager.on('device-found',
|
||||
this.onBluetoothDeviceFound.bind(this));
|
||||
|
||||
this._keyNavigationAdapter = new KeyNavigationAdapter();
|
||||
this._keyNavigationAdapter.init();
|
||||
|
||||
this._navigableElements =
|
||||
SharedUtils.nodeListToArray(
|
||||
document.querySelectorAll('.navigable:not(.app-banner)'));
|
||||
|
||||
this._spatialNavigator = new SpatialNavigator(this._navigableElements);
|
||||
this._spatialNavigator.on('focus', this.onFocus.bind(this));
|
||||
|
||||
this._keyNavigationAdapter.on('move', this.onMove.bind(this));
|
||||
this._keyNavigationAdapter.on('enter-keyup', this.onEnter.bind(this));
|
||||
|
||||
this._spatialNavigator.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* refresh list of devices in div#connected-devices-list and
|
||||
* div#newly-found-devices-list
|
||||
*
|
||||
* @public
|
||||
* @method DeviceDeck#refreshDevices
|
||||
*/
|
||||
refreshDevices: function() {
|
||||
var that = this;
|
||||
this._bluetoothManager.safelyStopDiscovery().then(function() {
|
||||
[].forEach.call(that.connectedDevicesList.children, function(elem) {
|
||||
elem.remove();
|
||||
});
|
||||
[].forEach.call(that.newlyFoundDeviceList.children, function(elem) {
|
||||
elem.remove();
|
||||
});
|
||||
}).then(function() {
|
||||
that._bluetoothManager.safelyStartDiscovery();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Create {@link http://bit.ly/1Ld0WYX|SmartButton} for each device found
|
||||
* and append it to div#connected-devices-list or
|
||||
* div#newly-found-devices-list
|
||||
*
|
||||
* @public
|
||||
* @method DeviceDeck#onBluetoothDeviceFound
|
||||
* @param {BluetoothDevice} device - see
|
||||
* {@link http://mzl.la/1UQllr3|BluetoothDevice}
|
||||
*/
|
||||
onBluetoothDeviceFound: function(device) {
|
||||
var name = device.name || device.address;
|
||||
var paired = device.paired;
|
||||
|
||||
// TODO: we should validate whether there is duplicate button of device
|
||||
var button = document.createElement('smart-button');
|
||||
button.setAttribute('type', 'app-button');
|
||||
button.setAttribute('app-type', 'device');
|
||||
button.classList.add('navigable');
|
||||
button.setAttribute('label', name);
|
||||
button.dataset.type = 'bluetooth';
|
||||
button.dataset.address = device.address;
|
||||
button.dataset.icon = BluetoothCodMapper.getIconName(device.cod);
|
||||
button.dataset.bluetoothDeviceType = device.type;
|
||||
|
||||
if (paired) {
|
||||
this.connectedDevicesList.appendChild(button);
|
||||
} else {
|
||||
this.newlyFoundDeviceList.appendChild(button);
|
||||
}
|
||||
this._spatialNavigator.add(button);
|
||||
},
|
||||
|
||||
onMove: function(key) {
|
||||
this._spatialNavigator.move(key);
|
||||
},
|
||||
|
||||
onEnter: function() {
|
||||
var focused = this._spatialNavigator.getFocusedElement();
|
||||
if (focused && focused.id === 'refresh-button') {
|
||||
this.refreshDevices();
|
||||
}
|
||||
},
|
||||
|
||||
onFocus: function(elem) {
|
||||
elem.focus();
|
||||
}
|
||||
});
|
||||
|
||||
exports.deviceDeck = new DeviceDeck();
|
||||
exports.deviceDeck.init();
|
||||
|
||||
} (window));
|
||||
Loading…
Reference in a new issue