/usr/share/kivi-examples/android/compass/main.py is in python-kivy-examples 1.7.2-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | import kivy
kivy.require('1.3.0')
import math
import time
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.uix.scatter import Scatter
from kivy.clock import Clock
from kivy.vector import Vector
from kivy.core.window import Window
from kivy.graphics import Color, Ellipse, Rectangle, Triangle
from kivy.logger import Logger
from jnius import autoclass
Logger.info('COMPASS: STARTED')
def LoggerDisplayMetrics(metrics):
"""
Logging all values of the Java Android DisplayMetrics class
to get some more information about the metrics of Android devices
"""
display = {'Default':metrics.DENSITY_DEFAULT,
'Device':metrics.DENSITY_DEVICE,
'High':metrics.DENSITY_HIGH,
'Low':metrics.DENSITY_LOW,
'Medium':metrics.DENSITY_MEDIUM,
'XHIGH':metrics.DENSITY_XHIGH,
'density':metrics.density,
'densityDpi':metrics.densityDpi,
'heightPixels':metrics.heightPixels,
'scaledDensity':metrics.scaledDensity,
'widthPixels':metrics.widthPixels,
'xdpi':metrics.xdpi,
'ydpi':metrics.ydpi}
for (k,v) in display.items():
Logger.info('COMPASS: display %s = %s'%(k,v))
class CompassWidget(FloatLayout):
def __init__(self, **kwargs):
"""
Constructor of the CompassWidget class
"""
super(CompassWidget, self).__init__(**kwargs)
def build(self,pos,size):
"""
building the background of the CompassWidget with a circle of a
compass windrose image
(Source of this image: Wikipedia - http://en.wikipedia.org/wiki/Compass_rose)
"""
with self.canvas:
self.pos = pos
self.size = size
self.windrose = Ellipse(source="500px-Windrose.svg.png", pos=pos, size=size)
class NeedleWidget(Scatter):
def __init__(self, **kwargs):
"""
Constructor of the NeedleWidget class
do_rotation, do_translation, do_scale are all set to False
to indicate that the scatter widget can onlybe updated from the
app and not by an interaction with your fingers
"""
super(NeedleWidget, self).__init__(**kwargs)
self.do_rotation = False
self.do_translation = False
self.do_scale = False
self.auto_bring_to_front = True
def rotateNeedle(self,angle):
"""
rotate the NeedleWidget with the parameter angle
90 is subtracted because North of the windrose is at 90 degrees
of the device
"""
self.rotation = angle - 90
def build(self,center,needleSize):
"""
building the needle with two Triangles of different color
"""
self.pos = center - needleSize/2.
self.size = needleSize
self.size_hint = [None, None]
with self.canvas:
Color(1., 0, 0)
needleTP1 = Vector(needleSize[0]/2.,needleSize[1])
needleTP2 = Vector(needleSize[0]/2.,0)
needleTP3 = Vector(-needleSize[0],needleSize[1]/2.)
needlePoints = (needleTP1[0],needleTP1[1],
needleTP2[0],needleTP2[1],
needleTP3[0],needleTP3[1])
self.needleT1 = Triangle(points=needlePoints)
Color(0.5, 0.5, 0.5)
needleTP3 = Vector(2*needleSize[0],needleSize[1]/2.)
needlePoints = (needleTP1[0],needleTP1[1],
needleTP2[0],needleTP2[1],
needleTP3[0],needleTP3[1])
self.needleT2 = Triangle(points=needlePoints)
class CompassApp(App):
def __init__(self, **kwargs):
"""
Constructor of the Compass App
1) The Java Android API DisplayMetrics is called to get
information about the densityDpi factor of the Android device
2) The Kivy Python-For-Android Android API is called to
get access to the hardware sensors of the Android device
"""
super(CompassApp, self).__init__(**kwargs)
DisplayMetrics = autoclass('android.util.DisplayMetrics')
metrics = DisplayMetrics()
metrics.setToDefaults()
LoggerDisplayMetrics(metrics)
self.densityDpi = metrics.densityDpi
Hardware = autoclass('org.renpy.android.Hardware')
self.hw = Hardware()
Logger.info('COMPASS: Hardware Objects: %s'%(str(dir(self.hw))))
Logger.info('COMPASS: Hardware Sensors\n%s\n'%(self.hw.getHardwareSensors()))
def viewCompass(self, *largs):
"""
viewCompass calls the readSensor method of the
magneticFieldSensor instance of the generic3AxisSensor, it reads the
3-tuple value of the magnetic field
the declination angle is computed as the angle of the magnetic field
vector in the x,y-plane and the unity-vector of the y-axis.
afterwards the rotateNeedle function rotates the needle as given
by the declination angle parameter
"""
(x, y, z) = self.hw.magneticFieldSensor.readSensor()
declination = Vector(x,y).angle((0,1))
#Logger.info('COMPASS: viewCompass x=%s y=%s z=%s declination=%s'%(x,y,z,declination))
self.needle.rotateNeedle(declination)
def stopApp(self,*largs):
"""
this function is called when pushed the stopButton, disables
the magneticFieldSensor and stops the app
"""
self.hw.magneticFieldSensor.changeStatus(False)
Logger.info('COMPASS: stop largs '+str(largs))
self.stop()
def build(self):
"""
Building all together:
1) Creating the parent widget and clearing it to white background color
2) Defining a suitable position and size of the CompassWidget, the
needleSize and the stopButtonHeight depending on the densityDpi value
given by DisplayMetrics
3) Creating an instance of the CompassWidget and adding it to the
parent widget and calling the appropriate build function
4) Creating an instance of the NeedleWidget and adding it also to the
parent widget and calling the appropriate build function
5) Creating an instance of a Button widget and adding it as stopButton
also to the parent widget and bind it with the stopApp function
6) Calling the instance method changeStatus of the magneticFieldSensor
instance with parameter True to enable the magnetic field sensor
and additionally calling the function schedule_interval of the Clock
class for a repeated call of the function viewCompass every second.
"""
parent = FloatLayout(size=(500,500))
Window.clearcolor = (1, 1, 1, 1)
if self.densityDpi == 240:
CompassPos = Vector(50., 200.)
CompassSize = Vector(400., 400.)
needleSize = Vector(100., 60.)
stopButtonHeight = 60
elif self.densityDpi == 320:
CompassPos = Vector(75., 300.)
CompassSize = Vector(600., 600.)
needleSize = Vector(150., 90.)
stopButtonHeight = 90
else:
Logger.info('COMPASS: widget size should be adopted - minimum used for densityDpi=%s'%(str(self.densityDpi)))
CompassPos = Vector(50., 200.)
CompassSize = Vector(400., 400.)
needleSize = Vector(100., 60.)
stopButtonHeight = 60
self.Compass = CompassWidget()
parent.add_widget(self.Compass)
self.Compass.build(pos=CompassPos,size=CompassSize)
self.needle = NeedleWidget()
parent.add_widget(self.needle)
self.needle.build(center=CompassPos+CompassSize/2.,needleSize=needleSize)
self.stopButton = Button(text='Stop', pos_hint={'right':1}, size_hint=(None,None), height=stopButtonHeight)
parent.add_widget(self.stopButton)
self.stopButton.bind(on_press=self.stopApp)
self.hw.magneticFieldSensor.changeStatus(True)
Clock.schedule_interval(self.viewCompass, 1.)
return parent
if __name__ in ('__main__', '__android__'):
CompassApp().run()
|