[gnome-shell/wip/loc-apps] tmp
- From: Zeeshan Ali Khattak <zeeshanak src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/wip/loc-apps] tmp
- Date: Thu, 11 Feb 2016 22:23:38 +0000 (UTC)
commit 11db28b216480ae13943e57d4dea62f250438d31
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date: Tue Feb 9 17:16:08 2016 +0000
tmp
js/ui/status/location.js | 281 +++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 254 insertions(+), 27 deletions(-)
---
diff --git a/js/ui/status/location.js b/js/ui/status/location.js
index 1aae47a..59cd04b 100644
--- a/js/ui/status/location.js
+++ b/js/ui/status/location.js
@@ -7,12 +7,16 @@ const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
+const ModalDialog = imports.ui.modalDialog;
const Shell = imports.gi.Shell;
+const St = imports.gi.St;
const LOCATION_SCHEMA = 'org.gnome.system.location';
const MAX_ACCURACY_LEVEL = 'max-accuracy-level';
const ENABLED = 'enabled';
-const APPS = 'applications';
+
+const APP_PERMISSIONS_TABLE = 'desktop';
+const APP_PERMISSIONS_ID = 'geolocation';
const GeoclueAccuracyLevel = {
NONE: 0,
@@ -47,6 +51,26 @@ var AgentIface = '<node> \
</interface> \
</node>';
+var XdgAppIface = '<node> \
+ <interface name="org.freedesktop.XdgApp.PermissionStore"> \
+ <method name="Lookup"> \
+ <arg name="table" type="s" direction="in"/> \
+ <arg name="id" type="s" direction="in"/> \
+ <arg name="permissions" type="a{sas}" direction="out"/> \
+ <arg name="data" type="v" direction="out"/> \
+ </method> \
+ <method name="Set"> \
+ <arg name="table" type="s" direction="in"/> \
+ <arg name="create" type="b" direction="in"/> \
+ <arg name="id" type="s" direction="in"/> \
+ <arg name="app_permissions" type="a{sas}" direction="in"/> \
+ <arg name="data" type="v" direction="in"/> \
+ </method> \
+ </interface> \
+</node>';
+
+const PermissionStore = Gio.DBusProxy.makeProxyWrapper(XdgAppIface);
+
const Indicator = new Lang.Class({
Name: 'LocationIndicator',
Extends: PanelMenu.SystemIndicator,
@@ -84,73 +108,200 @@ const Indicator = new Lang.Class({
this._onSessionUpdated();
this._onMaxAccuracyLevelChanged();
this._connectToGeoclue();
+ this._connectToPermissionStore();
},
get MaxAccuracyLevel() {
return this._getMaxAccuracyLevel();
},
- AuthorizeApp: function(desktop_id, reqAccuracyLevel) {
- let apps = this._settings.get_value(APPS);
- let nApps = apps.n_children();
+ AuthorizeAppAsync: function(params, invocation) {
+ let [desktop_id, reqAccuracyLevel] = params;
+ log("%s is requesting location".format(desktop_id));
+
+ let callback = function(level, timesAllowed) {
+ if (level >= GeoclueAccuracyLevel.NONE && timesAllowed > 2) {
+ log("%s is in store".format(desktop_id));
+ let accuracyLevel = clamp(reqAccuracyLevel, 0, level);
+ this._completeAuthorizeApp(desktop_id,
+ accuracyLevel,
+ timesAllowed,
+ invocation);
+ } else {
+ log("%s not in store".format(desktop_id));
+ this._userAuthorizeApp(desktop_id,
+ reqAccuracyLevel,
+ timesAllowed,
+ invocation);
+ }
+ }
+ this._fetchPermissionFromStore(desktop_id, Lang.bind(this, callback);
+ },
+
+ _userAuthorizeApp: function(desktopId, reqAccuracyLevel, timesAllowed, invocation) {
+ var appSystem = Shell.AppSystem.get_default();
+ var app = appSystem.lookup_app(desktopId + ".desktop");
+ if (app == null) {
+ this._completeAuthorizeApp(desktopId,
+ GeoclueAccuracyLevel.NONE,
+ timesAllowed,
+ invocation);
+ return;
+ }
+
+ var name = app.get_name();
+ var icon = app.get_app_info().get_icon();
+ var reason = app.get_string("X-Geoclue-Reason");
+ var allowCallback = function() {
+ this._completeAuthorizeApp(desktopId,
+ reqAccuracyLevel,
+ timesAllowed,
+ invocation);
+ };
+ var denyCallback = function() {
+ this._completeAuthorizeApp(desktopId,
+ GeoclueAccuracyLevel.NONE,
+ timesAllowed,
+ invocation);
+ };
+
+ this._showAppAuthDialog(name,
+ reason,
+ icon,
+ Lang.bind(this, allowCallback),
+ Lang.bind(this, denyCallback));
+ },
+
+ _showAppAuthDialog: function(name, reason, icon, allowCallback, denyCallback) {
+ if (this._dialog == null)
+ this._dialog = new GeolocationDialog(name, reason, icon);
+ else
+ this._dialog.update(name, reason, icon);
+
+ let closedId = this._dialog.connect('closed', function() {
+ this._dialog.disconnect(closedId);
+ if (this._dialog.allowed)
+ allowCallback ();
+ else
+ denyCallback ();
+ }.bind(this));
+
+ this._dialog.open(global.get_current_time ());
+ },
+
+ _completeAuthorizeApp: function(desktopId,
+ accuracyLevel,
+ timesAllowed,
+ invocation) {
+ if (accuracyLevel == GeoclueAccuracyLevel.NONE) {
+ invocation.return_value(GLib.Variant.new('(bu)',
+ [false, accuracyLevel]));
+ this._saveToPermissionStore(desktopId, accuracyLevel, 0);
+ return;
+ }
- for (let i = 0; i < nApps; i++) {
- let [app, levelStr] = apps.get_child_value(i).deep_unpack();
- if (app != desktop_id)
- continue;
+ let allowedAccuracyLevel = clamp(accuracyLevel,
+ 0,
+ this._getMaxAccuracyLevel());
+ invocation.return_value(GLib.Variant.new('(bu)',
+ [true, allowedAccuracyLevel]));
- level = GeoclueAccuracyLevel[levelStr.toUpperCase()] ||
- GeoclueAccuracyLevel.NONE;
- if (level == GeoclueAccuracyLevel.NONE)
- return [false, 0];
+ this._saveToPermissionStore(desktopId, allowedAccuracyLevel, timesAllowed + 1);
+ },
- let allowedAccuracyLevel = clamp(reqAccuracyLevel, 0, level);
- allowedAccuracyLevel = clamp(allowedAccuracyLevel, 0, this._getMaxAccuracyLevel());
+ _fetchPermissionFromStore: function(desktopId, callback) {
+ if (this._permStoreProxy == null) {
+ callback (-1, 0);
- return [true, allowedAccuracyLevel];
+ return;
}
- return [false, 0];
+ this._permStoreProxy.LookupRemote(APP_PERMISSIONS_TABLE,
+ APP_PERMISSIONS_ID,
+ function(result, error) {
+ if (error != null) {
+ log(error.message);
+ callback(-1, 0);
+
+ return;
+ }
+
+ let [permissions, data] = result;
+ let permission = permissions[desktopId];
+ if (permission == null) {
+ callback(-1, 0);
+
+ return;
+ }
+
+ let levelStr = permission[0];
+ let level = GeoclueAccuracyLevel[levelStr.toUpperCase()] ||
+ GeoclueAccuracyLevel.NONE;
+ let timesAllowed = data.get_byte();
+
+ callback(level, timesAllowed);
+ });
+ },
+
+ _saveToPermissionStore: function(desktopId,
+ allowedAccuracyLevel,
+ timesAllowed) {
+ if (timesAllowed > 2 || this._permStoreProxy == null)
+ return;
+
+ let levelStr = Object.keys(GeoclueAccuracyLevel)[allowedAccuracyLevel];
+ let permission = { desktopId: [levelStr] };
+ let permissions = GLib.Variant.new('a{sas}', [permission]));
+ let data = GLib.Variant.new('y', timesAllowed);
+
+ this._permStoreProxy.SetRemote(APP_PERMISSIONS_TABLE,
+ true,
+ APP_PERMISSIONS_ID,
+ permissions,
+ data,
+ function (result, error) {
+ log(error.message);
+ });
},
_syncIndicator: function() {
- if (this._proxy == null) {
+ if (this._managerProxy == null) {
this._indicator.visible = false;
this._item.actor.visible = false;
return;
}
- this._indicator.visible = this._proxy.InUse;
+ this._indicator.visible = this._managerProxy.InUse;
this._item.actor.visible = this._indicator.visible;
this._updateMenuLabels();
},
_connectToGeoclue: function() {
- if (this._proxy != null || this._connecting)
+ if (this._managerProxy != null || this._connecting)
return false;
this._connecting = true;
new GeoclueManager(Gio.DBus.system,
'org.freedesktop.GeoClue2',
'/org/freedesktop/GeoClue2/Manager',
- Lang.bind(this, this._onProxyReady));
+ Lang.bind(this, this._onManagerProxyReady));
return true;
},
- _onProxyReady: function(proxy, error) {
+ _onManagerProxyReady: function(proxy, error) {
if (error != null) {
log(error.message);
this._connecting = false;
return;
}
- this._proxy = proxy;
- this._propertiesChangedId = this._proxy.connect('g-properties-changed',
+ this._managerProxy = proxy;
+ this._propertiesChangedId = this._managerProxy.connect('g-properties-changed',
Lang.bind(this, this._onGeocluePropsChanged));
this._syncIndicator();
- this._proxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
+ this._managerProxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
},
_onAgentRegistered: function(result, error) {
@@ -163,10 +314,10 @@ const Indicator = new Lang.Class({
_onGeoclueVanished: function() {
if (this._propertiesChangedId) {
- this._proxy.disconnect(this._propertiesChangedId);
+ this._managerProxy.disconnect(this._propertiesChangedId);
this._propertiesChangedId = 0;
}
- this._proxy = null;
+ this._managerProxy = null;
this._syncIndicator();
},
@@ -221,9 +372,85 @@ const Indicator = new Lang.Class({
let unpacked = properties.deep_unpack();
if ("InUse" in unpacked)
this._syncIndicator();
- }
+ },
+
+ _connectToPermissionStore: function() {
+ this._permStoreProxy = null;
+ new PermissionStore(Gio.DBus.session,
+ 'org.freedesktop.XdgApp',
+ '/org/freedesktop/XdgApp/PermissionStore',
+ Lang.bind(this, this._onPermStoreProxyReady));
+ },
+
+ _onPermStoreProxyReady: function(proxy, error) {
+ if (error != null) {
+ log(error.message);
+ return;
+ }
+
+ this._permStoreProxy = proxy;
+ },
});
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
+
+const GeolocationDialog = new Lang.Class({
+ Name: 'GeolocationDialog',
+ Extends: ModalDialog.ModalDialog,
+
+ // FIXME: Would be nice to show the application icon too
+ _init: function(name, reason, icon) {
+ this.parent({ destroyOnClose: false });
+
+ let text = _("'%s' is requesting access to location data.").format (name);
+ this._label = new St.Label({ style_class: 'prompt-dialog-description',
+ text: text });
+
+ this.contentLayout.add(this._label, {});
+
+ if (reason != null) {
+ this._reasonLabel = new St.Label({ style_class: 'prompt-dialog-description',
+ text: reason });
+ this.contentLayout.add(this._reasonLabel, {});
+ } else {
+ this._reasonLabel = null;
+ }
+
+ this._allowButton = this.addButton({ label: _("Confirm"),
+ action: this._onAllowClicked.bind(this),
+ default: false },
+ { expand: true, x_fill: false, x_align: St.Align.END });
+ this._denyButton = this.addButton({ label: _("Cancel"),
+ action: this._onDisallowClicked.bind(this),
+ default: true },
+ { expand: true, x_fill: false, x_align: St.Align.START });
+ },
+
+ update: function(name, reason, icon) {
+ let text = _("'%s' is requesting access to location data.").format (name);
+ this._label.text = text;
+
+ if (this._reasonLabel != null) {
+ this.contentLayout.remove(this._reasonLabel, {});
+ this._reasonLabel = null;
+ }
+
+ if (reason != null) {
+ this._reasonLabel = new St.Label({ style_class: 'prompt-dialog-description',
+ text: reason });
+ this.contentLayout.add(this._reasonLabel, {});
+ }
+ },
+
+ _onAllowClicked: function() {
+ this.allowed = true;
+ this.close();
+ },
+
+ _onDisallowClicked: function() {
+ this.allowed = false;
+ this.close();
+ }
+});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]