-
-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathandroid_location.py
More file actions
126 lines (98 loc) · 4.22 KB
/
android_location.py
File metadata and controls
126 lines (98 loc) · 4.22 KB
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
"""
Copyright (c) 2017-2022, Jairus Martin.
Distributed under the terms of the MIT License.
The full license is in the file LICENSE, distributed with this software.
Created on Sept 5, 2017
"""
from atom.api import List
from .android_content import Context, SystemService
from .app import AndroidApplication
from .bridge import JavaCallback, JavaMethod, JavaProxy
class LocationAccessDenied(RuntimeError):
"""User denied access or it's disabled by the system"""
class LocationManager(SystemService):
SERVICE_TYPE = Context.LOCATION_SERVICE
__nativeclass__ = "android.location.LocationManager"
ACCESS_FINE_PERMISSION = "android.permission.ACCESS_FINE_LOCATION"
ACCESS_COARSE_PERMISSION = "android.permission.ACCESS_COARSE_LOCATION"
GPS_PROVIDER = "gps"
NETWORK_PROVIDER = "network"
PASSIVE_PROVIDER = "passive"
PROVIDERS = {
"gps": GPS_PROVIDER,
"network": NETWORK_PROVIDER,
"passive": PASSIVE_PROVIDER,
}
requestLocationUpdates = JavaMethod(
str, "long", float, "android.location.LocationListener"
)
removeUpdates = JavaMethod("android.location.LocationListener")
class LocationListener(JavaProxy):
__nativeclass__ = "android.location.LocationListener"
# -------------------------------------------------------------------------
# LocationListener API
# -------------------------------------------------------------------------
onLocationChanged = JavaCallback("android.location.Location")
onProviderDisabled = JavaCallback(str)
onProviderEnabled = JavaCallback(str)
onStatusChanged = JavaCallback(str, int, "android.os.Bundle")
#: Active listeners
listeners = List(LocationListener)
@classmethod
async def start(cls, callback, provider="gps", min_time=1000, min_distance=0):
"""Convenience method that checks and requests permission if necessary
and if successful calls the callback with a populated `Location`
instance on updates.
Note you must have the permissions in your manifest or requests
will be denied immediately.
"""
request_fine = provider == "gps"
has_perm = await LocationManager.check_permission(fine=request_fine)
if not has_perm:
has_perm = await LocationManager.request_permission(fine=request_fine)
if not has_perm:
raise RuntimeError("Location permission denied")
mgr = await LocationManager.get()
#: When we have finally have permission
mgr.onLocationChanged.connect(callback)
#: Save a reference to our listener
#: because we may want to stop updates
listener = LocationManager.LocationListener(mgr)
mgr.listeners.append(listener)
mgr.requestLocationUpdates(provider, min_time, min_distance, listener)
@classmethod
def stop(cls):
"""Stops location updates if currently updating."""
manager = LocationManager.instance()
if manager is not None:
for listener in manager.listeners:
manager.removeUpdates(listener)
manager.listeners = []
@classmethod
async def check_permission(cls, fine=True) -> bool:
"""Returns a future that returns a boolean indicating if permission
is currently granted or denied. If permission is denied, you can
request using `LocationManager.request_permission()` below.
"""
app = AndroidApplication.instance()
if fine:
permission = cls.ACCESS_FINE_PERMISSION
else:
permission = cls.ACCESS_COARSE_PERMISSION
return await app.has_permission(permission)
@classmethod
async def request_permission(cls, fine=True) -> bool:
"""Requests permission and returns an async result that returns
a boolean indicating if the permission was granted or denied.
"""
app = AndroidApplication.instance()
if fine:
permission = cls.ACCESS_FINE_PERMISSION
else:
permission = cls.ACCESS_COARSE_PERMISSION
perms = await app.request_permissions(permission)
return perms.get(permission)
def __del__(self):
"""Remove any listeners before destroying"""
self.stop()
super().__del__()