8000 tidy new Hardware.java and added getHardwareSensors for a complete list · break123/python-for-android@b4c117c · GitHub
[go: up one dir, main page]

Skip to content

Commit b4c117c

Browse files
Nik KleverNik Klever
authored andcommitted
tidy new Hardware.java and added getHardwareSensors for a complete list
changed and updated doc files for using Python-For-Android with PyJNIus
1 parent 4d8c23c commit b4c117c

File tree

3 files changed

+311
-189
lines changed

3 files changed

+311
-189
lines changed

docs/source/android.rst

Lines changed: 248 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,187 @@
11
Android Python module
22
=====================
33

4-
Python for android project include a python module named "android". This module is designed to give you an access to the Android API. As for today, the module is very limited, and waiting for contribution to wrap more Android API.
4+
Python for android project include a python module named "android". This module is designed to give you an access to the Java Android API.
5+
As for today, the module is very limited, and waiting for contribution to wrap more Java Android API.
56

6-
Example
7-
-------
87

9-
::
8+
How to use it
9+
-------------
1010

11-
import android
11+
Using `PyJNIus <https://github.com/kivy/pyjnius>`__ to access the Android API
12+
restricts the usage to a simple call of the **autoclass** constructor function
13+
and a second call to instantiate this class.
1214

13-
# activate the vibrator
14-
android.vibrate(1)
15+
You can access through this method all Java Android API, e.g. to get the DisplayMetrics
16+
of an Android device could fetched using the following piece of code:
1517

16-
# read screen dpi
17-
print android.get_dpi()
18+
.. code-block:: python
1819
19-
How it's working
20-
----------------
20+
DisplayMetrics = autoclass('android.util.DisplayMetrics')
21+
metrics = DisplayMetrics()
22+
metrics.setToDefaults()
23+
self.densityDpi = metrics.densityDpi
2124
22-
The whole Android API is accessible in Java. Their is no native or extensible
23-
way to access it from Python. The schema for accessing to their API is::
25+
You can access all fields and methods as described in the `Java Android
26+
DisplayMetrics API <http://developer.android.com/reference/android/util/DisplayMetrics.html>`__
27+
as shown here with the method `setToDefaults()` and the field `densityDpi`.
28+
Before you use o view a field, you should always call `setToDefaults` to initiate
29+
to the default values of the device.
2430

25-
[1] Cython -> [2] C JNI -> [3] Java
31+
Currently only JavaMethod, JavaStaticMethod, JavaField, JavaStaticField
32+
and JavaMultipleMethod are built into PyJNIus, therefore such constructs like
33+
registerListener or something like this have to be coded still in Java.
34+
For this the Android module described below is available to access some of
35+
the hardware in Android devices.
2636

27-
#. ``android.pyx`` is written in `Cython <http://cython.org/>`_: a language
28-
with typed informations, very close to Python, that generate Python
29-
extension. It's easier to write in Cython than CPython, and it's linked
30-
directly to the part 2.
31-
#. ``android_jni.c`` is defining simple c methods that access to Java
32-
interfaces using JNI layer.
33-
#. The last part contain the Java code that will be called from the JNI stuff.
37+
More background how to use the Java Android API without PyJNIus is also given
38+
below in the chapter `how-it-s-working-without-pyjnius`_
3439

35-
All the source code is available at:
3640

37-
https://github.com/kivy/python-for-android/tree/master/recipes/android/src
41+
Prebuilt VirtualBox
42+
-------------------
43+
44+
A good starting point to build an APK are prebuilt VirtualBox images, where
45+
the Android NDK, the Android SDK and the Kivy Python-For-Android sources
46+
are prebuilt in an VirtualBox image. Please search the `Google Python-For-Android forum
47+
<https://groups.google.com/forum/?fromgroups=&pli=1#!forum/python-android>`__ for
48+
such an image.
49+
50+
Example
51+
-------
52+
53+
The following example is an extract from the Compass app as provided in the Kivy
54+
`examples/android/compass <https://github.com/kivy/kivy/tree/master/examples/android/compass/>`__
55+
folder:
56+
57+
.. code-block:: python
58+
59+
from pyjnius import autoclass
60+
61+
...
62+
63+
class CompassApp(App):
64+
65+
def __init__(self, **kwargs):
66+
"""
67+
Constructor of the Compass App
68+
69+
1) The Java Android API DisplayMetrics is called to get
70+
information about the densityDpi factor of the Android device
71+
72+
2) The Kivy Python-For-Android Android API is called to
73+
get access to the hardware sensors of the Android device
74+
75+
"""
76+
super(CompassApp, self).__init__(**kwargs)
77+
DisplayMetrics = autoclass('android.util.DisplayMetrics')
78+
metrics = DisplayMetrics()
79+
metrics.setToDefaults()
80+
LoggerDisplayMetrics(metrics)
81+
self.densityDpi = metrics.densityDpi
82+
83+
Hardware = autoclass('org.renpy.android.Hardware')
84+
self.hw = Hardware()
85+
Logger.info('COMPASS: Hardware Objects: %s'%(str(dir(self.hw))))
86+
Logger.info('COMPASS: Hardware Sensors\n%s\n'%(self.hw.getHardwareSensors()))
87+
88+
def viewCompass(self, *largs):
89+
"""
90+
viewCompass calls the readSensor method of the
91+
magneticFieldSensor instance of the generic3AxisSensor, it reads the
92+
3-tuple value of the magnetic field
93+
94+
the declination angle is computed as the angle of the magnetic field
95+
vector in the x,y-plane and the unity-vector of the y-axis.
96+
97+
afterwards the rotateNeedle function rotates the needle as given
98+
by the declination angle parameter
99+
"""
100+
(x, y, z) = self.hw.magneticFieldSensor.readSensor()
101+
declination = Vector(x,y).angle((0,1))
102+
Logger.info('COMPASS: viewCompass x=%s y=%s z=%s declination=%s'%(x,y,z,declination))
103+
self.needle.rotateNeedle(declination)
104+
105+
def stopApp(self,*largs):
106+ 10000
"""
107+
this function is called when pushed the stopButton, disables
108+
the magneticFieldSensor and stops the app
109+
"""
110+
self.hw.magneticFieldSensor.changeStatus(False)
111+
Logger.info('COMPASS: stop largs '+str(largs))
112+
self.stop()
113+
114+
def build(self):
115+
"""
116+
Building all together:
117+
118+
1) Creating the parent widget and clearing it to white background color
119+
120+
2) Defining a suitable position and size of the CompassWidget, the
121+
needleSize and the stopButtonHeight depending on the densityDpi value
122+
given by DisplayMetrics
123+
124+
3) Creating an instance of the CompassWidget and adding it to the
125+
parent widget and calling the appropriate build function
126+
127+
4) Creating an instance of the NeedleWidget and adding it also to the
128+
parent widget and calling the appropriate build function
129+
130+
5) Creating an instance of a Button widget and adding it as stopButton
131+
also to the parent widget and bind it with the stopApp function
132+
133+
6) Calling the instance method changeStatus of the magneticFieldSensor
134+
instance with parameter True to enable the magnetic field sensor
135+
and additionally calling the function schedule_interval of the Clock
136+
class for a repeated call of the function viewCompass every second.
137+
"""
138+
parent = FloatLayout(size=(500,500))
139+
Window.clearcolor = (1, 1, 1, 1)
140+
141+
if self.densityDpi == 240:
142+
CompassPos = Vector(50., 200.)
143+
CompassSize = Vector(400., 400.)
144+
needleSize = Vector(100., 60.)
145+
stopButtonHeight = 60
146+
elif self.densityDpi == 320:
147+
CompassPos = Vector(75., 300.)
148+
CompassSize = Vector(600., 600.)
149+
needleSize = Vector(150., 90.)
150+
stopButtonHeight = 90
151+
else:
152+
Logger.info('COMPASS: widget size should be adopted - minimum used for densityDpi=%s'%(str(self.densityDpi)))
153+
CompassPos = Vector(50., 200.)
154+
CompassSize = Vector(400., 400.)
155+
needleSize = Vector(100., 60.)
156+
stopButtonHeight = 60
157+
158+
self.Compass = CompassWidget()
159+
parent.add_widget(self.Compass)
160+
self.Compass.build(pos=CompassPos,size=CompassSize)
161+
162+
self.needle = NeedleWidget()
163+
parent.add_widget(self.needle)
164+
self.needle.build(center=CompassPos+CompassSize/2.,needleSize=needleSize)
165+
166+
self.stopButton = Button(text='Stop', pos_hint={'right':1}, size_hint=(None,None), height=stopButtonHeight)
167+
parent.add_widget(self.stopButton)
168+
self.stopButton.bind(on_press=self.stopApp)
169+
170+
self.hw.magneticFieldSensor.changeStatus(True)
171+
Clock.schedule_interval(self.viewCompass, 1.)
172+
return parent
173+
174+
If you compile this app, you will get an APK which outputs the following
175+
screen:
176+
177+
.. figure:: Screenshot_Kivy_Kompass.png
178+
:width: 100%
179+
:scale: 60%
180+
:figwidth: 80%
181+
:alt: Screenshot Kivy Compass
182+
183+
Screenshot of the Kivy Compass App
184+
(Source of the Compass Windrose: `Wikipedia <http://en.wikipedia.org/wiki/Compass_rose>`__)
38185

39186

40187
API
@@ -45,41 +192,53 @@ android
45192

46193
.. module:: android
47194

48-
.. function:: check_pause()
49195

50-
This should be called on a regular basis to check to see if Android
51-
expects the game to pause. If it return true, the game should call
52-
:func:`android.wait_for_resume()`, after persisting its state as necessary.
196+
.. function:: vibrate(s)
53197

54-
.. function:: wait_for_resume()
198+
Causes the phone to vibrate for `s` seconds. This requires that your
199+
application have the VIBRATE permission.
55200

56-
This function should be called after :func:`android.check_pause()` returns
57-
true. It does not return until Android has resumed from the pause. While in
58-
this function, Android may kill a game without further notice.
59201

60-
.. function:: map_key(keycode, keysym)
202+
.. function:: getHardwareSensors()
61203

62-
This maps between an android keycode and a python keysym. The android
63-
keycodes are available as constants in the android module.
204+
Returns a string of all hardware sensors of an Android device where each
205+
line lists the informations about one sensor in the following format:
64206

65-
.. function:: vibrate(s)
207+
Name=name,Vendor=vendor,Version=version,MaximumRange=maximumRange,MinDelay=minDelay,Power=power,Type=type
208+
209+
For more information about this informations look into the original Java API
210+
for the `Sensors Class <http://developer.android.com/reference/android/hardware/Sensor.html>`__
211+
212+
.. attribute:: accelerometerSensor
213+
214+
This variable links to a generic3AxisSensor instance and their functions to
215+
access the accelerometer sensor
66216

67-
Causes the phone to vibrate for `s` seconds. This requires that your
68-
application have the VIBRATE permission.
217+
.. attribute:: orientationSensor
69218

70-
.. function:: accelerometer_enable(enable)
219+
This variable links to a generic3AxisSensor instance and their functions to
220+
access the orientation sensor
71221

72-
Enables (if `enable` is true) or disables the device's accelerometer.
222+
.. attribute:: magenticFieldSensor
73223

74-
.. function:: accelerometer_reading()
75224

