Skip to content

Instantly share code, notes, and snippets.

@bebef1987
Created October 21, 2013 16:02
Show Gist options
  • Save bebef1987/7086369 to your computer and use it in GitHub Desktop.
Save bebef1987/7086369 to your computer and use it in GitHub Desktop.
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
var GaiaApps = {
normalizeName: function(name) {
return name.replace(/[- ]+/g, '').toLowerCase();
},
getRunningApps: function() {
let runningApps = window.wrappedJSObject.WindowManager.getRunningApps();
// Return a simplified version of the runningApps object which can be
// JSON-serialized.
let apps = {};
for (let app in runningApps) {
let anApp = {};
for (let key in runningApps[app]) {
if (["name", "origin", "manifest"].indexOf(key) > -1) {
anApp[key] = runningApps[app][key];
}
}
apps[app] = anApp;
}
return apps;
},
getRunningAppOrigin: function(name) {
let runningApps = window.wrappedJSObject.WindowManager.getRunningApps();
let origin;
for (let property in runningApps) {
if (runningApps[property].name == name) {
origin = property;
}
}
return origin;
},
getPermission: function(appName, permissionName) {
GaiaApps.locateWithName(appName, function(app) {
console.log("Getting permission '" + permissionName + "' for " + appName);
var mozPerms = navigator.mozPermissionSettings;
var result = mozPerms.get(
permissionName, app.manifestURL, app.origin, false
);
marionetteScriptFinished(result);
});
},
setPermission: function(appName, permissionName, value) {
GaiaApps.locateWithName(appName, function(app) {
console.log("Setting permission '" + permissionName + "' for " +
appName + "to '" + value + "'");
var mozPerms = navigator.mozPermissionSettings;
mozPerms.set(
permissionName, value, app.manifestURL, app.origin, false
);
marionetteScriptFinished();
});
},
locateWithName: function(name, aCallback) {
var callback = aCallback || marionetteScriptFinished;
function sendResponse(app, appName, entryPoint) {
if (callback === marionetteScriptFinished) {
if (typeof(app) === 'object') {
var result = {
name: app.manifest.name,
origin: app.origin,
entryPoint: entryPoint || null,
normalizedName: appName
};
callback(result);
} else {
callback(false);
}
} else {
callback(app, appName, entryPoint);
}
}
let appsReq = navigator.mozApps.mgmt.getAll();
appsReq.onsuccess = function() {
let apps = appsReq.result;
let normalizedSearchName = GaiaApps.normalizeName(name);
for (let i = 0; i < apps.length; i++) {
let app = apps[i];
let origin = null;
let entryPoints = app.manifest.entry_points;
if (entryPoints) {
for (let ep in entryPoints) {
let currentEntryPoint = entryPoints[ep];
let appName = currentEntryPoint.name;
if (normalizedSearchName === GaiaApps.normalizeName(appName)) {
return sendResponse(app, appName, ep);
}
}
} else {
let appName = app.manifest.name;
if (normalizedSearchName === GaiaApps.normalizeName(appName)) {
return sendResponse(app, appName);
}
}
}
callback(false);
}
},
// Returns the number of running apps.
numRunningApps: function() {
let count = 0;
let runningApps = window.wrappedJSObject.WindowManager.getRunningApps();
for (let origin in runningApps) {
count++;
}
return count;
},
// Kills the specified app.
kill: function(aOrigin, aCallback) {
var callback = aCallback || marionetteScriptFinished;
let runningApps = window.wrappedJSObject.WindowManager.getRunningApps();
if (!runningApps.hasOwnProperty(aOrigin)) {
callback(false);
}
else {
window.addEventListener('appterminated', function gt_onAppTerminated() {
window.removeEventListener('appterminated', gt_onAppTerminated);
waitFor(
function() {
console.log("app with origin '" + aOrigin + "' has terminated");
callback(true);
},
function() {
let runningApps =
window.wrappedJSObject.WindowManager.getRunningApps();
return !runningApps.hasOwnProperty(aOrigin);
}
);
});
console.log("terminating app with origin '" + aOrigin + "'");
window.wrappedJSObject.WindowManager.kill(aOrigin);
}
},
// Kills all running apps, except the homescreen.
killAll: function() {
let originsToClose = [];
let that = this;
let runningApps = window.wrappedJSObject.WindowManager.getRunningApps();
for (let origin in runningApps) {
if (origin.indexOf('homescreen') == -1) {
originsToClose.push(origin);
}
}
if (!originsToClose.length) {
marionetteScriptFinished(true);
return;
}
originsToClose.slice(0).forEach(function(origin) {
GaiaApps.kill(origin, function() {});
});
// Even after the 'appterminated' event has been fired for an app,
// it can still exist in the apps list, so wait until 1 or fewer
// apps are running (since we don't close the homescreen app).
waitFor(
function() { marionetteScriptFinished(true); },
function() { return that.numRunningApps() <= 1; }
);
},
// Launches app with the specified name (e.g., 'Calculator'); returns the
// app frame's id if successful, false if the app can't be found, or times
// out if the app frame can't be found after launching the app.
launchWithName: function(name) {
GaiaApps.locateWithName(name, function(app, appName, entryPoint) {
if (app) {
let windowManager = window.wrappedJSObject.WindowManager;
let runningApps = windowManager.getRunningApps();
let origin = GaiaApps.getRunningAppOrigin(appName);
let sendResponse = function() {
let app = runningApps[origin];
let result = {frame: app.frame.firstChild,
src: app.iframe.src,
name: app.name,
origin: origin};
marionetteScriptFinished(result);
};
if (windowManager.getDisplayedApp() == origin) {
console.log("app with origin '" + origin + "' is already running");
sendResponse();
}
else {
window.addEventListener('apploadtime', function apploadtime() {
window.removeEventListener('apploadtime', apploadtime);
waitFor(
function() {
console.log("app with origin '" + origin + "' has launched");
sendResponse();
},
function() {
origin = GaiaApps.getRunningAppOrigin(appName);
return windowManager.getDisplayedApp() == origin;
}
);
});
console.log("launching app with name '" + appName + "'");
app.launch(entryPoint || null);
}
} else {
marionetteScriptFinished(false);
}
});
},
/**
* Returns the currently displayed app.
*/
displayedApp: function() {
let windowManager = window.wrappedJSObject.WindowManager;
let runningApps = windowManager.getRunningApps();
let origin = windowManager.getDisplayedApp();
console.log("app with origin '" + origin + "' is displayed");
let app = runningApps[origin];
let result = {frame: app.frame.firstChild,
src: app.iframe.src,
name: app.name,
origin: origin};
marionetteScriptFinished(result);
},
/**
* Uninstalls the app with the specified name.
*/
uninstallWithName: function(name) {
GaiaApps.locateWithName(name, function uninstall(app) {
navigator.mozApps.mgmt.uninstall(app);
marionetteScriptFinished(false);
});
}
};
class GaiaApps(object):
def __init__(self, marionette):
self.marionette = marionette
js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js"))
self.marionette.import_script(js)
def get_permission(self, app_name, permission_name):
return self.marionette.execute_async_script("return GaiaApps.getPermission('%s', '%s')" % (app_name, permission_name))
def set_permission(self, app_name, permission_name, value):
return self.marionette.execute_async_script("return GaiaApps.setPermission('%s', '%s', '%s')" %
(app_name, permission_name, value))
def launch(self, name, switch_to_frame=True, url=None, launch_timeout=None):
self.marionette.switch_to_frame()
result = self.marionette.execute_async_script("GaiaApps.launchWithName('%s')" % name, script_timeout=launch_timeout)
assert result, "Failed to launch app with name '%s'" % name
app = GaiaApp(frame=result.get('frame'),
src=result.get('src'),
name=result.get('name'),
origin=result.get('origin'))
if app.frame_id is None:
raise Exception("App failed to launch; there is no app frame")
if switch_to_frame:
self.switch_to_frame(app.frame_id, url)
return app
@property
def displayed_app(self):
self.marionette.switch_to_frame()
result = self.marionette.execute_async_script('return GaiaApps.displayedApp();')
return GaiaApp(frame=result.get('frame'),
src=result.get('src'),
name=result.get('name'),
origin=result.get('origin'))
def is_app_installed(self, app_name):
self.marionette.switch_to_frame()
return self.marionette.execute_async_script("GaiaApps.locateWithName('%s')" % app_name)
def uninstall(self, name):
self.marionette.switch_to_frame()
self.marionette.execute_async_script("GaiaApps.uninstallWithName('%s')" % name)
def kill(self, app):
self.marionette.switch_to_frame()
js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js"))
self.marionette.import_script(js)
result = self.marionette.execute_async_script("GaiaApps.kill('%s');" % app.origin)
assert result, "Failed to kill app with name '%s'" % app.name
def kill_all(self):
self.marionette.switch_to_frame()
js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js"))
self.marionette.import_script(js)
self.marionette.execute_async_script("GaiaApps.killAll()")
def runningApps(self):
return self.marionette.execute_script("return GaiaApps.getRunningApps()")
def switch_to_frame(self, app_frame, url=None, timeout=30):
self.marionette.switch_to_frame(app_frame)
start = time.time()
if not url:
def check(now):
return "about:blank" not in now
else:
def check(now):
return url in now
while (time.time() - start < timeout):
if check(self.marionette.get_url()):
return
time.sleep(2)
raise TimeoutException('Could not switch to app frame %s in time' % app_frame)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment