from kivy.app import App from kivy.clock import Clock from kivy.uix.screenmanager import ScreenManager, Screen, RiseInTransition from kivy.properties import NumericProperty, StringProperty from kivy.lang import Builder from kivy_garden.mapview import MapView from plyer import gps from kivy.clock import mainthread from kivy.utils import platform from kivy.vector import Vector from kivy.animation import Animation from math import floor class MapScreen(Screen): hue = NumericProperty(0) mapview = MapView(zoom=11, lat=50.6394, lon=3.057) class CompassScreen(Screen): hue = NumericProperty(0) x_calib = NumericProperty(0) y_calib = NumericProperty(0) z_calib = NumericProperty(0) needle_angle = NumericProperty(0) def enable(self): self.facade.enable() Clock.schedule_interval(self.get_field, 1 / 20.) gps.start(1000, 0) def disable(self): self.facade.disable() Clock.unschedule(self.get_field) def get_field(self, dt): needle_angle = 7 if self.facade.field != (None, None, None): self.x_calib, self.y_calib, self.z_calib = self.facade.field x, y, z = self.facade.field needle_angle = Vector(x, y).angle((0, 1)) + 90. # fix animation transition around the unit circle if (self.needle_angle % 360) - needle_angle > 180: needle_angle += 360 elif (self.needle_angle % 360) - needle_angle < -180: needle_angle -= 360 # add the number of revolutions to the result needle_angle += 360 * floor(self.needle_angle / 360.) # animate the needle if self._anim: self._anim.stop(self) self._anim = Animation(needle_angle=needle_angle, d=.2, t='out_quad') self._anim.start(self) class FlockompassApp(App): gps_location = StringProperty() gps_status = StringProperty('Click Start to get GPS location updates') def request_android_permissions(self): from android.permissions import request_permissions, Permission def callback(permissions, results): if all([res for res in results]): print("callback. All permissions granted.") else: print("callback. Some permissions refused.") request_permissions([Permission.ACCESS_COARSE_LOCATION, Permission.ACCESS_FINE_LOCATION], callback) def start(self, minTime, minDistance): gps.start(minTime, minDistance) def stop(self): gps.stop() def on_pause(self): gps.stop() return True def on_resume(self): gps.start(1000, 0) @mainthread def on_location(self, **kwargs): self.gps_location = '\n'.join([ '{}={}'.format(k, v) for k, v in kwargs.items()]) @mainthread def on_status(self, stype, status): self.gps_status = 'type={}\n{}'.format(stype, status) def build(self): try: gps.configure(on_location=self.on_location, on_status=self.on_status) except NotImplementedError: import traceback traceback.print_exc() self.gps_status = 'GPS is not implemented for your platform' if platform == "android": print("gps.py: Android detected. Requesting permissions") self.request_android_permissions() root = ScreenManager(transition=RiseInTransition()) root.add_widget(MapScreen(name='map')) cs = CompassScreen(name='compass') cs._anim = None root.add_widget(cs) return root if __name__ == '__main__': FlockompassApp().run() # Button: # text: 'Use FallOutTransition' # on_release: root.manager.transition = FallOutTransition() # Button: # text: 'Use RiseInTransition' # on_release: root.manager.transition = RiseInTransition()