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:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,320 @@
'use strict';
/* global ActionMenu, BaseModule, applications,
ManifestHelper, DefaultActivityHelper, LazyLoader */
(function() {
var Activities = function Activities() {
this.actionMenu = null;
};
Activities.EVENTS = [
'mozChromeEvent',
'appopened',
'lockscreen-appopened',
'home',
'applicationinstall'
];
/**
* Handles relaying of information for web activities.
* Contains code to display the list of valid activities,
* and fires an event off when the user selects one.
* @class Activities
*/
BaseModule.create(Activities, {
/** @lends Activities */
name: 'Activities',
_start: function() {
return LazyLoader.load([
'shared/js/default_activity_helper.js',
'shared/js/settings_helper.js'
]);
},
/**
* Remove all event listeners. This is mainly used in unit tests.
*/
destroy: function() {
window.removeEventListener('mozChromeEvent', this);
window.removeEventListener('appopened', this);
window.removeEventListener('lockscreen-appopened', this);
window.removeEventListener('applicationinstall', this);
},
/**
* General event handler interface.
* Updates the overlay with as we receive load events.
* @memberof Activities.prototype
* @param {DOMEvent} evt The event.
*/
handleEvent: function(evt) {
switch (evt.type) {
case 'mozChromeEvent':
var detail = evt.detail;
switch (detail.type) {
case 'activity-choice':
this.chooseActivity(detail);
break;
}
break;
case 'home':
case 'lockscreen-appopened':
if (this._detail) {
this.cancel();
}
break;
case 'appopened':
if (this.actionMenu) {
this.actionMenu.hide();
}
break;
case 'applicationinstall':
this._onNewAppInstalled(evt.detail.application);
break;
}
},
_onNewAppInstalled: function(app) {
var activities = app && app.manifest && app.manifest.activities;
if (!activities) {
return;
}
Object.keys(activities).forEach(function(activity) {
var filters = activities[activity].filters;
// Type can be single value, array, or a definition object (with value)
var type = filters && filters.type && filters.type.value ||
filters && filters.type;
if (!type) {
return;
}
if (typeof type === 'string') {
// single value, change to Array
type = type.split(',');
}
// Now that it's an array, we check all the elements
type.forEach((diff) => {
DefaultActivityHelper.getDefaultAction(activity, diff)
.then((defApp) => {
// If default launch app is set for the type
if (defApp) {
// Delete the current default app
DefaultActivityHelper.setDefaultAction(activity, diff, null);
}
});
});
});
},
/**
* This gets the index from the defaultChoice in the choices
* list.
* @param {Object} defaultChoice The default choice
* @return {Integer} The index where the default
* choice is located. -1 if it
* is not found
*/
_choiceFromDefaultAction: function(defaultChoiceManifest, detail) {
var index = -1;
if (defaultChoiceManifest) {
index = detail.choices.findIndex(function(choice) {
return choice.manifest.indexOf(defaultChoiceManifest) !== -1;
});
}
return index;
},
/**
* Displays the activity menu if needed.
* If there is only one option, the activity is automatically launched.
* @memberof Activities.prototype
* @param {Object} detail The activity choose event detail.
*/
chooseActivity: function(detail) {
var name = detail && detail.name;
var type = detail && detail.activityType;
this._detail = detail;
this.publish('activityrequesting');
DefaultActivityHelper.getDefaultAction(name, type).then(
this._gotDefaultAction.bind(this));
},
_gotDefaultAction: function(defaultChoice) {
var choices = this._detail.choices;
var index = this._choiceFromDefaultAction(defaultChoice, this._detail);
if (index > -1) {
this.choose(index);
} else if (choices.length === 1) {
this.choose('0');
} else {
//
// Our OMA Forward Lock DRM implementation relies on a "view"
// activity to invoke the "fl" app when the user clicks on a
// link to content with a mime type of
// "application/vnd.oma.dd+xml" or "application/vnd.oma.drm.message".
//
// In order for this to be secure, we need to ensure that the
// FL app is the only one that can respond to view activity
// requests for those particular mime types. Here in the System app
// we don't know what the type associated with an activity request is
// but we do know the name of the activity. So if this is an activity
// choice for a "view" activity, and the FL app is one of the choices
// then we must select the FL app without allowing the user to choose
// any of the others.
//
// If we wanted to be more general here we could perhaps
// modify this code to allow any certified app to handle the
// activity, but it is much simpler to restrict to the FL app
// only.
//
if (this._detail.name === 'view') {
var flAppIndex = choices.findIndex(function(choice) {
var matchingRegex =
/^(http|https|app)\:\/\/fl\.gaiamobile\.org\//;
return matchingRegex.test(choice.manifest);
});
if (flAppIndex !== -1) {
this.choose(flAppIndex.toString(10)); // choose() requires a string
return;
}
}
// Since the mozChromeEvent could be triggered by a 'click', and gecko
// event are synchronous make sure to exit the event loop before
// showing the list.
setTimeout((function nextTick() {
// Bug 852785: force the keyboard to close before the activity menu
// shows
window.dispatchEvent(new CustomEvent('activitymenuwillopen'));
var name = this._detail.name;
var type = this._detail.activityType;
var config = DefaultActivityHelper.getDefaultConfig(name, type);
var titleId;
if (config) {
titleId = config.l10nId;
} else {
titleId = 'activity-' + this._detail.name;
}
var askForDefault = config !== undefined;
var items = this._listItems(choices);
if (!this.actionMenu) {
var controller = {
successCb: this.choose.bind(this),
cancelCb: this.cancel.bind(this)
};
LazyLoader.load('js/action_menu.js', function() {
this.actionMenu = new ActionMenu(controller);
this.actionMenu.show(items, titleId, askForDefault);
}.bind(this));
} else if (!this.actionMenu.active) {
this.actionMenu.show(items, titleId, askForDefault);
}
}).bind(this));
}
},
/**
* The user chooses an activity from the activity menu.
* @memberof Activities.prototype
* @param {Number} choice The activity choice.
* @param {Boolean} setAsDefault Should this be set as the default activity.
*/
choose: function(choice, setAsDefault) {
if (this.actionMenu) {
this.actionMenu.hide();
}
var returnedChoice = {
id: this._detail.id,
type: 'activity-choice',
value: choice,
setAsDefault: setAsDefault
};
var name = this._detail.name;
var type = this._detail.activityType;
if (setAsDefault) {
DefaultActivityHelper.setDefaultAction(name, type,
this._detail.choices[choice].manifest);
}
this.publish('activitychoosen');
this._sendEvent(returnedChoice);
delete this._detail;
},
/**
* Cancels from the activity menu.
* @memberof Activities.prototype
*/
cancel: function() {
if (this.actionMenu) {
this.actionMenu.hide();
}
var returnedChoice = {
id: this._detail.id,
type: 'activity-choice',
value: -1
};
this._sendEvent(returnedChoice);
this.publish('activitycanceled');
delete this._detail;
},
/**
* Sends an event to the platform when a user makes a choice
* or cancels the activity menu.
* @memberof Activities.prototype
* @param {Number} value The index of the selected activity.
*/
_sendEvent: function(value) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('mozContentEvent', true, true, value);
window.dispatchEvent(event);
},
/**
* Formats and returns a list of activity choices.
* @memberof Activities.prototype
* @param {Array} choices The list of activity choices.
* @return {Array}
*/
_listItems: function(choices) {
var items = [];
choices.forEach(function(choice, index) {
var app = applications.getByManifestURL(choice.manifest);
if (!app) {
return;
}
items.push({
label: new ManifestHelper(app.manifest).name,
icon: choice.icon,
manifest: choice.manifest,
value: index
});
});
return items;
}
});
}());