pythonnative 0.35.0__py3-none-any.whl → 0.37.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pythonnative/__init__.py +6 -4
- pythonnative/_ios_log.py +1 -1
- pythonnative/alerts.py +34 -88
- pythonnative/bootstrap.py +90 -0
- pythonnative/bridge/__init__.py +306 -0
- pythonnative/bridge/android.py +78 -0
- pythonnative/bridge/codec.py +164 -0
- pythonnative/bridge/fake.py +236 -0
- pythonnative/bridge/ios.py +138 -0
- pythonnative/cli/pn.py +24 -6
- pythonnative/components/layout.py +65 -3
- pythonnative/gestures.py +13 -10
- pythonnative/hooks.py +41 -26
- pythonnative/hosts/__init__.py +13 -36
- pythonnative/hosts/native.py +348 -0
- pythonnative/images.py +6 -5
- pythonnative/mutations.py +21 -0
- pythonnative/native_modules/__init__.py +30 -29
- pythonnative/native_modules/app_state.py +10 -6
- pythonnative/native_modules/battery.py +20 -84
- pythonnative/native_modules/biometrics.py +11 -124
- pythonnative/native_modules/camera.py +15 -291
- pythonnative/native_modules/clipboard.py +14 -109
- pythonnative/native_modules/desktop.py +322 -0
- pythonnative/native_modules/file_system.py +15 -21
- pythonnative/native_modules/haptics.py +19 -129
- pythonnative/native_modules/linking.py +24 -137
- pythonnative/native_modules/location.py +28 -180
- pythonnative/native_modules/net_info.py +25 -135
- pythonnative/native_modules/notifications.py +36 -257
- pythonnative/native_modules/permissions.py +20 -184
- pythonnative/native_modules/registry.py +513 -0
- pythonnative/native_modules/secure_store.py +18 -155
- pythonnative/native_modules/share.py +8 -113
- pythonnative/native_views/__init__.py +67 -86
- pythonnative/native_views/bridge_backend.py +264 -0
- pythonnative/platform.py +19 -15
- pythonnative/platform_metrics.py +3 -3
- pythonnative/project/android.py +0 -3
- pythonnative/project/builder.py +38 -16
- pythonnative/project/config.py +12 -2
- pythonnative/project/plugins.py +366 -0
- pythonnative/py.typed +0 -0
- pythonnative/runtime.py +35 -203
- pythonnative/sdk/__init__.py +48 -33
- pythonnative/sdk/_components.py +57 -76
- pythonnative/storage.py +18 -243
- pythonnative/templates/android_template/app/build.gradle +6 -9
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +34 -166
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -151
- pythonnative/templates/android_template/pythonnative/build.gradle +48 -0
- pythonnative/templates/android_template/pythonnative/src/main/AndroidManifest.xml +11 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/PNBridge.kt +214 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +249 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +32 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +115 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +35 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +33 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +156 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +87 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +245 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +179 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +97 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +135 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +88 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/Navigator.kt +116 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +223 -0
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
- pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNAccessibilityDelegate.kt +5 -4
- pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNBorderDrawable.kt +12 -3
- pythonnative/templates/android_template/pythonnative/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
- pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNFrameLayout.kt +9 -10
- pythonnative/templates/android_template/{app/src/main/java/com/pythonnative/android_template → pythonnative/src/main/java/com/pythonnative/runtime/views}/PNVirtualListView.java +9 -12
- pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
- pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
- pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
- pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
- pythonnative/templates/android_template/pythonnative/src/test/java/com/pythonnative/runtime/PromiseTest.kt +75 -0
- pythonnative/templates/android_template/settings.gradle +1 -0
- pythonnative/templates/ios_template/PythonNativeKit/Package.swift +21 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Animation/PNAnimator.swift +301 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNBridge.swift +191 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNRegistry.swift +140 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNTransaction.swift +165 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNButtonManagers.swift +206 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNImageManager.swift +221 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTextInputManager.swift +289 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +257 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/HostModule.swift +158 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/PNNativeModule.swift +125 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/PermissionModules.swift +251 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Screens/PNViewController.swift +251 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
- pythonnative/templates/ios_template/PythonNativeKit/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
- pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
- pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
- pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNManagerTests.swift +124 -0
- pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNModuleTests.swift +98 -0
- pythonnative/templates/ios_template/PythonNativeKit/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
- pythonnative/templates/ios_template/ios_template/AppDelegate.swift +8 -50
- pythonnative/templates/ios_template/ios_template/Info.plist +4 -4
- pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +38 -46
- pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +11 -16
- pythonnative/templates/ios_template/ios_template/ViewController.swift +12 -142
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +47 -1
- pythonnative/utils.py +4 -82
- pythonnative/virtual_rows.py +3 -3
- {pythonnative-0.35.0.dist-info → pythonnative-0.37.0.dist-info}/METADATA +3 -5
- pythonnative-0.37.0.dist-info/RECORD +263 -0
- pythonnative/hosts/android.py +0 -269
- pythonnative/hosts/ios.py +0 -404
- pythonnative/native_views/android.py +0 -3702
- pythonnative/native_views/ios.py +0 -5253
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/Navigator.kt +0 -43
- pythonnative-0.35.0.dist-info/RECORD +0 -155
- {pythonnative-0.35.0.dist-info → pythonnative-0.37.0.dist-info}/WHEEL +0 -0
- {pythonnative-0.35.0.dist-info → pythonnative-0.37.0.dist-info}/entry_points.txt +0 -0
- {pythonnative-0.35.0.dist-info → pythonnative-0.37.0.dist-info}/licenses/LICENSE +0 -0
- {pythonnative-0.35.0.dist-info → pythonnative-0.37.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Haptic feedback and raw vibration.
|
|
2
2
|
|
|
3
|
-
Two interfaces live here:
|
|
3
|
+
Two interfaces live here, both backed by the native ``Haptics`` module:
|
|
4
4
|
|
|
5
5
|
- [`Haptics`][pythonnative.Haptics]: semantic, iOS-style feedback
|
|
6
6
|
(impact / notification / selection) backed by
|
|
@@ -17,20 +17,20 @@ than errors.
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
-
from typing import Any
|
|
20
|
+
from typing import Any
|
|
21
21
|
|
|
22
22
|
from .. import diagnostics
|
|
23
|
-
from
|
|
23
|
+
from .registry import native_module
|
|
24
24
|
|
|
25
25
|
ImpactStyle = str # "light" | "medium" | "heavy" | "soft" | "rigid"
|
|
26
26
|
NotificationType = str # "success" | "warning" | "error"
|
|
27
27
|
|
|
28
|
-
_IOS_IMPACT_STYLE = {"light": 0, "medium": 1, "heavy": 2, "soft": 4, "rigid": 5}
|
|
29
|
-
_IOS_NOTIFICATION_TYPE = {"success": 0, "warning": 1, "error": 2}
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
def _call(method: str, **args: Any) -> None:
|
|
30
|
+
try:
|
|
31
|
+
native_module("Haptics").call(method, **args)
|
|
32
|
+
except Exception:
|
|
33
|
+
diagnostics.swallowed(f"haptics.{method}")
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
class Haptics:
|
|
@@ -39,26 +39,17 @@ class Haptics:
|
|
|
39
39
|
@staticmethod
|
|
40
40
|
def impact(style: ImpactStyle = "medium") -> None:
|
|
41
41
|
"""Play a physical "impact" tap of the given ``style``."""
|
|
42
|
-
|
|
43
|
-
_ios_impact(style)
|
|
44
|
-
elif IS_ANDROID:
|
|
45
|
-
_android_buzz(_ANDROID_IMPACT_MS.get(style, 20))
|
|
42
|
+
_call("impact", style=style)
|
|
46
43
|
|
|
47
44
|
@staticmethod
|
|
48
45
|
def notification(type_: NotificationType = "success") -> None:
|
|
49
46
|
"""Play a success / warning / error notification pattern."""
|
|
50
|
-
|
|
51
|
-
_ios_notification(type_)
|
|
52
|
-
elif IS_ANDROID:
|
|
53
|
-
_android_buzz(_ANDROID_NOTIFICATION_MS.get(type_, 30))
|
|
47
|
+
_call("notification", type=type_)
|
|
54
48
|
|
|
55
49
|
@staticmethod
|
|
56
50
|
def selection() -> None:
|
|
57
51
|
"""Play the light "selection changed" tick."""
|
|
58
|
-
|
|
59
|
-
_ios_selection()
|
|
60
|
-
elif IS_ANDROID:
|
|
61
|
-
_android_buzz(8)
|
|
52
|
+
_call("selection")
|
|
62
53
|
|
|
63
54
|
|
|
64
55
|
class Vibration:
|
|
@@ -66,116 +57,15 @@ class Vibration:
|
|
|
66
57
|
|
|
67
58
|
@staticmethod
|
|
68
59
|
def vibrate(duration_ms: int = 400) -> None:
|
|
69
|
-
"""Vibrate for ``duration_ms`` milliseconds.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if duration_ms >= 200:
|
|
77
|
-
_ios_legacy_vibrate()
|
|
78
|
-
else:
|
|
79
|
-
_ios_impact("heavy")
|
|
60
|
+
"""Vibrate for ``duration_ms`` milliseconds.
|
|
61
|
+
|
|
62
|
+
iOS has no arbitrary-duration API; the native module
|
|
63
|
+
approximates short buzzes with a heavy impact and longer ones
|
|
64
|
+
with the legacy system vibration sound.
|
|
65
|
+
"""
|
|
66
|
+
_call("vibrate", duration_ms=int(duration_ms))
|
|
80
67
|
|
|
81
68
|
@staticmethod
|
|
82
69
|
def cancel() -> None:
|
|
83
70
|
"""Cancel an in-progress vibration (Android only)."""
|
|
84
|
-
|
|
85
|
-
vibrator = _android_vibrator()
|
|
86
|
-
if vibrator is not None:
|
|
87
|
-
try:
|
|
88
|
-
vibrator.cancel()
|
|
89
|
-
except Exception:
|
|
90
|
-
diagnostics.swallowed("haptics.Vibration.cancel")
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# ======================================================================
|
|
94
|
-
# iOS
|
|
95
|
-
# ======================================================================
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def _ios_impact(style: str) -> None:
|
|
99
|
-
try:
|
|
100
|
-
from rubicon.objc import ObjCClass
|
|
101
|
-
|
|
102
|
-
generator = ObjCClass("UIImpactFeedbackGenerator").alloc().initWithStyle_(_IOS_IMPACT_STYLE.get(style, 1))
|
|
103
|
-
generator.prepare()
|
|
104
|
-
generator.impactOccurred()
|
|
105
|
-
except Exception:
|
|
106
|
-
diagnostics.swallowed("haptics._ios_impact")
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
def _ios_notification(type_: str) -> None:
|
|
110
|
-
try:
|
|
111
|
-
from rubicon.objc import ObjCClass
|
|
112
|
-
|
|
113
|
-
generator = ObjCClass("UINotificationFeedbackGenerator").alloc().init()
|
|
114
|
-
generator.prepare()
|
|
115
|
-
generator.notificationOccurred_(_IOS_NOTIFICATION_TYPE.get(type_, 0))
|
|
116
|
-
except Exception:
|
|
117
|
-
diagnostics.swallowed("haptics._ios_notification")
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def _ios_selection() -> None:
|
|
121
|
-
try:
|
|
122
|
-
from rubicon.objc import ObjCClass
|
|
123
|
-
|
|
124
|
-
generator = ObjCClass("UISelectionFeedbackGenerator").alloc().init()
|
|
125
|
-
generator.prepare()
|
|
126
|
-
generator.selectionChanged()
|
|
127
|
-
except Exception:
|
|
128
|
-
diagnostics.swallowed("haptics._ios_selection")
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
def _ios_legacy_vibrate() -> None:
|
|
132
|
-
try:
|
|
133
|
-
from ctypes import CDLL, util
|
|
134
|
-
|
|
135
|
-
audio = CDLL(util.find_library("AudioToolbox"))
|
|
136
|
-
audio.AudioServicesPlaySystemSound(4095) # kSystemSoundID_Vibrate
|
|
137
|
-
except Exception:
|
|
138
|
-
diagnostics.swallowed("haptics._ios_legacy_vibrate")
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
# ======================================================================
|
|
142
|
-
# Android
|
|
143
|
-
# ======================================================================
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def _android_vibrator() -> Optional[Any]:
|
|
147
|
-
try:
|
|
148
|
-
from java import jclass
|
|
149
|
-
|
|
150
|
-
from ..utils import get_android_context
|
|
151
|
-
|
|
152
|
-
ctx = get_android_context()
|
|
153
|
-
Build = jclass("android.os.Build")
|
|
154
|
-
if Build.VERSION.SDK_INT >= 31:
|
|
155
|
-
VibratorManager = jclass("android.os.VibratorManager")
|
|
156
|
-
Context = jclass("android.content.Context")
|
|
157
|
-
manager = ctx.getSystemService(Context.VIBRATOR_MANAGER_SERVICE)
|
|
158
|
-
VibratorManager # referenced for clarity
|
|
159
|
-
return manager.getDefaultVibrator()
|
|
160
|
-
Context = jclass("android.content.Context")
|
|
161
|
-
return ctx.getSystemService(Context.VIBRATOR_SERVICE)
|
|
162
|
-
except Exception:
|
|
163
|
-
return None
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def _android_buzz(duration_ms: int) -> None:
|
|
167
|
-
vibrator = _android_vibrator()
|
|
168
|
-
if vibrator is None:
|
|
169
|
-
return
|
|
170
|
-
try:
|
|
171
|
-
from java import jclass
|
|
172
|
-
|
|
173
|
-
Build = jclass("android.os.Build")
|
|
174
|
-
if Build.VERSION.SDK_INT >= 26:
|
|
175
|
-
VibrationEffect = jclass("android.os.VibrationEffect")
|
|
176
|
-
effect = VibrationEffect.createOneShot(int(duration_ms), VibrationEffect.DEFAULT_AMPLITUDE)
|
|
177
|
-
vibrator.vibrate(effect)
|
|
178
|
-
else:
|
|
179
|
-
vibrator.vibrate(int(duration_ms))
|
|
180
|
-
except Exception:
|
|
181
|
-
diagnostics.swallowed("haptics._android_buzz")
|
|
71
|
+
_call("cancel")
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
"""Open URLs, deep links, and the system settings page.
|
|
2
2
|
|
|
3
3
|
[`Linking`][pythonnative.Linking] wraps ``UIApplication.openURL`` /
|
|
4
|
-
``Intent(ACTION_VIEW)``
|
|
5
|
-
``mailto:``, ``tel:``, a custom
|
|
4
|
+
``Intent(ACTION_VIEW)`` (in the native ``Linking`` module) so a Python
|
|
5
|
+
app can hand a URL (``https:``, ``mailto:``, ``tel:``, a custom
|
|
6
|
+
scheme, ...) to the OS.
|
|
6
7
|
|
|
7
8
|
Outbound methods are synchronous and return a ``bool`` describing
|
|
8
9
|
whether the platform accepted the request. On desktop they return
|
|
9
10
|
``False``.
|
|
10
11
|
|
|
11
12
|
Inbound deep links flow the other way: declare your schemes in
|
|
12
|
-
``pythonnative.toml`` (``app.url_schemes``) and the native
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
with
|
|
13
|
+
``pythonnative.toml`` (``app.url_schemes``) and the native module
|
|
14
|
+
pushes a ``url`` event for every URL that opens the app, which lands in
|
|
15
|
+
[`dispatch_url`][pythonnative.native_modules.linking.dispatch_url]. The
|
|
16
|
+
URL that cold-started the app is kept and returned by
|
|
17
|
+
``get_initial_url``; later URLs reach subscribers added with
|
|
18
|
+
``add_listener``.
|
|
17
19
|
|
|
18
20
|
Example:
|
|
19
21
|
```python
|
|
@@ -30,43 +32,36 @@ from __future__ import annotations
|
|
|
30
32
|
|
|
31
33
|
from typing import Any, Callable, List, Optional
|
|
32
34
|
|
|
33
|
-
from
|
|
35
|
+
from .registry import native_module, on_event
|
|
34
36
|
|
|
35
|
-
# Populated by the native host when the app is launched from a deep
|
|
36
|
-
# link; ``get_initial_url`` returns it.
|
|
37
37
|
_initial_url: Optional[str] = None
|
|
38
38
|
_url_listeners: List[Callable[[str], None]] = []
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
def _call_bool(method: str, **args: Any) -> bool:
|
|
42
|
+
try:
|
|
43
|
+
return bool(native_module("Linking").call(method, **args))
|
|
44
|
+
except Exception:
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
|
|
41
48
|
class Linking:
|
|
42
49
|
"""System URL / deep-link interface (synchronous)."""
|
|
43
50
|
|
|
44
51
|
@staticmethod
|
|
45
52
|
def open_url(url: str) -> bool:
|
|
46
53
|
"""Hand ``url`` to the OS. Returns ``True`` if it was accepted."""
|
|
47
|
-
|
|
48
|
-
return _ios_open(url)
|
|
49
|
-
if IS_ANDROID:
|
|
50
|
-
return _android_open(url)
|
|
51
|
-
return False
|
|
54
|
+
return _call_bool("open_url", url=url)
|
|
52
55
|
|
|
53
56
|
@staticmethod
|
|
54
57
|
def can_open_url(url: str) -> bool:
|
|
55
58
|
"""Return ``True`` when some installed app can handle ``url``."""
|
|
56
|
-
|
|
57
|
-
return _ios_can_open(url)
|
|
58
|
-
if IS_ANDROID:
|
|
59
|
-
return _android_can_open(url)
|
|
60
|
-
return False
|
|
59
|
+
return _call_bool("can_open_url", url=url)
|
|
61
60
|
|
|
62
61
|
@staticmethod
|
|
63
62
|
def open_settings() -> bool:
|
|
64
63
|
"""Open this app's entry in the system Settings app."""
|
|
65
|
-
|
|
66
|
-
return _ios_open_settings()
|
|
67
|
-
if IS_ANDROID:
|
|
68
|
-
return _android_open_settings()
|
|
69
|
-
return False
|
|
64
|
+
return _call_bool("open_settings")
|
|
70
65
|
|
|
71
66
|
@staticmethod
|
|
72
67
|
def get_initial_url() -> Optional[str]:
|
|
@@ -97,18 +92,17 @@ class Linking:
|
|
|
97
92
|
|
|
98
93
|
|
|
99
94
|
def set_initial_url(url: Optional[str]) -> None:
|
|
100
|
-
"""Record the launch URL (
|
|
95
|
+
"""Record the launch URL (or clear it with ``None``)."""
|
|
101
96
|
global _initial_url
|
|
102
97
|
_initial_url = url
|
|
103
98
|
|
|
104
99
|
|
|
105
100
|
def dispatch_url(url: str) -> None:
|
|
106
|
-
"""Deliver an inbound deep link
|
|
101
|
+
"""Deliver an inbound deep link.
|
|
107
102
|
|
|
108
103
|
The first URL ever dispatched is also recorded as the initial URL
|
|
109
104
|
(a cold start from a deep link reaches Python only after the
|
|
110
|
-
interpreter boots, so
|
|
111
|
-
earlier than this).
|
|
105
|
+
interpreter boots, so native can't report it earlier than this).
|
|
112
106
|
|
|
113
107
|
Args:
|
|
114
108
|
url: The full URL string that opened the app.
|
|
@@ -125,111 +119,4 @@ def dispatch_url(url: str) -> None:
|
|
|
125
119
|
diagnostics.warn(f"Linking listener raised while handling {url!r}: {exc!r}")
|
|
126
120
|
|
|
127
121
|
|
|
128
|
-
|
|
129
|
-
# iOS
|
|
130
|
-
# ======================================================================
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def _ios_url(url: str) -> Optional[Any]:
|
|
134
|
-
try:
|
|
135
|
-
from rubicon.objc import ObjCClass
|
|
136
|
-
|
|
137
|
-
return ObjCClass("NSURL").URLWithString_(url)
|
|
138
|
-
except Exception:
|
|
139
|
-
return None
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def _ios_open(url: str) -> bool:
|
|
143
|
-
nsurl = _ios_url(url)
|
|
144
|
-
if nsurl is None:
|
|
145
|
-
return False
|
|
146
|
-
try:
|
|
147
|
-
from rubicon.objc import ObjCClass
|
|
148
|
-
|
|
149
|
-
app = ObjCClass("UIApplication").sharedApplication
|
|
150
|
-
if app.canOpenURL_(nsurl):
|
|
151
|
-
app.openURL_options_completionHandler_(nsurl, None, None)
|
|
152
|
-
return True
|
|
153
|
-
return False
|
|
154
|
-
except Exception:
|
|
155
|
-
return False
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def _ios_can_open(url: str) -> bool:
|
|
159
|
-
nsurl = _ios_url(url)
|
|
160
|
-
if nsurl is None:
|
|
161
|
-
return False
|
|
162
|
-
try:
|
|
163
|
-
from rubicon.objc import ObjCClass
|
|
164
|
-
|
|
165
|
-
return bool(ObjCClass("UIApplication").sharedApplication.canOpenURL_(nsurl))
|
|
166
|
-
except Exception:
|
|
167
|
-
return False
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
def _ios_open_settings() -> bool:
|
|
171
|
-
try:
|
|
172
|
-
from rubicon.objc import ObjCClass
|
|
173
|
-
|
|
174
|
-
settings = ObjCClass("UIApplicationOpenSettingsURLString")
|
|
175
|
-
return _ios_open(str(settings))
|
|
176
|
-
except Exception:
|
|
177
|
-
try:
|
|
178
|
-
return _ios_open("app-settings:")
|
|
179
|
-
except Exception:
|
|
180
|
-
return False
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
# ======================================================================
|
|
184
|
-
# Android
|
|
185
|
-
# ======================================================================
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def _android_open(url: str) -> bool:
|
|
189
|
-
try:
|
|
190
|
-
from java import jclass
|
|
191
|
-
|
|
192
|
-
from ..utils import get_android_context
|
|
193
|
-
|
|
194
|
-
Intent = jclass("android.content.Intent")
|
|
195
|
-
Uri = jclass("android.net.Uri")
|
|
196
|
-
intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
|
197
|
-
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
198
|
-
get_android_context().startActivity(intent)
|
|
199
|
-
return True
|
|
200
|
-
except Exception:
|
|
201
|
-
return False
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
def _android_can_open(url: str) -> bool:
|
|
205
|
-
try:
|
|
206
|
-
from java import jclass
|
|
207
|
-
|
|
208
|
-
from ..utils import get_android_context
|
|
209
|
-
|
|
210
|
-
Intent = jclass("android.content.Intent")
|
|
211
|
-
Uri = jclass("android.net.Uri")
|
|
212
|
-
intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
|
213
|
-
pm = get_android_context().getPackageManager()
|
|
214
|
-
return intent.resolveActivity(pm) is not None
|
|
215
|
-
except Exception:
|
|
216
|
-
return False
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def _android_open_settings() -> bool:
|
|
220
|
-
try:
|
|
221
|
-
from java import jclass
|
|
222
|
-
|
|
223
|
-
from ..utils import get_android_context
|
|
224
|
-
|
|
225
|
-
Intent = jclass("android.content.Intent")
|
|
226
|
-
Settings = jclass("android.provider.Settings")
|
|
227
|
-
Uri = jclass("android.net.Uri")
|
|
228
|
-
ctx = get_android_context()
|
|
229
|
-
intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
|
230
|
-
intent.setData(Uri.fromParts("package", ctx.getPackageName(), None))
|
|
231
|
-
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
232
|
-
ctx.startActivity(intent)
|
|
233
|
-
return True
|
|
234
|
-
except Exception:
|
|
235
|
-
return False
|
|
122
|
+
on_event("Linking", "url", lambda payload: dispatch_url(str(payload)))
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
[`Location.get_current`][pythonnative.native_modules.location.Location.get_current]
|
|
4
4
|
is a coroutine that resolves to a ``(latitude, longitude)`` tuple, or
|
|
5
5
|
``None`` if no recent fix is available or the user denies permission.
|
|
6
|
+
The native ``Location`` module owns the ``CLLocationManager`` /
|
|
7
|
+
``LocationManager`` session and resolves the call with
|
|
8
|
+
``{"latitude", "longitude", "accuracy", "altitude", "timestamp"}``.
|
|
6
9
|
|
|
7
10
|
Permission prompts are triggered the first time a location-using API
|
|
8
11
|
is called; ensure the appropriate manifest entries
|
|
@@ -24,16 +27,9 @@ Example:
|
|
|
24
27
|
|
|
25
28
|
from __future__ import annotations
|
|
26
29
|
|
|
27
|
-
import
|
|
28
|
-
from typing import Any, Callable, Dict, Optional, Tuple
|
|
30
|
+
from typing import Any, Dict, Optional, Tuple
|
|
29
31
|
|
|
30
|
-
from
|
|
31
|
-
from ..runtime import resolve_future
|
|
32
|
-
from ..utils import IS_ANDROID, IS_IOS
|
|
33
|
-
|
|
34
|
-
# Retain pool keyed by ``id(delegate)`` so iOS / Android listeners
|
|
35
|
-
# aren't garbage-collected before the platform calls back.
|
|
36
|
-
_pending_delegates: Dict[int, Any] = {}
|
|
32
|
+
from .registry import native_module
|
|
37
33
|
|
|
38
34
|
Coords = Tuple[float, float]
|
|
39
35
|
|
|
@@ -46,184 +42,36 @@ class Location:
|
|
|
46
42
|
"""Request the device's current location.
|
|
47
43
|
|
|
48
44
|
Args:
|
|
49
|
-
**options:
|
|
50
|
-
``
|
|
45
|
+
**options: Forwarded to the native module (``accuracy``,
|
|
46
|
+
``timeout``). Unknown keys are ignored.
|
|
51
47
|
|
|
52
48
|
Returns:
|
|
53
49
|
``(latitude, longitude)`` if a fix was obtained, otherwise
|
|
54
50
|
``None``.
|
|
55
51
|
"""
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def _on_result(coords: Optional[Coords]) -> None:
|
|
61
|
-
resolve_future(future, coords)
|
|
62
|
-
|
|
63
|
-
if IS_ANDROID:
|
|
64
|
-
_android_get(_on_result)
|
|
65
|
-
elif IS_IOS:
|
|
66
|
-
_ios_get(_on_result)
|
|
67
|
-
else:
|
|
68
|
-
resolve_future(future, None)
|
|
69
|
-
|
|
70
|
-
return await future
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# ======================================================================
|
|
74
|
-
# iOS implementation: CLLocationManagerDelegate
|
|
75
|
-
# ======================================================================
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def _ios_get(on_result: Callable[[Optional[Coords]], None]) -> None:
|
|
79
|
-
try:
|
|
80
|
-
from rubicon.objc import ObjCClass, objc_method
|
|
81
|
-
|
|
82
|
-
CLLocationManager = ObjCClass("CLLocationManager")
|
|
83
|
-
NSObject = ObjCClass("NSObject")
|
|
52
|
+
fix = await Location.get_current_fix(**options)
|
|
53
|
+
if fix is None:
|
|
54
|
+
return None
|
|
55
|
+
return (fix["latitude"], fix["longitude"])
|
|
84
56
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
_delivered: bool = False
|
|
89
|
-
|
|
90
|
-
def _finish(self, coords: Optional[Coords]) -> None:
|
|
91
|
-
if self._delivered:
|
|
92
|
-
return
|
|
93
|
-
self._delivered = True
|
|
94
|
-
try:
|
|
95
|
-
if self._manager is not None:
|
|
96
|
-
self._manager.stopUpdatingLocation()
|
|
97
|
-
except Exception:
|
|
98
|
-
diagnostics.swallowed("location._ios_get._PNLocationDelegate._finish")
|
|
99
|
-
cb = self._callback
|
|
100
|
-
self._callback = None
|
|
101
|
-
_pending_delegates.pop(id(self), None)
|
|
102
|
-
if cb is not None:
|
|
103
|
-
try:
|
|
104
|
-
cb(coords)
|
|
105
|
-
except Exception:
|
|
106
|
-
diagnostics.swallowed("location._ios_get._PNLocationDelegate._finish")
|
|
107
|
-
|
|
108
|
-
@objc_method
|
|
109
|
-
def locationManager_didUpdateLocations_(self, manager: Any, locations: Any) -> None:
|
|
110
|
-
del manager
|
|
111
|
-
try:
|
|
112
|
-
last = locations.lastObject
|
|
113
|
-
if last is None:
|
|
114
|
-
return
|
|
115
|
-
coord = last.coordinate
|
|
116
|
-
self._finish((float(coord.latitude), float(coord.longitude)))
|
|
117
|
-
except Exception:
|
|
118
|
-
self._finish(None)
|
|
119
|
-
|
|
120
|
-
@objc_method
|
|
121
|
-
def locationManager_didFailWithError_(self, manager: Any, error: Any) -> None:
|
|
122
|
-
del manager, error
|
|
123
|
-
self._finish(None)
|
|
124
|
-
|
|
125
|
-
@objc_method
|
|
126
|
-
def locationManagerDidChangeAuthorization_(self, manager: Any) -> None:
|
|
127
|
-
try:
|
|
128
|
-
status = int(manager.authorizationStatus)
|
|
129
|
-
except Exception:
|
|
130
|
-
status = 0
|
|
131
|
-
if status in (3, 4): # AuthorizedAlways, AuthorizedWhenInUse
|
|
132
|
-
try:
|
|
133
|
-
manager.startUpdatingLocation()
|
|
134
|
-
except Exception:
|
|
135
|
-
diagnostics.swallowed(
|
|
136
|
-
"location._ios_get._PNLocationDelegate.locationManagerDidChangeAuthorization_"
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
delegate = _PNLocationDelegate.new()
|
|
140
|
-
delegate._callback = on_result
|
|
141
|
-
_pending_delegates[id(delegate)] = delegate
|
|
142
|
-
|
|
143
|
-
manager = CLLocationManager.alloc().init()
|
|
144
|
-
manager.setDelegate_(delegate)
|
|
145
|
-
delegate._manager = manager
|
|
146
|
-
try:
|
|
147
|
-
manager.requestWhenInUseAuthorization()
|
|
148
|
-
except Exception:
|
|
149
|
-
diagnostics.swallowed("location._ios_get")
|
|
150
|
-
try:
|
|
151
|
-
manager.startUpdatingLocation()
|
|
152
|
-
except Exception:
|
|
153
|
-
diagnostics.swallowed("location._ios_get")
|
|
154
|
-
except Exception:
|
|
155
|
-
on_result(None)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
# ======================================================================
|
|
159
|
-
# Android implementation: LocationListener
|
|
160
|
-
# ======================================================================
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def _android_get(on_result: Callable[[Optional[Coords]], None]) -> None:
|
|
164
|
-
try:
|
|
165
|
-
from java import dynamic_proxy, jclass
|
|
166
|
-
|
|
167
|
-
from ..utils import get_android_context
|
|
168
|
-
|
|
169
|
-
ctx = get_android_context()
|
|
170
|
-
Context = jclass("android.content.Context")
|
|
171
|
-
lm = ctx.getSystemService(Context.LOCATION_SERVICE)
|
|
57
|
+
@staticmethod
|
|
58
|
+
async def get_current_fix(**options: Any) -> Optional[Dict[str, float]]:
|
|
59
|
+
"""Like ``get_current`` but returns the full fix dict.
|
|
172
60
|
|
|
173
|
-
|
|
174
|
-
|
|
61
|
+
Keys: ``latitude``, ``longitude``, and when the platform reports
|
|
62
|
+
them ``accuracy`` (meters), ``altitude`` (meters), ``speed``
|
|
63
|
+
(m/s), ``heading`` (degrees), ``timestamp`` (Unix seconds).
|
|
64
|
+
"""
|
|
175
65
|
try:
|
|
176
|
-
|
|
177
|
-
loc = lm.getLastKnownLocation(provider)
|
|
178
|
-
if loc is not None:
|
|
179
|
-
on_result((float(loc.getLatitude()), float(loc.getLongitude())))
|
|
180
|
-
return
|
|
66
|
+
result = await native_module("Location").call_async("get_current", **options)
|
|
181
67
|
except Exception:
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
delivered = [False]
|
|
186
|
-
|
|
187
|
-
def _finish(coords: Optional[Coords], listener: Any) -> None:
|
|
188
|
-
if delivered[0]:
|
|
189
|
-
return
|
|
190
|
-
delivered[0] = True
|
|
191
|
-
try:
|
|
192
|
-
lm.removeUpdates(listener)
|
|
193
|
-
except Exception:
|
|
194
|
-
diagnostics.swallowed("location._android_get._finish")
|
|
195
|
-
_pending_delegates.pop(id(listener), None)
|
|
196
|
-
try:
|
|
197
|
-
on_result(coords)
|
|
198
|
-
except Exception:
|
|
199
|
-
diagnostics.swallowed("location._android_get._finish")
|
|
200
|
-
|
|
201
|
-
class _PNLocationListener(dynamic_proxy(LocationListener)): # type: ignore[misc]
|
|
202
|
-
def onLocationChanged(self, loc: Any) -> None:
|
|
203
|
-
try:
|
|
204
|
-
coords = (float(loc.getLatitude()), float(loc.getLongitude()))
|
|
205
|
-
except Exception:
|
|
206
|
-
coords = None
|
|
207
|
-
_finish(coords, self)
|
|
208
|
-
|
|
209
|
-
def onStatusChanged(self, provider: Any, status: int, extras: Any) -> None:
|
|
210
|
-
del provider, status, extras
|
|
211
|
-
|
|
212
|
-
def onProviderEnabled(self, provider: Any) -> None:
|
|
213
|
-
del provider
|
|
214
|
-
|
|
215
|
-
def onProviderDisabled(self, provider: Any) -> None:
|
|
216
|
-
del provider
|
|
217
|
-
_finish(None, self)
|
|
218
|
-
|
|
219
|
-
listener = _PNLocationListener()
|
|
220
|
-
_pending_delegates[id(listener)] = listener
|
|
68
|
+
return None
|
|
69
|
+
if not isinstance(result, dict):
|
|
70
|
+
return None
|
|
221
71
|
try:
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
except Exception:
|
|
229
|
-
on_result(None)
|
|
72
|
+
fix: Dict[str, float] = {k: float(v) for k, v in result.items() if v is not None}
|
|
73
|
+
fix["latitude"]
|
|
74
|
+
fix["longitude"]
|
|
75
|
+
except (KeyError, TypeError, ValueError):
|
|
76
|
+
return None
|
|
77
|
+
return fix
|