From f7f4114864c857f73a5c2ab5f1fd2597aab9ae58 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Fri, 24 Jan 2014 22:36:43 +0000 Subject: [PATCH 1/7] Added simple buildozer.spec for gps example --- examples/gps/buildozer.spec | 173 ++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 examples/gps/buildozer.spec diff --git a/examples/gps/buildozer.spec b/examples/gps/buildozer.spec new file mode 100644 index 000000000..cc98f0877 --- /dev/null +++ b/examples/gps/buildozer.spec @@ -0,0 +1,173 @@ +[app] + +# (str) Title of your application +title = Plyer GPS example + +# (str) Package name +package.name = gpsexample + +# (str) Package domain (needed for android/ios packaging) +package.domain = org.test + +# (str) Source code where the main.py live +source.dir = . + +# (list) Source files to include (let empty to include all the files) +source.include_exts = py,png,jpg,kv,atlas + +# (list) Source files to exclude (let empty to not exclude anything) +#source.exclude_exts = spec + +# (list) List of directory to exclude (let empty to not exclude anything) +#source.exclude_dirs = tests, bin + +# (list) List of exclusions using pattern matching +#source.exclude_patterns = license,images/*/*.jpg + +# (str) Application versioning (method 1) +# version.regex = __version__ = '(.*)' +# version.filename = %(source.dir)s/main.py + +# (str) Application versioning (method 2) +version = 1.0 + +# (list) Application requirements +requirements = plyer,kivy + +# (str) Presplash of the application +#presplash.filename = %(source.dir)s/data/presplash.png + +# (str) Icon of the application +#icon.filename = %(source.dir)s/data/icon.png + +# (str) Supported orientation (one of landscape, portrait or all) +orientation = portrait + +# (bool) Indicate if the application should be fullscreen or not +fullscreen = 0 + + +# +# Android specific +# + +# (list) Permissions +android.permissions = INTERNET,ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION + +# (int) Android API to use +#android.api = 14 + +# (int) Minimum API required (8 = Android 2.2 devices) +#android.minapi = 8 + +# (int) Android SDK version to use +#android.sdk = 21 + +# (str) Android NDK version to use +#android.ndk = 9 + +# (bool) Use --private data storage (True) or --dir public storage (False) +#android.private_storage = True + +# (str) Android NDK directory (if empty, it will be automatically downloaded.) +#android.ndk_path = + +# (str) Android SDK directory (if empty, it will be automatically downloaded.) +#android.sdk_path = + +# (str) Android entry point, default is ok for Kivy-based app +#android.entrypoint = org.renpy.android.PythonActivity + +# (list) List of Java .jar files to add to the libs so that pyjnius can access +# their classes. Don't add jars that you do not need, since extra jars can slow +# down the build process. Allows wildcards matching, for example: +# OUYA-ODK/libs/*.jar +#android.add_jars = foo.jar,bar.jar,path/to/more/*.jar + +# (list) List of Java files to add to the android project (can be java or a +# directory containing the files) +#android.add_src = + +# (str) python-for-android branch to use, if not master, useful to try +# not yet merged features. +#android.branch = master + +# (str) OUYA Console category. Should be one of GAME or APP +# If you leave this blank, OUYA support will not be enabled +#android.ouya.category = GAME + +# (str) Filename of OUYA Console icon. It must be a 732x412 png image. +#android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png + +# (str) XML file to include as an intent filters in tag +#android.manifest.intent_filters = + +# (list) Android additionnal libraries to copy into libs/armeabi +#android.add_libs_armeabi = libs/android/*.so + +# (bool) Indicate whether the screen should stay on +# Don't forget to add the WAKE_LOCK permission if you set this to True +#android.wakelock = False + +# (list) Android application meta-data to set (key=value format) +#android.meta_data = + +# (list) Android library project to add (will be added in the +# project.properties automatically.) +#android.library_references = + +# +# iOS specific +# + +# (str) Name of the certificate to use for signing the debug version +# Get a list of available identities: buildozer ios list_identities +#ios.codesign.debug = "iPhone Developer: ()" + +# (str) Name of the certificate to use for signing the release version +#ios.codesign.release = %(ios.codesign.debug)s + + +[buildozer] + +# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) +log_level = 2 + + +# ----------------------------------------------------------------------------- +# List as sections +# +# You can define all the "list" as [section:key]. +# Each line will be considered as a option to the list. +# Let's take [app] / source.exclude_patterns. +# Instead of doing: +# +# [app] +# source.exclude_patterns = license,data/audio/*.wav,data/images/original/* +# +# This can be translated into: +# +# [app:source.exclude_patterns] +# license +# data/audio/*.wav +# data/images/original/* +# + + +# ----------------------------------------------------------------------------- +# Profiles +# +# You can extend section / key with a profile +# For example, you want to deploy a demo version of your application without +# HD content. You could first change the title to add "(demo)" in the name +# and extend the excluded directories to remove the HD content. +# +# [app@demo] +# title = My Application (demo) +# +# [app:source.exclude_patterns@demo] +# images/hd/* +# +# Then, invoke the command line with the "demo" profile: +# +# buildozer --profile demo android debug From 2d24ea2d9dfa207f5629693ba761b67dbc15b554 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Sat, 25 Jan 2014 15:09:14 +0000 Subject: [PATCH 2/7] Added email facade --- plyer/__init__.py | 6 ++++- plyer/facades.py | 20 +++++++++++++++- plyer/platforms/android/email.py | 40 ++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 plyer/platforms/android/email.py diff --git a/plyer/__init__.py b/plyer/__init__.py index 4ec8329a9..ac1ea5af9 100644 --- a/plyer/__init__.py +++ b/plyer/__init__.py @@ -4,7 +4,7 @@ ''' -__all__ = ('accelerometer', 'camera', 'gps', 'notification', 'tts') +__all__ = ('accelerometer', 'camera', 'gps', 'notification', 'tts', 'email') __version__ = '1.1.2' from plyer import facades @@ -29,3 +29,7 @@ #: TTS proxy to :class:`plyer.facades.TTS` tts = Proxy( 'tts', facades.TTS) + +#: Email proxy to :class:`plyer.facades.Email` +email = Proxy( + 'email', facades.Email) diff --git a/plyer/facades.py b/plyer/facades.py index 3c0089067..b67cc9223 100644 --- a/plyer/facades.py +++ b/plyer/facades.py @@ -6,7 +6,7 @@ ''' -__all__ = ('Accelerometer', 'Camera', 'GPS', 'Notification', 'TTS') +__all__ = ('Accelerometer', 'Camera', 'GPS', 'Notification', 'TTS', 'Email') class Accelerometer(object): @@ -90,6 +90,24 @@ def _notify(self, **kwargs): raise NotImplementedError() +class Email(object): + '''Email facade.''' + + def send(self, recipient=None, subject=None, text=None, + attachment=None): + '''Open an email client message send window, prepopulated with the + given arguments.''' + print 'EMAIL FACADE USED' + self._send(recipient=recipient, subject=subject, text=text, + attachment=None) + + # private + + def _send(self, **kwargs): + raise NotImplementedError() + + + class TTS(object): '''TextToSpeech facade. ''' diff --git a/plyer/platforms/android/email.py b/plyer/platforms/android/email.py new file mode 100644 index 000000000..7b0eb0e78 --- /dev/null +++ b/plyer/platforms/android/email.py @@ -0,0 +1,40 @@ +from jnius import autoclass, cast +from plyer.facades import Email +from plyer.platforms.android import activity + +Intent = autoclass('android.content.Intent') +AndroidString = autoclass('java.lang.String') +Uri = autoclass('android.net.Uri') + +class AndroidEmail(Email): + def _send(self, **kwargs): + print 'Using ANDROIDEMAIL' + intent = Intent(Intent.ACTION_SEND) + intent.setType('text/plain') + + recipient = kwargs.get('recipient') + subject = kwargs.get('subject') + text = kwargs.get('text') + attachment = kwargs.get('attachment') + + if recipient: + android_recipient = cast('java.lang.CharSequence', + AndroidString(recipient)) + intent.putExtra(Intent.EXTRA_EMAIL, android_recipient) + if subject: + android_subject = cast('java.lang.CharSequence', + AndroidString(subject)) + intent.putExtra(Intent.EXTRA_SUBJECT, android_subject) + if text: + android_text = cast('java.lang.CharSequence', + AndroidString(android_text)) + intent.putExtra(Intent.EXTRA_TEXT, android_text) + if attachment: + android_attachment = AndroidString('file://' + attachment)) + intent.putExtra(Intent.EXTRA_STREAM, Uri.parse(android_attachment)) + + activity.startActivity(intent) + + +def instance(): + return AndroidEmail() From d31e02c0a994fcf6d6a09a146d3554dec30dd19c Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Mon, 27 Jan 2014 22:00:55 +0000 Subject: [PATCH 3/7] Completed email facade and android implementation --- plyer/facades.py | 16 ++++++++++++---- plyer/platforms/android/email.py | 21 ++++++++++----------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/plyer/facades.py b/plyer/facades.py index b67cc9223..6dd75256d 100644 --- a/plyer/facades.py +++ b/plyer/facades.py @@ -94,12 +94,20 @@ class Email(object): '''Email facade.''' def send(self, recipient=None, subject=None, text=None, - attachment=None): + create_chooser=None): '''Open an email client message send window, prepopulated with the - given arguments.''' - print 'EMAIL FACADE USED' + given arguments. + + :param recipient: Recipient of the message (str) + :param subject: Subject of the message (str) + :param text: Main body of the message (str) + :param create_chooser: Whether to display a program chooser to + handle the message (bool) + + .. note:: create_chooser is only supported on Android + ''' self._send(recipient=recipient, subject=subject, text=text, - attachment=None) + create_chooser=create_chooser) # private diff --git a/plyer/platforms/android/email.py b/plyer/platforms/android/email.py index 7b0eb0e78..3d3748440 100644 --- a/plyer/platforms/android/email.py +++ b/plyer/platforms/android/email.py @@ -4,36 +4,35 @@ Intent = autoclass('android.content.Intent') AndroidString = autoclass('java.lang.String') -Uri = autoclass('android.net.Uri') class AndroidEmail(Email): def _send(self, **kwargs): - print 'Using ANDROIDEMAIL' intent = Intent(Intent.ACTION_SEND) intent.setType('text/plain') recipient = kwargs.get('recipient') subject = kwargs.get('subject') text = kwargs.get('text') - attachment = kwargs.get('attachment') + create_chooser = kwargs.get('create_chooser') if recipient: - android_recipient = cast('java.lang.CharSequence', - AndroidString(recipient)) - intent.putExtra(Intent.EXTRA_EMAIL, android_recipient) + intent.putExtra(Intent.EXTRA_EMAIL, [recipient]) if subject: android_subject = cast('java.lang.CharSequence', AndroidString(subject)) intent.putExtra(Intent.EXTRA_SUBJECT, android_subject) if text: android_text = cast('java.lang.CharSequence', - AndroidString(android_text)) + AndroidString(text)) intent.putExtra(Intent.EXTRA_TEXT, android_text) - if attachment: - android_attachment = AndroidString('file://' + attachment)) - intent.putExtra(Intent.EXTRA_STREAM, Uri.parse(android_attachment)) - activity.startActivity(intent) + if create_chooser: + chooser_title = cast('java.lang.CharSequence', + AndroidString('Send message with:')) + activity.startActivity(Intent.createChooser(intent, + chooser_title)) + else: + activity.startActivity(intent) def instance(): From e0ebdfd19baa2d5eb9a4dcf0c93e72ac86177f5e Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Mon, 27 Jan 2014 22:01:43 +0000 Subject: [PATCH 4/7] Added email to README --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 73258bb0e..83be1ea16 100644 --- a/README.rst +++ b/README.rst @@ -25,4 +25,5 @@ Camera (taking picture) X X GPS X X Notifications X X X X X Text to speech X X X X X +Email (open mail client) X ================================== ============= ============= === ======= === ===== From 63f8885b2025e98da6589e1be38175b5786394c2 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Mon, 27 Jan 2014 22:02:21 +0000 Subject: [PATCH 5/7] Added email facade example --- examples/email/buildozer.spec | 173 ++++++++++++++++++++++++++++++++++ examples/email/main.py | 71 ++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 examples/email/buildozer.spec create mode 100644 examples/email/main.py diff --git a/examples/email/buildozer.spec b/examples/email/buildozer.spec new file mode 100644 index 000000000..e55d77f17 --- /dev/null +++ b/examples/email/buildozer.spec @@ -0,0 +1,173 @@ +[app] + +# (str) Title of your application +title = Plyer email test + +# (str) Package name +package.name = email + +# (str) Package domain (needed for android/ios packaging) +package.domain = org.test + +# (str) Source code where the main.py live +source.dir = . + +# (list) Source files to include (let empty to include all the files) +source.include_exts = py,png,jpg,kv,atlas + +# (list) Source files to exclude (let empty to not exclude anything) +#source.exclude_exts = spec + +# (list) List of directory to exclude (let empty to not exclude anything) +#source.exclude_dirs = tests, bin + +# (list) List of exclusions using pattern matching +#source.exclude_patterns = license,images/*/*.jpg + +# (str) Application versioning (method 1) +# version.regex = __version__ = '(.*)' +# version.filename = %(source.dir)s/main.py + +# (str) Application versioning (method 2) +version = 1.0 + +# (list) Application requirements +requirements = plyer,kivy + +# (str) Presplash of the application +#presplash.filename = %(source.dir)s/data/presplash.png + +# (str) Icon of the application +#icon.filename = %(source.dir)s/data/icon.png + +# (str) Supported orientation (one of landscape, portrait or all) +orientation = portrait + +# (bool) Indicate if the application should be fullscreen or not +fullscreen = 0 + + +# +# Android specific +# + +# (list) Permissions +#android.permissions = INTERNET + +# (int) Android API to use +#android.api = 14 + +# (int) Minimum API required (8 = Android 2.2 devices) +#android.minapi = 8 + +# (int) Android SDK version to use +#android.sdk = 21 + +# (str) Android NDK version to use +#android.ndk = 9 + +# (bool) Use --private data storage (True) or --dir public storage (False) +#android.private_storage = True + +# (str) Android NDK directory (if empty, it will be automatically downloaded.) +#android.ndk_path = + +# (str) Android SDK directory (if empty, it will be automatically downloaded.) +#android.sdk_path = + +# (str) Android entry point, default is ok for Kivy-based app +#android.entrypoint = org.renpy.android.PythonActivity + +# (list) List of Java .jar files to add to the libs so that pyjnius can access +# their classes. Don't add jars that you do not need, since extra jars can slow +# down the build process. Allows wildcards matching, for example: +# OUYA-ODK/libs/*.jar +#android.add_jars = foo.jar,bar.jar,path/to/more/*.jar + +# (list) List of Java files to add to the android project (can be java or a +# directory containing the files) +#android.add_src = + +# (str) python-for-android branch to use, if not master, useful to try +# not yet merged features. +#android.branch = master + +# (str) OUYA Console category. Should be one of GAME or APP +# If you leave this blank, OUYA support will not be enabled +#android.ouya.category = GAME + +# (str) Filename of OUYA Console icon. It must be a 732x412 png image. +#android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png + +# (str) XML file to include as an intent filters in tag +#android.manifest.intent_filters = + +# (list) Android additionnal libraries to copy into libs/armeabi +#android.add_libs_armeabi = libs/android/*.so + +# (bool) Indicate whether the screen should stay on +# Don't forget to add the WAKE_LOCK permission if you set this to True +#android.wakelock = False + +# (list) Android application meta-data to set (key=value format) +#android.meta_data = + +# (list) Android library project to add (will be added in the +# project.properties automatically.) +#android.library_references = + +# +# iOS specific +# + +# (str) Name of the certificate to use for signing the debug version +# Get a list of available identities: buildozer ios list_identities +#ios.codesign.debug = "iPhone Developer: ()" + +# (str) Name of the certificate to use for signing the release version +#ios.codesign.release = %(ios.codesign.debug)s + + +[buildozer] + +# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) +log_level = 2 + + +# ----------------------------------------------------------------------------- +# List as sections +# +# You can define all the "list" as [section:key]. +# Each line will be considered as a option to the list. +# Let's take [app] / source.exclude_patterns. +# Instead of doing: +# +# [app] +# source.exclude_patterns = license,data/audio/*.wav,data/images/original/* +# +# This can be translated into: +# +# [app:source.exclude_patterns] +# license +# data/audio/*.wav +# data/images/original/* +# + + +# ----------------------------------------------------------------------------- +# Profiles +# +# You can extend section / key with a profile +# For example, you want to deploy a demo version of your application without +# HD content. You could first change the title to add "(demo)" in the name +# and extend the excluded directories to remove the HD content. +# +# [app@demo] +# title = My Application (demo) +# +# [app:source.exclude_patterns@demo] +# images/hd/* +# +# Then, invoke the command line with the "demo" profile: +# +# buildozer --profile demo android debug diff --git a/examples/email/main.py b/examples/email/main.py new file mode 100644 index 000000000..8b57724cc --- /dev/null +++ b/examples/email/main.py @@ -0,0 +1,71 @@ + +from kivy.app import App +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.button import Button +from kivy.lang import Builder +from kivy.properties import StringProperty, BooleanProperty + +from plyer import email + +from jnius import autoclass, cast + +Builder.load_string(''' +: + orientation: 'vertical' + BoxLayout: + Label: + text: 'Recipient:' + TextInput: + id: recipient + BoxLayout: + Label: + text: 'Subject:' + TextInput: + id: subject + BoxLayout: + Label: + text: 'text' + TextInput: + id: text + BoxLayout: + Label: + text: 'create chooser?' + CheckBox: + id: create_chooser + IntentButton: + email_recipient: recipient.text + email_subject: subject.text + email_text: text.text + create_chooser: create_chooser.active + text: 'Send email' + size_hint_y: None + height: sp(40) + on_release: self.send_email() +''') + + +class EmailInterface(BoxLayout): + pass + + +class IntentButton(Button): + email_recipient = StringProperty() + email_subject = StringProperty() + email_text = StringProperty() + create_chooser = BooleanProperty() + + def send_email(self, *args): + email.send(recipient=self.email_recipient, + subject=self.email_subject, + text=self.email_text, + create_chooser=self.create_chooser) + + +class EmailApp(App): + def build(self): + return EmailInterface() + def on_pause(self): + return True + +if __name__ == "__main__": + EmailApp().run() From 7f8e28c3c4621f06b71d8673f2c1a94dadd98b03 Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Mon, 27 Jan 2014 22:05:40 +0000 Subject: [PATCH 6/7] pep8 fixes --- examples/email/main.py | 7 ++++--- plyer/facades.py | 3 --- plyer/platforms/android/email.py | 1 + 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/email/main.py b/examples/email/main.py index 8b57724cc..6aad1bf97 100644 --- a/examples/email/main.py +++ b/examples/email/main.py @@ -31,7 +31,7 @@ Label: text: 'create chooser?' CheckBox: - id: create_chooser + id: create_chooser IntentButton: email_recipient: recipient.text email_subject: subject.text @@ -46,7 +46,7 @@ class EmailInterface(BoxLayout): pass - + class IntentButton(Button): email_recipient = StringProperty() @@ -64,8 +64,9 @@ def send_email(self, *args): class EmailApp(App): def build(self): return EmailInterface() + def on_pause(self): return True - + if __name__ == "__main__": EmailApp().run() diff --git a/plyer/facades.py b/plyer/facades.py index 6dd75256d..788ff1a07 100644 --- a/plyer/facades.py +++ b/plyer/facades.py @@ -114,7 +114,6 @@ def send(self, recipient=None, subject=None, text=None, def _send(self, **kwargs): raise NotImplementedError() - class TTS(object): '''TextToSpeech facade. @@ -201,5 +200,3 @@ def _start(self): def _stop(self): raise NotImplementedError() - - diff --git a/plyer/platforms/android/email.py b/plyer/platforms/android/email.py index 3d3748440..79923e46c 100644 --- a/plyer/platforms/android/email.py +++ b/plyer/platforms/android/email.py @@ -5,6 +5,7 @@ Intent = autoclass('android.content.Intent') AndroidString = autoclass('java.lang.String') + class AndroidEmail(Email): def _send(self, **kwargs): intent = Intent(Intent.ACTION_SEND) From 258e03198e44131737183f0aec03f592d3bdbd3e Mon Sep 17 00:00:00 2001 From: Alexander Taylor Date: Mon, 27 Jan 2014 22:08:25 +0000 Subject: [PATCH 7/7] Removed unnecessary import from email --- examples/email/main.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/email/main.py b/examples/email/main.py index 6aad1bf97..fbe202309 100644 --- a/examples/email/main.py +++ b/examples/email/main.py @@ -7,8 +7,6 @@ from plyer import email -from jnius import autoclass, cast - Builder.load_string(''' : orientation: 'vertical'