76-
Returns an (x, y, z) tuple of floats that gives the accelerometer reading,
77-
in meters per second squared. See `this page
78-
<http://developer.android.com/reference/android/hardware/SensorEvent.html>`_
79-
for a description of the coordinate system. The accelerometer must be
80-
enabled before this function is called. If the tuple contains three zero
81-
values, the accelerometer is not enabled, not available, defective, has not
82-
returned a reading, or the device is in free-fall.
225+
The following two instance methods of the generic3AxisSensor class should be
226+
used to enable/disable the sensor and to read the sensor
227+
228+
229+
.. function:: changeStatus(boolean enable)
230+
231+
Changes the status of the sensor, the status of the sensor is enabled,
232+
if `enable` is true or disabled, if `enable` is false.
233+
234+
.. function:: readSensor()
235+
236+
Returns an (x, y, z) tuple of floats that gives the sensor reading,
237+
the units depend on the sensor as shown on the Java API page for `SensorEvent
238+
<http://developer.android.com/reference/android/hardware/SensorEvent.html>`_.
239+
The sesnor must be enabled before this function is called. If the tuple
240+
contains three zero values, the accelerometer is not enabled, not available,
241+
defective, has not returned a reading, or the device is in free-fall.
83242

84243
.. function:: get_dpi()
85244

@@ -95,45 +254,16 @@ android
95254

96255
.. function:: wifi_scanner_enable()
97256

98-
Enables wifi scanning. ACCESS_WIFI_STATE and CHANGE_WIFI_STATE permissions
99-
required.
100-
101-
.. function:: wifi_scan()
102-
103-
Returns tuple of (SSID, BSSID, SignalLevel) for each visible WiFi access
104-
point.
105-
106-
.. function:: action_send(mimetype, filename, subject, text, chooser_title)
257+
Enables wifi scanning.
107258

108-
Deliver data to someone else. This method is a wrapper around `ACTION_SEND
109-
<http://developer.android.com/reference/android/content/Intent.html#ACTION_SEND>`_
259+
.. note:: ACCESS_WIFI_STATE and CHANGE_WIFI_STATE permissions are required.
110260

111-
:Parameters:
112-
`mimetype`: str
113-
Must be a valid mimetype, that represent the content to sent.
114-
`filename`: str, default to None
115-
(optional) Name of the file to attach. Must be a absolute path.
116-
`subject`: str, default to None
117-
(optional) Default subject
118-
`text`: str, default to None
119-
(optional) Content to send.
120-
`chooser_title`: str, default to None
121-
(optional) Title of the android chooser window, default to 'Send email...'
122-
123-
Sending a simple hello world text::
124-
125-
android.action_send('text/plain', text='Hello world',
126-
subject='Test from python')
127-
128-
Sharing an image file::
261+
.. function:: wifi_scan()
129262

130-
# let's say you've make an image in /sdcard/image.png
131-
android.action_send('image/png', filename='/sdcard/image.png')
263+
Returns a String for each visible WiFi access point
132264

133-
Sharing an image with a default text too::
265+
(SSID, BSSID, SignalLevel)
134266

135-
android.action_send('image/png', filename='/sdcard/image.png',
136-
text='Hi,\n\tThis is my awesome image, what do you think about it ?')
137267

138268
android_mixer
139269
~~~~~~~~~~~~~
@@ -185,3 +315,40 @@ It has several differences from the pygame mixer:
185315

186316
The android_mixer module hasn't been tested much, and so bugs may be
187317
present.
318+
319+
320+
How it's working without PyJNIus
321+
--------------------------------
322+
323+
The whole Android API is accessible in Java. Their is no native or extensible
324+
way to access it from Python. The schema for accessing to their API is::
325+
326+
[1] Cython -> [2] C JNI -> [3] Java
327+
328+
#. ``android.pyx`` is written in `Cython <http://cython.org/>`_: a language
329+
with typed informations, very close to Python, that generate Python
330+
extension. It's easier to write in Cython than CPython, and it's linked
331+
directly to the part 2.
332+
#. ``android_jni.c`` is defining simple c methods that access to Java
333+
interfaces using JNI layer.
334+
#. The last part contain the Java code that will be called from the JNI stuff.
335+
336+
All the source code is available at:
337+
338+
https://github.com/kivy/python-for-android/tree/master/recipes/android/src
339+
340+
341+
Example without PyJNIus
342+
-----------------------
343+
344+
::
345+
346+
import android
347+
348+
# activate the vibrator
349+
android.vibrate(1)
350+
351+
# read screen dpi
352+
print android.get_dpi()
353+
354+

0 commit comments

Comments
 (0)
0