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.
This commit is contained in:
Goffi 2019-03-09 16:23:01 +01:00
commit 248d771176

View file

@ -17,15 +17,18 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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 @@ from plyer import notification, vibrator
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 @@ class AndroidPlugin(object):
)
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