# HG changeset patch # User Goffi # Date 1552144981 -3600 # Node ID 90115cf4e73133dc63c1fc52cd0009cc0b2bbb5b # Parent 0f277708e2aeade0bbb5b7fac7561965eca54ec8 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. diff -r 0f277708e2ae -r 90115cf4e731 sat/plugins/plugin_misc_android.py --- a/sat/plugins/plugin_misc_android.py Sat Mar 09 16:23:00 2019 +0100 +++ b/sat/plugins/plugin_misc_android.py Sat Mar 09 16:23:01 2019 +0100 @@ -17,15 +17,18 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import sys +import os +import os.path from sat.core.i18n import _, D_ from sat.core.constants import Const as C from sat.core.log import getLogger +from sat.core import exceptions +from twisted.internet import reactor +from twisted.internet import protocol +from twisted.internet import error as int_error log = getLogger(__name__) -from sat.core import exceptions -import sys -import mmap - PLUGIN_INFO = { C.PI_NAME: "Android ", @@ -46,6 +49,34 @@ PARAM_VIBRATE_CATEGORY = "Notifications" PARAM_VIBRATE_NAME = "vibrate" PARAM_VIBRATE_LABEL = D_(u"Vibrate on notifications") +SOCKET_DIR = "/data/data/org.salutatoi.cagou/" +SOCKET_FILE = ".socket" +STATE_RUNNING = "running" +STATE_PAUSED = "paused" +STATE_STOPPED = "stopped" +STATES = (STATE_RUNNING, STATE_PAUSED, STATE_STOPPED) + + +class FrontendStateProtocol(protocol.Protocol): + + def __init__(self, android_plugin): + self.android_plugin = android_plugin + + def dataReceived(self, data): + if data in STATES: + self.android_plugin.state = data + else: + log.warning(u"Unexpected data: {data}".format(data=data)) + + +class FrontendStateFactory(protocol.Factory): + + def __init__(self, android_plugin): + self.android_plugin = android_plugin + + def buildProtocol(self, addr): + return FrontendStateProtocol(self.android_plugin) + class AndroidPlugin(object): @@ -66,20 +97,62 @@ ) def __init__(self, host): - log.info(_("plugin Android initialization")) + log.info(_(u"plugin Android initialization")) self.host = host host.memory.updateParams(self.params) - self.cagou_status_fd = open("app/.cagou_status", "rb") - self.cagou_status = mmap.mmap( - self.cagou_status_fd.fileno(), 1, prot=mmap.PROT_READ - ) - # we set a low priority because we want the notification to be sent after all plugins have done their job + try: + os.mkdir(SOCKET_DIR, 0700) + except OSError as e: + if e.errno == 17: + # dir already exists + pass + else: + raise e + self._state = None + factory = FrontendStateFactory(self) + socket_path = os.path.join(SOCKET_DIR, SOCKET_FILE) + try: + reactor.listenUNIX(socket_path, factory) + except int_error.CannotListenError as e: + if e.socketError.errno == 98: + # the address is already in use, we need to remove it + os.unlink(socket_path) + reactor.listenUNIX(socket_path, factory) + else: + raise e + # we set a low priority because we want the notification to be sent after all + # plugins have done their job host.trigger.add("MessageReceived", self.messageReceivedTrigger, priority=-1000) @property + def state(self): + return self._state + + @state.setter + def state(self, new_state): + log.debug(u"frontend state has changed: {state}".format(state=new_state)) + previous_state = self._state + self._state = new_state + if new_state == STATE_RUNNING: + self._onRunning(previous_state) + elif new_state == STATE_PAUSED: + self._onPaused(previous_state) + elif new_state == STATE_STOPPED: + self._onStopped(previous_state) + + @property def cagou_active(self): - #  'R' status means Cagou is running in front - return self.cagou_status[0] == "R" + return self._state == STATE_RUNNING + + def _onRunning(self, previous_state): + if previous_state is not None: + self.host.bridge.bridgeReactivateSignals() + + def _onPaused(self, previous_state): + self.host.bridge.bridgeDeactivateSignals() + + def _onStopped(self, previous_state): + pass def _notifyMessage(self, mess_data, client): # send notification if there is a message and it is not a groupchat