Merge lp:~mandel/ubuntuone-client/notification-center-support into lp:ubuntuone-client

Proposed by Manuel de la Peña on 2012-08-31
Status: Rejected
Rejected by: dobey on 2013-08-02
Proposed branch: lp:~mandel/ubuntuone-client/notification-center-support
Merge into: lp:ubuntuone-client
Diff against target: 351 lines (+309/-0)
6 files modified
tests/platform/notification/test_darwin.py (+150/-0)
ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_client.py (+1/-0)
ubuntuone/platform/notification/__init__.py (+3/-0)
ubuntuone/platform/notification/darwin/__init__.py (+53/-0)
ubuntuone/platform/notification/darwin/growl.py (+53/-0)
ubuntuone/platform/notification/darwin/notification_center.py (+49/-0)
To merge this branch: bzr merge lp:~mandel/ubuntuone-client/notification-center-support
Reviewer Review Type Date Requested Status
Mike McCracken (community) Needs Fixing on 2012-08-31
dobey (community) 2012-08-31 Needs Fixing on 2012-08-31
Review via email: mp+122237@code.launchpad.net

Commit Message

- Added support for the notification center and growl (LP: #1044315).

Description of the Change

- Added support for the notification center and growl (LP: #1044315).

The following dependencies have been added which are probably no in your system:

http://pypi.python.org/pypi/pync/1.1 => notification center support
https://github.com/kfdm/gntp/ => growl support

You can test it IRL by starting sd and adding a big file to the Ubuntu One folder, you should see a notificaiton.

To post a comment you must log in.
1308. By Manuel de la Peña on 2012-08-31

Compare ints no strings.

1309. By Manuel de la Peña on 2012-08-31

Do not use growl all the time.

dobey (dobey) wrote :

+APPLICATION_NAME = 'Ubuntu One Client'

We shouldn't duplicate this string in multiple places. Also, I think this should probably just be 'Ubuntu One'.

Also, what do these 2 notifications actually look like? Can you provide screen shots of them?

review: Needs Fixing
1310. By Manuel de la Peña on 2012-08-31

Do not duplicate strings.

Manuel de la Peña (mandel) wrote :

Images of how it looks:

Growl support: http://imgur.com/QnMu6,jZwvj
Notification center support: http://imgur.com/QnMu6,jZwvj#1

The proper icon is missing because we have to discuss its locations in the fs once the app has been packaged.

dobey (dobey) wrote :

This does need to pass the icon argument on to the upstream API calls though, where applicable. And perhaps a comment stating it is ignored for pync because the API doesn't accept it as an argument.

Mike McCracken (mikemc) wrote :

A couple of issues:

- gntp won't work if growl isn't installed. It only talks to an existing growl, so we'll get tracebacks on 10.6 and 10.7 for lots of people…

- pync depends on terminal-notifier, which is a separate .app that calls NSNotification Center.
pync downloads that if it can't find it in a hard-coded spot, which is kind of awkward. we can put terminal-notifier there, but we'll have to strip out the apple-copyrighted Terminal.icns, which is in the terminal-notifier app for some reason.

We should probably look at using PyObjC, which would let us either directly call NSNotificationCenter and Growl, or (even better) just use the Growl 2.0 ObjC api via PyObjC, which lets us use one API and support growl on 10.6/7, and either growl or NC on 10.8, depending on user choice.

Also, as of 1.3 or so, Growl doesn't need to install anything to show notifications - that was an annoying issue previously.

here's the description from the Growl 2.0 API readme:

 1. Growl.app is installed, and the user has configured growl to NOT use NC
 ▪ Notifications work as before. Notification tickets are sent to the Growl.app which displays them and performs actions and displays notifications as configured by the user
 2. Growl.app is installed, and the user has configured Growl.app to use NC
 ▪ Growl.framework detects this state from within the app and notifications are sent directly to NC from the app's process. Additionally, notification tickets are sent to growl which performs any associated actions. Growl.app displays nothing.
 3. Growl.app is not installed
 ▪ Growl.framework detects this state from within the app and notifications are sent directly to NC from the app's process. Nothing else is done.

review: Needs Fixing

Unmerged revisions

1310. By Manuel de la Peña on 2012-08-31

Do not duplicate strings.

1309. By Manuel de la Peña on 2012-08-31

Do not use growl all the time.

1308. By Manuel de la Peña on 2012-08-31

Compare ints no strings.

1307. By Manuel de la Peña on 2012-08-31

Added support for growl in older versions. Added tests.

1306. By Manuel de la Peña on 2012-08-30

Do call notify.

1305. By Manuel de la Peña on 2012-08-30

Added support for the os x 10.8 notification center.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'tests/platform/notification/test_darwin.py'
2--- tests/platform/notification/test_darwin.py 1970-01-01 00:00:00 +0000
3+++ tests/platform/notification/test_darwin.py 2012-08-31 15:37:20 +0000
4@@ -0,0 +1,150 @@
5+# Copyright 2012 Canonical Ltd.
6+#
7+# This program is free software: you can redistribute it and/or modify it
8+# under the terms of the GNU General Public License version 3, as published
9+# by the Free Software Foundation.
10+#
11+# This program is distributed in the hope that it will be useful, but
12+# WITHOUT ANY WARRANTY; without even the implied warranties of
13+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14+# PURPOSE. See the GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License along
17+# with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+# In addition, as a special exception, the copyright holders give
20+# permission to link the code of portions of this program with the
21+# OpenSSL library under certain conditions as described in each
22+# individual source file, and distribute linked combinations
23+# including the two.
24+# You must obey the GNU General Public License in all respects
25+# for all of the code used other than OpenSSL. If you modify
26+# file(s) with this exception, you may extend this exception to your
27+# version of the file(s), but you are not obligated to do so. If you
28+# do not wish to do so, delete this exception statement from your
29+# version. If you delete this exception statement from all source
30+# files in the program, then also delete it here.
31+"""Test the notification modules for darwin."""
32+
33+import os
34+
35+from twisted.internet import defer
36+from twisted.trial.unittest import TestCase
37+
38+from ubuntuone.platform.notification import darwin
39+
40+
41+class CorrectImportTestCase(TestCase):
42+ """Test that the correct module is used."""
43+
44+ @defer.inlineCallbacks
45+ def setUp(self):
46+ """Set the different tests."""
47+ yield super(CorrectImportTestCase, self).setUp()
48+ self.current_version = '10.8.1'
49+
50+ def fake_mac_ver():
51+ """Return a fake version."""
52+ return [self.current_version, ('','',''), 'x86_64']
53+
54+ self.patch(darwin.platform, 'mac_ver', fake_mac_ver)
55+
56+ def test_import_notification_center(self):
57+ """Import the notification center."""
58+ self.current_version = '10.8.1'
59+ module = darwin.get_module()
60+ self.assertEqual(darwin.notification_center, module)
61+
62+
63+ def test_import_growl(self):
64+ """Import growl."""
65+ self.current_version = '10.7.2'
66+ module = darwin.get_module()
67+ self.assertEqual(darwin.growl, module)
68+
69+
70+class GrowlTestCase(TestCase):
71+ """Test the grown support."""
72+
73+ @defer.inlineCallbacks
74+ def setUp(self):
75+ """Set the tests."""
76+ yield super(GrowlTestCase, self).setUp()
77+ self.can_register = True
78+ self.called = []
79+ self.title = 'Title'
80+ self.message = 'le message'
81+
82+ def fake_register(my_self):
83+ """Fake the registration."""
84+ self.called.append('register')
85+ if not self.can_register:
86+ raise Exception('Connection refused.')
87+
88+ self.patch(darwin.growl.GrowlNotifier, 'register', fake_register)
89+
90+ def fake_notify(my_self, noteType=None, title=None, description=None,
91+ sticky=None, priority=0):
92+ """Fake a notification."""
93+ self.called.append(('notify', noteType, title, description,
94+ sticky, priority))
95+
96+ self.patch(darwin.growl.GrowlNotifier, 'notify', fake_notify)
97+
98+ def test_notify_can_register(self):
99+ """Test a notification when we can register."""
100+ self.can_register = True
101+ notification = darwin.growl.Notification()
102+ notification.send_notification(self.title, self.message)
103+ self.assertIn('register', self.called)
104+ notify_args = self.called[1]
105+ self.assertIn('New Messages', notify_args)
106+ self.assertIn(self.title, notify_args)
107+ self.assertIn(self.message, notify_args)
108+ self.assertIn(1, notify_args)
109+ self.assertIn(False, notify_args)
110+
111+ def test_notify_fail_register(self):
112+ """Test a notification when we cannot register."""
113+ self.can_register = False
114+ notification = darwin.growl.Notification()
115+ notification.send_notification(self.title, self.message)
116+ self.assertIn('register', self.called)
117+ self.assertEqual(1, len(self.called))
118+
119+
120+class NotificationCenterTestCase(TestCase):
121+ """Test the notification center implementation."""
122+
123+ @defer.inlineCallbacks
124+ def setUp(self):
125+ """Set the tests."""
126+ yield super(NotificationCenterTestCase, self).setUp()
127+ self.title = 'Title'
128+ self.message = 'le message'
129+ self.called = []
130+
131+ def fake_notify(message, title=None, group=None):
132+ """Fake the notify event."""
133+ self.called.extend(('notify', message, title, group))
134+
135+ self.patch(darwin.notification_center.Notifier, 'notify',
136+ fake_notify)
137+ self.notification = darwin.notification_center.Notification()
138+
139+ def test_append(self):
140+ """Test when we are appending messages."""
141+ self.notification.send_notification(self.title, self.message,
142+ append=True)
143+ self.assertIn(self.title, self.called)
144+ self.assertIn(self.message, self.called)
145+ self.assertIn(self.notification.application_name, self.called)
146+
147+
148+ def test_not_append(self):
149+ """Test not appending messages."""
150+ self.notification.send_notification(self.title, self.message,
151+ append=False)
152+ self.assertIn(self.title, self.called)
153+ self.assertIn(self.message, self.called)
154+ self.assertNotIn(self.notification.application_name, self.called)
155
156=== modified file 'ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_client.py'
157--- ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_client.py 2012-08-22 15:03:24 +0000
158+++ ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_client.py 2012-08-31 15:37:20 +0000
159@@ -46,6 +46,7 @@
160 ACTIONS = {
161 fsevents.IN_CREATE: IN_CREATE,
162 fsevents.IN_DELETE: IN_DELETE,
163+ fsevents.IN_ATTRIB: IN_MODIFY,
164 fsevents.IN_MODIFY: IN_MODIFY,
165 fsevents.IN_MOVED_FROM: IN_MOVED_FROM,
166 fsevents.IN_MOVED_TO: IN_MOVED_TO,
167
168=== modified file 'ubuntuone/platform/notification/__init__.py'
169--- ubuntuone/platform/notification/__init__.py 2012-05-02 13:15:46 +0000
170+++ ubuntuone/platform/notification/__init__.py 2012-08-31 15:37:20 +0000
171@@ -35,6 +35,9 @@
172 if sys.platform == "win32":
173 from ubuntuone.platform.notification import windows
174 source = windows
175+elif sys.platform == "darwin":
176+ from ubuntuone.platform.notification import darwin
177+ source = darwin
178 else:
179 from ubuntuone.platform.notification import linux
180 source = linux
181
182=== added directory 'ubuntuone/platform/notification/darwin'
183=== added file 'ubuntuone/platform/notification/darwin/__init__.py'
184--- ubuntuone/platform/notification/darwin/__init__.py 1970-01-01 00:00:00 +0000
185+++ ubuntuone/platform/notification/darwin/__init__.py 2012-08-31 15:37:20 +0000
186@@ -0,0 +1,53 @@
187+# Copyright 2012 Canonical Ltd.
188+#
189+# This program is free software: you can redistribute it and/or modify it
190+# under the terms of the GNU General Public License version 3, as published
191+# by the Free Software Foundation.
192+#
193+# This program is distributed in the hope that it will be useful, but
194+# WITHOUT ANY WARRANTY; without even the implied warranties of
195+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
196+# PURPOSE. See the GNU General Public License for more details.
197+#
198+# You should have received a copy of the GNU General Public License along
199+# with this program. If not, see <http://www.gnu.org/licenses/>.
200+#
201+# In addition, as a special exception, the copyright holders give
202+# permission to link the code of portions of this program with the
203+# OpenSSL library under certain conditions as described in each
204+# individual source file, and distribute linked combinations
205+# including the two.
206+# You must obey the GNU General Public License in all respects
207+# for all of the code used other than OpenSSL. If you modify
208+# file(s) with this exception, you may extend this exception to your
209+# version of the file(s), but you are not obligated to do so. If you
210+# do not wish to do so, delete this exception statement from your
211+# version. If you delete this exception statement from all source
212+# files in the program, then also delete it here.
213+"""Notification support for darwin."""
214+
215+import platform
216+
217+MAC_OS_X = 10
218+MOUNTAIN_LION = 8
219+
220+
221+def get_module():
222+ """Return the module to be used."""
223+
224+ # get the current mac version and decide if we use the notification or we
225+ # don't
226+ version = platform.mac_ver()[0].split('.')
227+
228+ if int(version[0]) >= MAC_OS_X and int(version[1]) >= MOUNTAIN_LION:
229+ from ubuntuone.platform.notification.darwin import notification_center
230+ return notification_center
231+ else:
232+ from ubuntuone.platform.notification.darwin import growl
233+ return growl
234+
235+
236+source = get_module()
237+APPLICATION_NAME = source.APPLICATION_NAME
238+
239+Notification = source.Notification
240
241=== added file 'ubuntuone/platform/notification/darwin/growl.py'
242--- ubuntuone/platform/notification/darwin/growl.py 1970-01-01 00:00:00 +0000
243+++ ubuntuone/platform/notification/darwin/growl.py 2012-08-31 15:37:20 +0000
244@@ -0,0 +1,53 @@
245+# Copyright 2012 Canonical Ltd.
246+#
247+# This program is free software: you can redistribute it and/or modify it
248+# under the terms of the GNU General Public License version 3, as published
249+# by the Free Software Foundation.
250+#
251+# This program is distributed in the hope that it will be useful, but
252+# WITHOUT ANY WARRANTY; without even the implied warranties of
253+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
254+# PURPOSE. See the GNU General Public License for more details.
255+#
256+# You should have received a copy of the GNU General Public License along
257+# with this program. If not, see <http://www.gnu.org/licenses/>.
258+#
259+# In addition, as a special exception, the copyright holders give
260+# permission to link the code of portions of this program with the
261+# OpenSSL library under certain conditions as described in each
262+# individual source file, and distribute linked combinations
263+# including the two.
264+# You must obey the GNU General Public License in all respects
265+# for all of the code used other than OpenSSL. If you modify
266+# file(s) with this exception, you may extend this exception to your
267+# version of the file(s), but you are not obligated to do so. If you
268+# do not wish to do so, delete this exception statement from your
269+# version. If you delete this exception statement from all source
270+# files in the program, then also delete it here.
271+"""Module that implements notification of the end user."""
272+
273+from gntp.notifier import GrowlNotifier
274+
275+from ubuntuone.status.notification import AbstractNotification, APPLICATION_NAME
276+
277+
278+class Notification(AbstractNotification):
279+ """Notification of the end user."""
280+
281+ def __init__(self, application_name=APPLICATION_NAME):
282+ self.application_name = application_name
283+ self.notifier = GrowlNotifier(applicationName = self.application_name,
284+ notifications = ['New Updates','New Messages'],
285+ defaultNotifications = ['New Messages'])
286+ try:
287+ self.notifier.register()
288+ except:
289+ # we get a connection error if the user has an old version of growl
290+ # therefore we wont be able to send notifications
291+ self.notifier = None
292+
293+ def send_notification(self, title, message, icon=None, append=True):
294+ """Send a notification using the underlying library."""
295+ if self.notifier:
296+ self.notifier.notify(noteType='New Messages', title=title,
297+ description=message, sticky=False, priority=1)
298
299=== added file 'ubuntuone/platform/notification/darwin/notification_center.py'
300--- ubuntuone/platform/notification/darwin/notification_center.py 1970-01-01 00:00:00 +0000
301+++ ubuntuone/platform/notification/darwin/notification_center.py 2012-08-31 15:37:20 +0000
302@@ -0,0 +1,49 @@
303+# Copyright 2012 Canonical Ltd.
304+#
305+# This program is free software: you can redistribute it and/or modify it
306+# under the terms of the GNU General Public License version 3, as published
307+# by the Free Software Foundation.
308+#
309+# This program is distributed in the hope that it will be useful, but
310+# WITHOUT ANY WARRANTY; without even the implied warranties of
311+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
312+# PURPOSE. See the GNU General Public License for more details.
313+#
314+# You should have received a copy of the GNU General Public License along
315+# with this program. If not, see <http://www.gnu.org/licenses/>.
316+#
317+# In addition, as a special exception, the copyright holders give
318+# permission to link the code of portions of this program with the
319+# OpenSSL library under certain conditions as described in each
320+# individual source file, and distribute linked combinations
321+# including the two.
322+# You must obey the GNU General Public License in all respects
323+# for all of the code used other than OpenSSL. If you modify
324+# file(s) with this exception, you may extend this exception to your
325+# version of the file(s), but you are not obligated to do so. If you
326+# do not wish to do so, delete this exception statement from your
327+# version. If you delete this exception statement from all source
328+# files in the program, then also delete it here.
329+"""Module that implements notification of the end user."""
330+
331+import os
332+
333+from pync import Notifier
334+
335+from ubuntuone.status.notification import AbstractNotification, APPLICATION_NAME
336+
337+
338+class Notification(AbstractNotification):
339+ """Notification of the end user."""
340+
341+ def __init__(self, application_name=APPLICATION_NAME):
342+ self.application_name = application_name
343+ self.notifier = Notifier
344+
345+ def send_notification(self, title, message, icon=None, append=True):
346+ """Send a notification using the underlying library."""
347+ if append:
348+ self.notifier.notify(message, title=title,
349+ group=self.application_name)
350+ else:
351+ self.notifier.notify(message, title=title)

Subscribers

People subscribed via source and target branches