8000 add android_broadcast module · emanuele-f/python-for-android@075a465 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 075a465

Browse files
committed
add android_broadcast module
1 parent 55d291e commit 075a465

File tree

4 files changed

+181
-0
lines changed

4 files changed

+181
-0
lines changed

docs/source/android.rst

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,84 @@ Example without PyJNIus
348348
print android.get_dpi()
349349

350350

351+
Bridges
352+
-------
353+
354+
Some part of the Android API is not accessible from PyJNIus. For example, if
355+
you want to receive some broadcast, you need to implement a `BroadcastReceiver
356+
<http://developer.android.com/reference/android/content/BroadcastReceiver.html>`_.
357+
PyJNIus allows you to implement dynamically classes from Java interfaces, but
358+
unfortunately, the `BroadcastReceiver` is an abstract class.
359+
360+
So we started to create bridges for this case.
361+
362+
android_broadcast
363+
~~~~~~~~~~~~~~~~~
364+
365+
.. module:: android_broadcast
366+
367+
.. class:: BroadcastReceiver
368+
369+
Implementation of the android `BroadcastReceiver
370+
<http://developer.android.com/reference/android/content/BroadcastReceiver.html>`_.
371+
You can specify the callback that will receive the broadcast event, and
372+
actions or categories filters.
373+
374+
.. warning::
375+
376+
The callback will be called in another thread than the main thread. Be
377+
careful to not access to OpenGL or something like that.
378+
379+
.. method:: __init__(callback, actions=None, categories=None)
380+
381+
:param callback: function or method that will receive the event. Will
382+
receive the context and intent as argument.
383+
:param actions: list of strings that represent an action.
384+
:param categories: list of strings that represent a category.
385+
386+
For actions and categories, the string must be in lower case, without the prefix::
387+
388+
# In java: Intent.ACTION_HEADSET_PLUG
389+
# In python: 'headset_plug'
390+
391+
.. method:: start()
392+
393+
Register the receiver with all the actions and categories, and start
394+
handling events.
395+
396+
.. method:: stop()
397+
398+
Unregister the receiver with all the actions and categories, and stop
399+
handling events.
400+
401+
Example::
402+
403+
class TestApp(App):
404+
405+
def build(self):
406+
self.br = BroadcastReceiver(
407+
self.on_broadcast, actions=['headset_plug'])
408+
self.br.start()
409+
# ...
410+
411+
def on_broadcast(self, context, intent):
412+
extras = intent.getExtras()
413+
headset_state = bool(extras.get('state'))
414+
if headset_state:
415+
print 'The headset is plugged'
416+
else:
417+
print 'The headset is unplugged'
418+
419+
# don't forget to stop and restart the receiver when the app is going
420+
# to pause / resume mode
421+
422+
def on_pause(self):
423+
self.br.stop()
424+
return True
425+
426+
def on_resume(self):
427+
self.br.start()
428+
351429

352430
Old Version
353431
-----------
@@ -434,3 +512,4 @@ It has several differences from the pygame mixer:
434512
The android_mixer module hasn't been tested much, and so bugs may be
435513
present.
436514

515+
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# -------------------------------------------------------------------
2+
# Broadcast receiver bridge
3+
4+
from jnius import autoclass, PythonJavaClass, java_method
5+
6+
class BroadcastReceiver(object):
7+
8+
class Callback(PythonJavaClass):
9+
__javainterfaces__ = ['org/renpy/android/GenericBroadcastReceiverCallback']
10+
__javacontext__ = 'app'
11+
12+
def __init__(self, callback, *args, **kwargs):
13+
self.callback = callback
14+
PythonJavaClass.__init__(self, *args, **kwargs)
15+
16+
@java_method('(Landroid/content/Context;Landroid/content/Intent;)V')
17+
def onReceive(self, context, intent):
18+
self.callback(context, intent)
19+
20+
def __init__(self, callback, actions=None, categories=None):
21+
super(BroadcastReceiver, self).__init__()
22+
self.callback = callback
23+
24+
if not actions and not categories:
25+
raise Exception('You need to define at least actions or categories')
26+
27+
# resolve actions/categories first
28+
Intent = autoclass('android.content.Intent')
29+
resolved_actions = []
30+
if actions:
31+
for x in actions:
32+
name = 'ACTION_{}'.format(x.upper())
33+
if not hasattr(Intent, name):
34+
raise Exception('The intent {} doesnt exist'.format(name))
35+
resolved_actions += [getattr(Intent, name)]
36+
37+
resolved_categories = []
38+
if categories:
39+
for x in categories:
40+
name = 'CATEGORY_{}'.format(x.upper())
41+
if not hasattr(Intent, name):
42+
raise Exception('The intent {} doesnt exist'.format(name))
43+
resolved_categories += [getattr(Intent, name)]
44+
45+
# resolve android API
46+
PythonActivity = autoclass('org.renpy.android.PythonActivity')
47+
GenericBroadcastReceiver = autoclass('org.renpy.android.GenericBroadcastReceiver')
48+
IntentFilter = autoclass('android.content.IntentFilter')
49+
HandlerThread = autoclass('android.os.HandlerThread')
50+
51+
# create a thread for handling events from the receiver
52+
self.handlerthread = HandlerThread('handlerthread')
53+
54+
# create a listener
55+
self.context = PythonActivity.mActivity
56+
self.listener = BroadcastReceiver.Callback(self.callback)
57+
self.receiver = GenericBroadcastReceiver(self.listener)
58+
self.receiver_filter = IntentFilter()
59+
for x in resolved_actions:
60+
self.receiver_filter.addAction(x)
61+
for x in resolved_categories:
62+
self.receiver_filter.addCategory(x)
63+
64+
def start(self):
65+
Handler = autoclass('android.os.Handler')
66+
self.handlerthread.start()
67+
self.handler = Handler(self.handlerthread.getLooper())
68+
self.context.registerReceiver(self.receiver, self.receiver_filter, None,
69+
self.handler)
70+
71+
def stop(self):
72+
self.context.unregisterReceiver(self.receiver)
73+
self.handlerthread.quit()
74+
75+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.renpy.android;
2+
3+
import android.content.BroadcastReceiver;
4+
import android.content.Intent;
5+
import android.content.Context;
6+
7+
public class GenericBroadcastReceiver extends BroadcastReceiver {
8+
9+
GenericBroadcastReceiverCallback listener;
10+
11+
public GenericBroadcastReceiver(GenericBroadcastReceiverCallback listener) {
12+
super();
13+
this.listener = listener;
14+
}
15+
16+
public void onReceive(Context context, Intent intent) {
17+
this.listener.onReceive(context, intent);
18+
}
19+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.renpy.android;
2+
3+
import android.content.Intent;
4+
import android.content.Context;
5+
6+
public interface GenericBroadcastReceiverCallback {
7+
void onReceive(Context context, Intent intent);
8+
};

0 commit comments

Comments
 (0)
0