diff cagou/core/platform_/android.py @ 342:89799148f894

core: use classes and factory to handle platform specific behaviours in a generic way
author Goffi <goffi@goffi.org>
date Sat, 04 Jan 2020 16:24:57 +0100
parents e2b51663d8b8
children a3cefa7158dc
line wrap: on
line diff
--- a/cagou/core/platform_/android.py	Fri Jan 03 15:48:59 2020 +0100
+++ b/cagou/core/platform_/android.py	Sat Jan 04 16:24:57 2020 +0100
@@ -17,12 +17,15 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import sys
+import os
+import socket
 from jnius import autoclass, cast
 from android import activity
 from sat.core import log as logging
 from cagou.core.constants import Const as C
 from cagou import G
 from kivy.clock import Clock
+from .base import Platform as BasePlatform
 
 
 log = logging.getLogger(__name__)
@@ -41,84 +44,108 @@
 SOCKET_DIR = "/data/data/org.salutatoi.cagou/"
 SOCKET_FILE = ".socket"
 
-# cache for callbacks to run when profile is plugged
-cache = []
+
+class Platform(BasePlatform):
+
+    def __init__(self):
+        super().__init__()
+        # cache for callbacks to run when profile is plugged
+        self.cache = []
+
+    def init_platform(self):
+        # sys.platform is "linux" on android by default
+        # so we change it to allow backend to detect android
+        sys.platform = "android"
+        C.PLUGIN_EXT = 'pyc'
+
+    def on_app_build(self, wid):
+        # we don't want menu on Android
+        wid.root_menus.height = 0
+
+    def on_host_init(self, host):
+        argument = ''
+        service.start(mActivity, argument)
 
+        activity.bind(on_new_intent=self.on_new_intent)
+        self.cache.append((self.on_new_intent, mActivity.getIntent()))
+        host.addListener('profilePlugged', self.onProfilePlugged)
+
+    def on_initFrontendState(self):
+        # XXX: we use a separated socket instead of bridge because if we
+        #      try to call a bridge method in on_pause method, the call data
+        #      is not written before the actual pause
+        s = self._frontend_status_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+        s.connect(os.path.join(SOCKET_DIR, SOCKET_FILE))
+        s.sendall(STATE_RUNNING)
+
+    def onProfilePlugged(self, profile):
+        log.debug("ANDROID profilePlugged")
+        for method, *args in self.cache:
+            method(*args)
+        del self.cache
+        G.host.removeListener("profilePlugged", self.onProfilePlugged)
+
+    def on_pause(self):
+        G.host.sync = False
+        self._frontend_status_socket.sendall(STATE_PAUSED)
+        return True
 
-def on_new_intent(intent):
-    log.debug("on_new_intent")
-    Intent = autoclass('android.content.Intent')
-    action = intent.getAction();
-    intent_type = intent.getType();
-    if action == "android.intent.action.SEND":
-        # we have receiving data to share, we parse the intent data
-        # and show the share widget
-        data = {}
-        text = intent.getStringExtra(Intent.EXTRA_TEXT)
-        if text is not None:
-            data['text'] = text
-        item = intent.getParcelableExtra(Intent.EXTRA_STREAM)
-        if item is not None:
-            uri = cast('android.net.Uri', item)
-            data['uri'] = uri.toString()
-            path = getPathFromUri(uri)
-            if path is not None:
-                data['path'] = path
+    def on_resume(self):
+        self._frontend_status_socket.sendall(STATE_RUNNING)
+        G.host.sync = True
+
+    def on_stop(self):
+        self._frontend_status_socket.sendall(STATE_STOPPED)
+        self._frontend_status_socket.close()
+
+    def getPathFromUri(self, uri):
+        cursor = mActivity.getContentResolver().query(uri, None, None, None, None)
+        if cursor is None:
+            return uri.getPath()
         else:
+            cursor.moveToFirst()
+            # FIXME: using DATA is not recommended (and DATA is deprecated)
+            # we should read directly the file with
+            # ContentResolver#openFileDescriptor(Uri, String)
+            col_idx = cursor.getColumnIndex(DATA);
+            if col_idx == -1:
+                return uri.getPath()
+            return cursor.getString(col_idx)
+
+    def on_new_intent(self, intent):
+        log.debug("on_new_intent")
+        Intent = autoclass('android.content.Intent')
+        action = intent.getAction();
+        intent_type = intent.getType();
+        if action == "android.intent.action.SEND":
+            # we have receiving data to share, we parse the intent data
+            # and show the share widget
+            data = {}
+            text = intent.getStringExtra(Intent.EXTRA_TEXT)
+            if text is not None:
+                data['text'] = text
+            item = intent.getParcelableExtra(Intent.EXTRA_STREAM)
+            if item is not None:
+                uri = cast('android.net.Uri', item)
+                data['uri'] = uri.toString()
+                path = self.getPathFromUri(uri)
+                if path is not None:
+                    data['path'] = path
+            else:
+                uri = None
+                path = None
+
+            Clock.schedule_once(lambda *args: G.host.share(intent_type, data), 0)
+        else:
+            text = None
             uri = None
             path = None
 
-        Clock.schedule_once(lambda *args: G.host.share(intent_type, data), 0)
-    else:
-        text = None
-        uri = None
-        path = None
-
-    msg = (f"NEW INTENT RECEIVED\n"
-           f"type: {intent_type}\n"
-           f"action: {action}\n"
-           f"text: {text}\n"
-           f"uri: {uri}\n"
-           f"path: {path}")
-
-    log.debug(msg)
-
-
-def onProfilePlugged(profile):
-    log.debug("ANDROID profilePlugged")
-    global cache
-    for method, *args in cache:
-        method(*args)
-    del cache
-    G.host.removeListener("profilePlugged", onProfilePlugged)
-
+        msg = (f"NEW INTENT RECEIVED\n"
+               f"type: {intent_type}\n"
+               f"action: {action}\n"
+               f"text: {text}\n"
+               f"uri: {uri}\n"
+               f"path: {path}")
 
-def init_platform():
-    # sys.platform is "linux" on android by default
-    # so we change it to allow backend to detect android
-    sys.platform = "android"
-    C.PLUGIN_EXT = 'pyc'
-
-
-def host_init(host):
-    argument = ''
-    service.start(mActivity, argument)
-
-    activity.bind(on_new_intent=on_new_intent)
-    cache.append((on_new_intent, mActivity.getIntent()))
-    host.addListener('profilePlugged', onProfilePlugged)
-
-
-def getPathFromUri(uri):
-    cursor = mActivity.getContentResolver().query(uri, None, None, None, None)
-    if cursor is None:
-        return uri.getPath()
-    else:
-        cursor.moveToFirst()
-        # FIXME: using DATA is not recommended (and DATA is deprecated)
-        # we should read directly the file with
-        # ContentResolver#openFileDescriptor(Uri, String)
-        col_idx = cursor.getColumnIndex(DATA);
-        if col_idx == -1:
-            return uri.getPath()
-        return cursor.getString(col_idx)
+        log.debug(msg)