Mercurial > libervia-backend
comparison sat/plugins/plugin_misc_android.py @ 2841:90115cf4e731
plugin android: improved state handling:
state handling is not using mmap anymore but an unix socket instead.
State change can now be managed.
Bridge signals are disabled when frontend is paused.
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 09 Mar 2019 16:23:01 +0100 |
parents | 003b8b4b56a7 |
children | 26d6ac4e4a66 |
comparison
equal
deleted
inserted
replaced
2840:0f277708e2ae | 2841:90115cf4e731 |
---|---|
15 # GNU Affero General Public License for more details. | 15 # GNU Affero General Public License for more details. |
16 | 16 |
17 # You should have received a copy of the GNU Affero General Public License | 17 # You should have received a copy of the GNU Affero General Public License |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 import sys | |
21 import os | |
22 import os.path | |
20 from sat.core.i18n import _, D_ | 23 from sat.core.i18n import _, D_ |
21 from sat.core.constants import Const as C | 24 from sat.core.constants import Const as C |
22 from sat.core.log import getLogger | 25 from sat.core.log import getLogger |
26 from sat.core import exceptions | |
27 from twisted.internet import reactor | |
28 from twisted.internet import protocol | |
29 from twisted.internet import error as int_error | |
23 | 30 |
24 log = getLogger(__name__) | 31 log = getLogger(__name__) |
25 from sat.core import exceptions | |
26 import sys | |
27 import mmap | |
28 | |
29 | 32 |
30 PLUGIN_INFO = { | 33 PLUGIN_INFO = { |
31 C.PI_NAME: "Android ", | 34 C.PI_NAME: "Android ", |
32 C.PI_IMPORT_NAME: "android", | 35 C.PI_IMPORT_NAME: "android", |
33 C.PI_TYPE: C.PLUG_TYPE_MISC, | 36 C.PI_TYPE: C.PLUG_TYPE_MISC, |
44 from plyer import notification, vibrator | 47 from plyer import notification, vibrator |
45 | 48 |
46 PARAM_VIBRATE_CATEGORY = "Notifications" | 49 PARAM_VIBRATE_CATEGORY = "Notifications" |
47 PARAM_VIBRATE_NAME = "vibrate" | 50 PARAM_VIBRATE_NAME = "vibrate" |
48 PARAM_VIBRATE_LABEL = D_(u"Vibrate on notifications") | 51 PARAM_VIBRATE_LABEL = D_(u"Vibrate on notifications") |
52 SOCKET_DIR = "/data/data/org.salutatoi.cagou/" | |
53 SOCKET_FILE = ".socket" | |
54 STATE_RUNNING = "running" | |
55 STATE_PAUSED = "paused" | |
56 STATE_STOPPED = "stopped" | |
57 STATES = (STATE_RUNNING, STATE_PAUSED, STATE_STOPPED) | |
58 | |
59 | |
60 class FrontendStateProtocol(protocol.Protocol): | |
61 | |
62 def __init__(self, android_plugin): | |
63 self.android_plugin = android_plugin | |
64 | |
65 def dataReceived(self, data): | |
66 if data in STATES: | |
67 self.android_plugin.state = data | |
68 else: | |
69 log.warning(u"Unexpected data: {data}".format(data=data)) | |
70 | |
71 | |
72 class FrontendStateFactory(protocol.Factory): | |
73 | |
74 def __init__(self, android_plugin): | |
75 self.android_plugin = android_plugin | |
76 | |
77 def buildProtocol(self, addr): | |
78 return FrontendStateProtocol(self.android_plugin) | |
79 | |
49 | 80 |
50 | 81 |
51 class AndroidPlugin(object): | 82 class AndroidPlugin(object): |
52 | 83 |
53 params = """ | 84 params = """ |
64 param_name=PARAM_VIBRATE_NAME, | 95 param_name=PARAM_VIBRATE_NAME, |
65 param_label=PARAM_VIBRATE_LABEL, | 96 param_label=PARAM_VIBRATE_LABEL, |
66 ) | 97 ) |
67 | 98 |
68 def __init__(self, host): | 99 def __init__(self, host): |
69 log.info(_("plugin Android initialization")) | 100 log.info(_(u"plugin Android initialization")) |
70 self.host = host | 101 self.host = host |
71 host.memory.updateParams(self.params) | 102 host.memory.updateParams(self.params) |
72 self.cagou_status_fd = open("app/.cagou_status", "rb") | 103 try: |
73 self.cagou_status = mmap.mmap( | 104 os.mkdir(SOCKET_DIR, 0700) |
74 self.cagou_status_fd.fileno(), 1, prot=mmap.PROT_READ | 105 except OSError as e: |
75 ) | 106 if e.errno == 17: |
76 # we set a low priority because we want the notification to be sent after all plugins have done their job | 107 # dir already exists |
108 pass | |
109 else: | |
110 raise e | |
111 self._state = None | |
112 factory = FrontendStateFactory(self) | |
113 socket_path = os.path.join(SOCKET_DIR, SOCKET_FILE) | |
114 try: | |
115 reactor.listenUNIX(socket_path, factory) | |
116 except int_error.CannotListenError as e: | |
117 if e.socketError.errno == 98: | |
118 # the address is already in use, we need to remove it | |
119 os.unlink(socket_path) | |
120 reactor.listenUNIX(socket_path, factory) | |
121 else: | |
122 raise e | |
123 # we set a low priority because we want the notification to be sent after all | |
124 # plugins have done their job | |
77 host.trigger.add("MessageReceived", self.messageReceivedTrigger, priority=-1000) | 125 host.trigger.add("MessageReceived", self.messageReceivedTrigger, priority=-1000) |
78 | 126 |
79 @property | 127 @property |
128 def state(self): | |
129 return self._state | |
130 | |
131 @state.setter | |
132 def state(self, new_state): | |
133 log.debug(u"frontend state has changed: {state}".format(state=new_state)) | |
134 previous_state = self._state | |
135 self._state = new_state | |
136 if new_state == STATE_RUNNING: | |
137 self._onRunning(previous_state) | |
138 elif new_state == STATE_PAUSED: | |
139 self._onPaused(previous_state) | |
140 elif new_state == STATE_STOPPED: | |
141 self._onStopped(previous_state) | |
142 | |
143 @property | |
80 def cagou_active(self): | 144 def cagou_active(self): |
81 # 'R' status means Cagou is running in front | 145 return self._state == STATE_RUNNING |
82 return self.cagou_status[0] == "R" | 146 |
147 def _onRunning(self, previous_state): | |
148 if previous_state is not None: | |
149 self.host.bridge.bridgeReactivateSignals() | |
150 | |
151 def _onPaused(self, previous_state): | |
152 self.host.bridge.bridgeDeactivateSignals() | |
153 | |
154 def _onStopped(self, previous_state): | |
155 pass | |
83 | 156 |
84 def _notifyMessage(self, mess_data, client): | 157 def _notifyMessage(self, mess_data, client): |
85 # send notification if there is a message and it is not a groupchat | 158 # send notification if there is a message and it is not a groupchat |
86 if mess_data["message"] and mess_data["type"] != C.MESS_TYPE_GROUPCHAT: | 159 if mess_data["message"] and mess_data["type"] != C.MESS_TYPE_GROUPCHAT: |
87 message = mess_data["message"].itervalues().next() | 160 message = mess_data["message"].itervalues().next() |