[gnome-shell] location: Provide a way to disable geolocation



commit 32a49b7846b4682364225b15bb5fa36848b23bf1
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date:   Thu Feb 13 17:50:32 2014 +0000

    location: Provide a way to disable geolocation
    
    Now that we are indicating 'geolocation in use' to user, we better also
    provide at least a way to disable geolocation. Once this is in place, we
    can provide slightly better controls rather than simply on/off switch.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=723684

 js/ui/panel.js           |    1 +
 js/ui/status/location.js |  130 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 125 insertions(+), 6 deletions(-)
---
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 62614ca..cfa6fdb 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -853,6 +853,7 @@ const AggregateMenu = new Lang.Class({
         if (this._bluetooth) {
             this.menu.addMenuItem(this._bluetooth.menu);
         }
+        this.menu.addMenuItem(this._location.menu);
         this.menu.addMenuItem(this._rfkill.menu);
         this.menu.addMenuItem(this._power.menu);
         this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
diff --git a/js/ui/status/location.js b/js/ui/status/location.js
index b14bd8a..d83aaf6 100644
--- a/js/ui/status/location.js
+++ b/js/ui/status/location.js
@@ -1,18 +1,37 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 
+const GLib = imports.gi.GLib;
 const Gio = imports.gi.Gio;
 const Lang = imports.lang;
 
+const Shell = imports.gi.Shell;
 const PanelMenu = imports.ui.panelMenu;
+const PopupMenu = imports.ui.popupMenu;
 
 var GeoclueIface = '<node> \
   <interface name="org.freedesktop.GeoClue2.Manager"> \
     <property name="InUse" type="b" access="read"/> \
+    <property name="AvailableAccuracyLevel" type="u" access="read"/> \
+    <method name="AddAgent"> \
+      <arg name="id" type="s" direction="in"/> \
+    </method> \
   </interface> \
 </node>';
 
 const GeoclueManager = Gio.DBusProxy.makeProxyWrapper(GeoclueIface);
 
+var AgentIface = '<node> \
+  <interface name="org.freedesktop.GeoClue2.Agent"> \
+    <property name="MaxAccuracyLevel" type="u" access="readwrite"/> \
+    <method name="AuthorizeApp"> \
+      <arg name="desktop_id" type="s" direction="in"/> \
+      <arg name="req_accuracy_level" type="u" direction="in"/> \
+      <arg name="authorized" type="b" direction="out"/> \
+      <arg name="allowed_accuracy_level" type="u" direction="out"/> \
+    </method> \
+  </interface> \
+</node>';
+
 const Indicator = new Lang.Class({
     Name: 'LocationIndicator',
     Extends: PanelMenu.SystemIndicator,
@@ -22,16 +41,58 @@ const Indicator = new Lang.Class({
 
         this._indicator = this._addIndicator();
         this._indicator.icon_name = 'find-location-symbolic';
-        this._sync();
+        this._syncIndicator();
+
+        this._item = new PopupMenu.PopupSubMenuMenuItem(_("Location"), true);
+        this._item.icon.icon_name = 'find-location-symbolic';
+
+        var credentials = new Gio.Credentials();
+        var uid = credentials.get_unix_user();
+        this._agent = Gio.DBusExportedObject.wrapJSObject(AgentIface, this);
+        this._agent.export(Gio.DBus.system,
+                          '/org/freedesktop/GeoClue2/Agent/' + uid);
+
+        this._item.status.text = _("On");
+        this._onoffAction = this._item.menu.addAction(_("Turn Off"), Lang.bind(this, this._onOnOffAction));
+
+        this.menu.addMenuItem(this._item);
 
         this._watchId = Gio.bus_watch_name(Gio.BusType.SYSTEM,
                                            'org.freedesktop.GeoClue2',
                                            0,
                                            Lang.bind(this, this._connectToGeoclue),
                                            Lang.bind(this, this._onGeoclueVanished));
+
+        this._connectToGeoclue();
     },
 
-    _sync: function() {
+    get MaxAccuracyLevel() {
+        return this._maxAccuracyLevel;
+    },
+
+    set MaxAccuracyLevel(value) {
+        if (this._userSetAccuracy)
+            // If user set the max accuracy level, don't let geoclue override
+            return;
+
+        this._setAccuracy (value, false);
+    },
+
+    // We (and geoclue) have currently no way to reliably identifying apps so
+    // for now, lets just authorize all apps as long as they provide a valid
+    // desktop ID. We also ensure they don't get more accuracy than global max.
+    AuthorizeApp: function(desktop_id, reqAccuracyLevel) {
+        var appSystem = Shell.AppSystem.get_default();
+        var app = appSystem.lookup_app(desktop_id + ".desktop");
+        if (app == null) {
+            return [false, 0];
+        }
+
+        var allowedAccuracyLevel = clamp(reqAccuracyLevel, 0, this._maxAccuracyLevel);
+        return [true, allowedAccuracyLevel];
+    },
+
+    _syncIndicator: function() {
         if (this._proxy == null) {
             this._indicator.visible = false;
             return;
@@ -53,21 +114,78 @@ const Indicator = new Lang.Class({
     },
 
     _onProxyReady: function (proxy, error) {
-        this._connecting = false;
         if (error != null) {
             log (error.message);
+            this._userSetAccuracy = false;
+            this._connecting = false;
             return;
         }
 
         this._proxy = proxy;
-        this._proxy.connect('g-properties-changed', Lang.bind(this, this._sync));
+        this._proxy.connect('g-properties-changed', Lang.bind(this, this._syncIndicator));
+
+        if (!this._availableAccuracyLevel) {
+            this._availableAccuracyLevel = this._proxy.AvailableAccuracyLevel;
+            this._maxAccuracyLevel = this._availableAccuracyLevel;
+        }
 
-        this._sync();
+        this._syncIndicator();
+
+        this._proxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
+    },
+
+    _onAgentRegistered: function(result, error) {
+        this._connecting = false;
+        this._notifyMaxAccuracyLevel();
+
+        if (error != null)
+            log (error.message);
     },
 
     _onGeoclueVanished: function() {
         this._proxy = null;
 
-        this._sync();
+        this._syncIndicator();
+    },
+
+    _onOnOffAction: function() {
+        if (this._maxAccuracyLevel == 0)
+            this._setAccuracy (this._availableAccuracyLevel, true);
+        else
+            this._setAccuracy (0, true);
+    },
+
+    _setAccuracy: function(maxAccuracyLevel, userSet) {
+        this._maxAccuracyLevel = maxAccuracyLevel;
+
+        if (this._maxAccuracyLevel == 0) {
+            this._item.status.text = _("Off");
+            this._onoffAction.label.text = "Turn On";
+        } else {
+            this._item.status.text = _("On");
+            this._onoffAction.label.text = "Turn Off";
+        }
+
+        if (!userSet)
+            return;
+
+        this._userSetAccuracy = true;
+        // Gotta ensure geoclue is up and we are registered as agent to it
+        // before we emit the notify for this property change.
+        if (!this._connectToGeoclue())
+            this._notifyMaxAccuracyLevel();
+    },
+
+    _notifyMaxAccuracyLevel: function() {
+        if (!this._userSetAccuracy)
+            return;
+
+        var variant = new GLib.Variant('u', this._maxAccuracyLevel);
+        this._agent.emit_property_changed ('MaxAccuracyLevel', variant);
+        this._userSetAccuracy = false;
     }
 });
+
+function clamp(value, min, max) {
+    return Math.max(min, Math.min(max, value));
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]