view cagou/core/platform_/android.py @ 324:4374cb741eb5

core (common widgets): added a DelayedBoxLayout class: DelayedBoxLayout delay the sizing, this is useful when sizing is complex and resource consuming. Thanks to https://blog.kivy.org/2019/07/a-delayed-resize-layout-in-kivy/
author Goffi <goffi@goffi.org>
date Fri, 06 Dec 2019 13:23:03 +0100
parents e2b51663d8b8
children 89799148f894
line wrap: on
line source

#!/usr/bin/env python3

# Cagou: desktop/mobile frontend for Salut à Toi XMPP client
# Copyright (C) 2016-2019 Jérôme Poisson (goffi@goffi.org)

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.

# 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
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


log = logging.getLogger(__name__)

service = autoclass('org.salutatoi.cagou.ServiceBackend')
mActivity = autoclass('org.kivy.android.PythonActivity').mActivity
ImagesMedia = autoclass('android.provider.MediaStore$Images$Media')
AudioMedia = autoclass('android.provider.MediaStore$Audio$Media')
VideoMedia = autoclass('android.provider.MediaStore$Video$Media')
DATA = '_data'


STATE_RUNNING = b"running"
STATE_PAUSED = b"paused"
STATE_STOPPED = b"stopped"
SOCKET_DIR = "/data/data/org.salutatoi.cagou/"
SOCKET_FILE = ".socket"

# cache for callbacks to run when profile is plugged
cache = []


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
        else:
            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)


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)