pythonnative 0.40.0__cp313-cp313-win_amd64.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 +411 -0
- pythonnative/_ios_log.py +92 -0
- pythonnative/_yoga.cp313-win_amd64.pyd +0 -0
- pythonnative/alerts.py +236 -0
- pythonnative/animated.py +1687 -0
- pythonnative/animation_graph.py +78 -0
- pythonnative/appearance.py +124 -0
- pythonnative/bootstrap.py +100 -0
- pythonnative/bridge/__init__.py +302 -0
- pythonnative/bridge/android.py +78 -0
- pythonnative/bridge/codec.py +170 -0
- pythonnative/bridge/commits.py +114 -0
- pythonnative/bridge/fake.py +243 -0
- pythonnative/bridge/ios.py +138 -0
- pythonnative/bridge/web.py +489 -0
- pythonnative/cli/__init__.py +7 -0
- pythonnative/cli/pn.py +1214 -0
- pythonnative/component.py +271 -0
- pythonnative/components/__init__.py +111 -0
- pythonnative/components/_base.py +166 -0
- pythonnative/components/controls.py +521 -0
- pythonnative/components/layout.py +518 -0
- pythonnative/components/lists.py +785 -0
- pythonnative/components/media.py +204 -0
- pythonnative/components/overlays.py +107 -0
- pythonnative/components/pressable.py +252 -0
- pythonnative/components/structural.py +167 -0
- pythonnative/components/text.py +291 -0
- pythonnative/devclient.py +824 -0
- pythonnative/devserver/__init__.py +34 -0
- pythonnative/devserver/server.py +718 -0
- pythonnative/devserver/static/animation_graph.js +82 -0
- pythonnative/devserver/static/bridge.js +147 -0
- pythonnative/devserver/static/colors.js +70 -0
- pythonnative/devserver/static/host.js +552 -0
- pythonnative/devserver/static/index.html +60 -0
- pythonnative/devserver/static/layout.js +85 -0
- pythonnative/devserver/static/preview.css +415 -0
- pythonnative/devserver/static/renderer.js +1994 -0
- pythonnative/devserver/static/shell.js +345 -0
- pythonnative/devserver/static/yoga/LICENSE +21 -0
- pythonnative/devserver/static/yoga/binaries/yoga-wasm-base64-esm.js +75 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.d.ts +189 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.js +211 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.js.map +1 -0
- pythonnative/devserver/static/yoga/src/index.d.ts +12 -0
- pythonnative/devserver/static/yoga/src/index.js +16 -0
- pythonnative/devserver/static/yoga/src/index.js.map +1 -0
- pythonnative/devserver/static/yoga/src/load.d.ts +11 -0
- pythonnative/devserver/static/yoga/src/load.js +17 -0
- pythonnative/devserver/static/yoga/src/load.js.map +1 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.d.ts +155 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.js +125 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.js.map +1 -0
- pythonnative/devserver/watcher.py +267 -0
- pythonnative/devserver/ws.py +421 -0
- pythonnative/diagnostics.py +241 -0
- pythonnative/element.py +159 -0
- pythonnative/equality.py +19 -0
- pythonnative/events.py +231 -0
- pythonnative/gestures.py +1333 -0
- pythonnative/hooks.py +1621 -0
- pythonnative/hosts/__init__.py +63 -0
- pythonnative/hosts/base.py +596 -0
- pythonnative/hosts/native.py +302 -0
- pythonnative/hot_reload.py +585 -0
- pythonnative/layout.py +328 -0
- pythonnative/mutations.py +142 -0
- pythonnative/native/android/build.gradle +52 -0
- pythonnative/native/android/gradle.properties +3 -0
- pythonnative/native/android/settings.gradle +12 -0
- pythonnative/native/android/src/main/AndroidManifest.xml +11 -0
- pythonnative/native/android/src/main/cpp/CMakeLists.txt +9 -0
- pythonnative/native/android/src/main/cpp/yoga_jni.cpp +52 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeModules.kt +5 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeProps.kt +3705 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/PNContracts.kt +129 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/PNBridge.kt +261 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationGraph.kt +108 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +257 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/CommitState.kt +106 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +40 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +117 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +37 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +32 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +162 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +86 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScreenStackManager.kt +110 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +250 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +159 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/NativeLayout.kt +145 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/YogaNode.kt +29 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +61 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +158 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +99 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +188 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNAccessibilityDelegate.kt +48 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNBorderDrawable.kt +76 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNFrameLayout.kt +49 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PromiseTest.kt +89 -0
- pythonnative/native/ios/Package.swift +23 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimationGraph.swift +199 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimator.swift +312 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNBridge.swift +255 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNCommit.swift +104 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNRegistry.swift +142 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNTransaction.swift +166 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNButtonManagers.swift +207 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNImageManager.swift +222 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScreenStackManager.swift +107 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextInputManager.swift +297 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +155 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeModules.swift +1 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeProps.swift +3775 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/PNContracts.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Layout/PNLayout.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/HostModule.swift +80 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/PNNativeModule.swift +168 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/PermissionModules.swift +266 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNViewController.swift +237 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNAnimationGraphTests.swift +26 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNCommitTests.swift +86 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNManagerTests.swift +126 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNModuleTests.swift +111 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
- pythonnative/native/yoga/LICENSE +21 -0
- pythonnative/native/yoga/Package.swift +9 -0
- pythonnative/native/yoga/VENDORED.md +2 -0
- pythonnative/native/yoga/include/PNStyle.h +10 -0
- pythonnative/native/yoga/include/module.modulemap +5 -0
- pythonnative/native/yoga/include/yoga/YGConfig.h +158 -0
- pythonnative/native/yoga/include/yoga/YGEnums.h +142 -0
- pythonnative/native/yoga/include/yoga/YGMacros.h +99 -0
- pythonnative/native/yoga/include/yoga/YGNode.h +304 -0
- pythonnative/native/yoga/include/yoga/YGNodeLayout.h +35 -0
- pythonnative/native/yoga/include/yoga/YGNodeStyle.h +130 -0
- pythonnative/native/yoga/include/yoga/YGPixelGrid.h +29 -0
- pythonnative/native/yoga/include/yoga/YGValue.h +84 -0
- pythonnative/native/yoga/include/yoga/Yoga.h +21 -0
- pythonnative/native/yoga/python.cpp +16 -0
- pythonnative/native/yoga/style.cpp +272 -0
- pythonnative/native/yoga/yoga/CMakeLists.txt +41 -0
- pythonnative/native/yoga/yoga/YGConfig.cpp +92 -0
- pythonnative/native/yoga/yoga/YGConfig.h +158 -0
- pythonnative/native/yoga/yoga/YGEnums.cpp +262 -0
- pythonnative/native/yoga/yoga/YGEnums.h +142 -0
- pythonnative/native/yoga/yoga/YGMacros.h +99 -0
- pythonnative/native/yoga/yoga/YGNode.cpp +366 -0
- pythonnative/native/yoga/yoga/YGNode.h +304 -0
- pythonnative/native/yoga/yoga/YGNodeLayout.cpp +92 -0
- pythonnative/native/yoga/yoga/YGNodeLayout.h +35 -0
- pythonnative/native/yoga/yoga/YGNodeStyle.cpp +405 -0
- pythonnative/native/yoga/yoga/YGNodeStyle.h +130 -0
- pythonnative/native/yoga/yoga/YGPixelGrid.cpp +22 -0
- pythonnative/native/yoga/yoga/YGPixelGrid.h +29 -0
- pythonnative/native/yoga/yoga/YGValue.cpp +20 -0
- pythonnative/native/yoga/yoga/YGValue.h +84 -0
- pythonnative/native/yoga/yoga/Yoga.h +21 -0
- pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.cpp +563 -0
- pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.h +41 -0
- pythonnative/native/yoga/yoga/algorithm/Align.h +72 -0
- pythonnative/native/yoga/yoga/algorithm/Baseline.cpp +78 -0
- pythonnative/native/yoga/yoga/algorithm/Baseline.h +21 -0
- pythonnative/native/yoga/yoga/algorithm/BoundAxis.h +79 -0
- pythonnative/native/yoga/yoga/algorithm/Cache.cpp +121 -0
- pythonnative/native/yoga/yoga/algorithm/Cache.h +30 -0
- pythonnative/native/yoga/yoga/algorithm/CalculateLayout.cpp +2428 -0
- pythonnative/native/yoga/yoga/algorithm/CalculateLayout.h +38 -0
- pythonnative/native/yoga/yoga/algorithm/FlexDirection.h +120 -0
- pythonnative/native/yoga/yoga/algorithm/FlexLine.cpp +124 -0
- pythonnative/native/yoga/yoga/algorithm/FlexLine.h +75 -0
- pythonnative/native/yoga/yoga/algorithm/PixelGrid.cpp +132 -0
- pythonnative/native/yoga/yoga/algorithm/PixelGrid.h +29 -0
- pythonnative/native/yoga/yoga/algorithm/SizingMode.h +73 -0
- pythonnative/native/yoga/yoga/algorithm/TrailingPosition.h +44 -0
- pythonnative/native/yoga/yoga/config/Config.cpp +135 -0
- pythonnative/native/yoga/yoga/config/Config.h +92 -0
- pythonnative/native/yoga/yoga/debug/AssertFatal.cpp +53 -0
- pythonnative/native/yoga/yoga/debug/AssertFatal.h +29 -0
- pythonnative/native/yoga/yoga/debug/Log.cpp +107 -0
- pythonnative/native/yoga/yoga/debug/Log.h +34 -0
- pythonnative/native/yoga/yoga/enums/Align.h +47 -0
- pythonnative/native/yoga/yoga/enums/BoxSizing.h +40 -0
- pythonnative/native/yoga/yoga/enums/Dimension.h +40 -0
- pythonnative/native/yoga/yoga/enums/Direction.h +41 -0
- pythonnative/native/yoga/yoga/enums/Display.h +41 -0
- pythonnative/native/yoga/yoga/enums/Edge.h +47 -0
- pythonnative/native/yoga/yoga/enums/Errata.h +41 -0
- pythonnative/native/yoga/yoga/enums/ExperimentalFeature.h +39 -0
- pythonnative/native/yoga/yoga/enums/FlexDirection.h +42 -0
- pythonnative/native/yoga/yoga/enums/Gutter.h +41 -0
- pythonnative/native/yoga/yoga/enums/Justify.h +44 -0
- pythonnative/native/yoga/yoga/enums/LogLevel.h +44 -0
- pythonnative/native/yoga/yoga/enums/MeasureMode.h +41 -0
- pythonnative/native/yoga/yoga/enums/NodeType.h +40 -0
- pythonnative/native/yoga/yoga/enums/Overflow.h +41 -0
- pythonnative/native/yoga/yoga/enums/PhysicalEdge.h +21 -0
- pythonnative/native/yoga/yoga/enums/PositionType.h +41 -0
- pythonnative/native/yoga/yoga/enums/Unit.h +42 -0
- pythonnative/native/yoga/yoga/enums/Wrap.h +41 -0
- pythonnative/native/yoga/yoga/enums/YogaEnums.h +85 -0
- pythonnative/native/yoga/yoga/event/event.cpp +87 -0
- pythonnative/native/yoga/yoga/event/event.h +130 -0
- pythonnative/native/yoga/yoga/module.modulemap +21 -0
- pythonnative/native/yoga/yoga/node/CachedMeasurement.h +53 -0
- pythonnative/native/yoga/yoga/node/LayoutResults.cpp +48 -0
- pythonnative/native/yoga/yoga/node/LayoutResults.h +122 -0
- pythonnative/native/yoga/yoga/node/LayoutableChildren.h +148 -0
- pythonnative/native/yoga/yoga/node/Node.cpp +443 -0
- pythonnative/native/yoga/yoga/node/Node.h +337 -0
- pythonnative/native/yoga/yoga/numeric/Comparison.h +81 -0
- pythonnative/native/yoga/yoga/numeric/FloatOptional.h +93 -0
- pythonnative/native/yoga/yoga/style/SmallValueBuffer.h +133 -0
- pythonnative/native/yoga/yoga/style/Style.h +757 -0
- pythonnative/native/yoga/yoga/style/StyleLength.h +107 -0
- pythonnative/native/yoga/yoga/style/StyleValueHandle.h +98 -0
- pythonnative/native/yoga/yoga/style/StyleValuePool.h +127 -0
- pythonnative/native_modules/__init__.py +124 -0
- pythonnative/native_modules/app_state.py +99 -0
- pythonnative/native_modules/battery.py +75 -0
- pythonnative/native_modules/biometrics.py +42 -0
- pythonnative/native_modules/camera.py +65 -0
- pythonnative/native_modules/clipboard.py +46 -0
- pythonnative/native_modules/fallback.py +324 -0
- pythonnative/native_modules/file_system.py +145 -0
- pythonnative/native_modules/haptics.py +75 -0
- pythonnative/native_modules/linking.py +123 -0
- pythonnative/native_modules/location.py +75 -0
- pythonnative/native_modules/net_info.py +112 -0
- pythonnative/native_modules/notifications.py +129 -0
- pythonnative/native_modules/permissions.py +108 -0
- pythonnative/native_modules/registry.py +526 -0
- pythonnative/native_modules/secure_store.py +52 -0
- pythonnative/native_modules/share.py +51 -0
- pythonnative/native_views/__init__.py +375 -0
- pythonnative/native_views/base.py +316 -0
- pythonnative/native_views/bridge_backend.py +277 -0
- pythonnative/navigation/__init__.py +103 -0
- pythonnative/navigation/container.py +154 -0
- pythonnative/navigation/handle.py +540 -0
- pythonnative/navigation/hooks.py +133 -0
- pythonnative/navigation/host.py +58 -0
- pythonnative/navigation/linking.py +200 -0
- pythonnative/navigation/navigators.py +659 -0
- pythonnative/navigation/screen.py +149 -0
- pythonnative/navigation/state.py +269 -0
- pythonnative/net.py +248 -0
- pythonnative/platform.py +166 -0
- pythonnative/platform_metrics.py +252 -0
- pythonnative/preview.py +287 -0
- pythonnative/profiling.py +101 -0
- pythonnative/project/__init__.py +68 -0
- pythonnative/project/android.py +557 -0
- pythonnative/project/builder.py +817 -0
- pythonnative/project/config.py +773 -0
- pythonnative/project/deps.py +719 -0
- pythonnative/project/devices.py +304 -0
- pythonnative/project/doctor.py +283 -0
- pythonnative/project/fingerprint.py +171 -0
- pythonnative/project/icons.py +247 -0
- pythonnative/project/ios.py +325 -0
- pythonnative/project/lockfile.py +100 -0
- pythonnative/project/permissions.py +361 -0
- pythonnative/project/plugins.py +519 -0
- pythonnative/project/runtime_assets.py +183 -0
- pythonnative/py.typed +0 -0
- pythonnative/query.py +153 -0
- pythonnative/reconciler/__init__.py +29 -0
- pythonnative/reconciler/boundaries.py +375 -0
- pythonnative/reconciler/children.py +88 -0
- pythonnative/reconciler/core.py +1165 -0
- pythonnative/reconciler/layout_pass.py +393 -0
- pythonnative/reconciler/vnode.py +266 -0
- pythonnative/refresh.py +55 -0
- pythonnative/runtime.py +306 -0
- pythonnative/scheduler.py +159 -0
- pythonnative/sdk/__init__.py +153 -0
- pythonnative/sdk/_components.py +427 -0
- pythonnative/sdk/builtins.py +91 -0
- pythonnative/sdk/codegen.py +149 -0
- pythonnative/sdk/module_codegen.py +184 -0
- pythonnative/sdk/schema.py +224 -0
- pythonnative/sdk/templates/contracts.kt +46 -0
- pythonnative/sdk/templates/contracts.swift +46 -0
- pythonnative/storage.py +184 -0
- pythonnative/style.py +841 -0
- pythonnative/suspense.py +183 -0
- pythonnative/templates/android_template/app/build.gradle +75 -0
- pythonnative/templates/android_template/app/proguard-rules.pro +21 -0
- pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +24 -0
- pythonnative/templates/android_template/app/src/debug/AndroidManifest.xml +7 -0
- pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +32 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +130 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -0
- pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
- pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +30 -0
- pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +10 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +22 -0
- pythonnative/templates/android_template/app/src/main/res/values/colors.xml +5 -0
- pythonnative/templates/android_template/app/src/main/res/values/strings.xml +5 -0
- pythonnative/templates/android_template/app/src/main/res/values/themes.xml +9 -0
- pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +7 -0
- pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +13 -0
- pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +19 -0
- pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +17 -0
- pythonnative/templates/android_template/build.gradle +10 -0
- pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
- pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +6 -0
- pythonnative/templates/android_template/gradle.properties +23 -0
- pythonnative/templates/android_template/gradlew +185 -0
- pythonnative/templates/android_template/gradlew.bat +89 -0
- pythonnative/templates/android_template/settings.gradle +17 -0
- pythonnative/templates/ios_template/ios_template/AppDelegate.swift +51 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +13 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +6 -0
- pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +25 -0
- pythonnative/templates/ios_template/ios_template/BridgingHeader.h +14 -0
- pythonnative/templates/ios_template/ios_template/Info.plist +28 -0
- pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +390 -0
- pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +61 -0
- pythonnative/templates/ios_template/ios_template/ViewController.swift +23 -0
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +745 -0
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +36 -0
- pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +41 -0
- pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +32 -0
- pythonnative/testing/__init__.py +53 -0
- pythonnative/testing/backend.py +276 -0
- pythonnative/testing/harness.py +369 -0
- pythonnative/utils.py +145 -0
- pythonnative-0.40.0.dist-info/DELVEWHEEL +2 -0
- pythonnative-0.40.0.dist-info/METADATA +150 -0
- pythonnative-0.40.0.dist-info/RECORD +418 -0
- pythonnative-0.40.0.dist-info/WHEEL +5 -0
- pythonnative-0.40.0.dist-info/entry_points.txt +2 -0
- pythonnative-0.40.0.dist-info/licenses/LICENSE +21 -0
- pythonnative-0.40.0.dist-info/top_level.txt +1 -0
- pythonnative.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
package com.pythonnative.runtime.modules
|
|
2
|
+
|
|
3
|
+
import com.pythonnative.runtime.PNBridge
|
|
4
|
+
import com.pythonnative.runtime.bridge.JsonUtil
|
|
5
|
+
import com.pythonnative.runtime.bridge.MainThread
|
|
6
|
+
import org.json.JSONObject
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A named native module exposing methods to Python through
|
|
10
|
+
* `PNBridge.call(module, method, argsJson)`.
|
|
11
|
+
*
|
|
12
|
+
* Implementations settle the [Promise] synchronously (the result is
|
|
13
|
+
* returned inline) or later from any thread (the result is delivered
|
|
14
|
+
* as a `module` callback on the main thread). Unknown methods should
|
|
15
|
+
* call [Promise.rejectUnknownMethod].
|
|
16
|
+
*/
|
|
17
|
+
interface NativeModule {
|
|
18
|
+
/** The module name Python addresses, for example `"Clipboard"`. */
|
|
19
|
+
val name: String
|
|
20
|
+
|
|
21
|
+
/** Handle one call; must settle `promise` exactly once (now or later). */
|
|
22
|
+
fun call(method: String, args: JSONObject, promise: Promise)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Result envelopes for module calls and events, as JSON strings.
|
|
27
|
+
*/
|
|
28
|
+
object ModuleEnvelope {
|
|
29
|
+
/** Decode `{"call_id": n, "args": {...}}` into `(callId, args)`. */
|
|
30
|
+
fun decodeCall(argsJson: String): Pair<Long, JSONObject> {
|
|
31
|
+
val obj = if (argsJson.isBlank()) JSONObject() else JSONObject(argsJson)
|
|
32
|
+
val callId = obj.optLong("call_id", 0L)
|
|
33
|
+
val args = obj.optJSONObject("args") ?: JSONObject()
|
|
34
|
+
return callId to args
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** `{"ok": true, "value": ...}` */
|
|
38
|
+
fun ok(value: Any?): String = JSONObject().put("ok", true).put("value", JsonUtil.wrap(value)).toString()
|
|
39
|
+
|
|
40
|
+
/** `{"ok": false, "error": message, "code": code}` */
|
|
41
|
+
fun error(message: String, code: String? = null): String {
|
|
42
|
+
val obj = JSONObject().put("ok", false).put("error", message)
|
|
43
|
+
if (code != null) obj.put("code", code)
|
|
44
|
+
return obj.toString()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** `{"pending": true}` */
|
|
48
|
+
fun pending(): String = JSONObject().put("pending", true).toString()
|
|
49
|
+
|
|
50
|
+
/** `{"call_id": n, "ok": true, "value": ...}` for asynchronous settlement. */
|
|
51
|
+
fun settled(callId: Long, value: Any?): String =
|
|
52
|
+
JSONObject().put("call_id", callId).put("ok", true).put("value", JsonUtil.wrap(value)).toString()
|
|
53
|
+
|
|
54
|
+
/** `{"call_id": n, "ok": false, "error": message, "code": code}` for asynchronous rejection. */
|
|
55
|
+
fun settledError(callId: Long, message: String, code: String?): String {
|
|
56
|
+
val obj = JSONObject().put("call_id", callId).put("ok", false).put("error", message)
|
|
57
|
+
if (code != null) obj.put("code", code)
|
|
58
|
+
return obj.toString()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** `{"event": name, "payload": {...}}` */
|
|
62
|
+
fun event(event: String, payload: Any?): String =
|
|
63
|
+
JSONObject().put("event", event).put("payload", JsonUtil.wrap(payload)).toString()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The settlement handle for one module call.
|
|
68
|
+
*
|
|
69
|
+
* If [resolve] or [reject] runs before the module's `call` returns,
|
|
70
|
+
* the result is returned inline to Python. Otherwise Python receives
|
|
71
|
+
* `{"pending": true}` and the eventual settlement is delivered on the
|
|
72
|
+
* main thread as a `module` callback carrying the `call_id`.
|
|
73
|
+
*/
|
|
74
|
+
class Promise(val callId: Long, val module: String, private val dispatch: (Runnable) -> Unit = defaultDispatcher) {
|
|
75
|
+
private var returned = false
|
|
76
|
+
private var settledInline: String? = null
|
|
77
|
+
internal var onFinished: (() -> Unit)? = null
|
|
78
|
+
private var cancellation: (() -> Unit)? = null
|
|
79
|
+
var isCancelled = false
|
|
80
|
+
private set
|
|
81
|
+
|
|
82
|
+
/** Release native work when the Python awaiter is cancelled. */
|
|
83
|
+
@Synchronized fun onCancel(callback: () -> Unit) {
|
|
84
|
+
if (isCancelled) callback() else if (!isSettled) cancellation = callback
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@Synchronized fun cancel() {
|
|
88
|
+
if (isSettled) return
|
|
89
|
+
isCancelled = true
|
|
90
|
+
isSettled = true
|
|
91
|
+
val callback = cancellation
|
|
92
|
+
cancellation = null
|
|
93
|
+
onFinished?.invoke()
|
|
94
|
+
runCatching { callback?.invoke() }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Whether the promise has been resolved or rejected. */
|
|
98
|
+
var isSettled = false
|
|
99
|
+
private set
|
|
100
|
+
|
|
101
|
+
/** Resolve with `value` (JSON-encodable: primitives, maps, lists, `JSONObject`). */
|
|
102
|
+
@Synchronized fun resolve(value: Any?) {
|
|
103
|
+
if (isSettled) return
|
|
104
|
+
isSettled = true
|
|
105
|
+
cancellation = null
|
|
106
|
+
onFinished?.invoke()
|
|
107
|
+
if (!returned) {
|
|
108
|
+
settledInline = ModuleEnvelope.ok(value)
|
|
109
|
+
} else {
|
|
110
|
+
deliver(ModuleEnvelope.settled(callId, value))
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Reject with `message` and an optional machine-readable `code`. */
|
|
115
|
+
@Synchronized fun reject(message: String, code: String? = null) {
|
|
116
|
+
if (isSettled) return
|
|
117
|
+
isSettled = true
|
|
118
|
+
cancellation = null
|
|
119
|
+
onFinished?.invoke()
|
|
120
|
+
if (!returned) {
|
|
121
|
+
settledInline = ModuleEnvelope.error(message, code)
|
|
122
|
+
} else {
|
|
123
|
+
deliver(ModuleEnvelope.settledError(callId, message, code))
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Reject because the module has no method named `method`. */
|
|
128
|
+
fun rejectUnknownMethod(method: String) = reject("$module has no method '$method'", "unknown_method")
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Called by the bridge after `call` returns: yields the inline
|
|
132
|
+
* envelope when already settled, otherwise `{"pending": true}` and
|
|
133
|
+
* arms asynchronous delivery.
|
|
134
|
+
*/
|
|
135
|
+
@Synchronized fun markReturned(): String {
|
|
136
|
+
returned = true
|
|
137
|
+
return settledInline ?: ModuleEnvelope.pending()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private fun deliver(payload: String) {
|
|
141
|
+
val moduleName = module
|
|
142
|
+
dispatch(Runnable { PNBridge.callPython("module", 0, moduleName, payload) })
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
companion object {
|
|
146
|
+
/** How asynchronous settlements reach the main thread (replaceable in tests). */
|
|
147
|
+
var defaultDispatcher: (Runnable) -> Unit = { MainThread.post(it) }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Unsolicited module events (`{"event": name, "payload": {...}}`). */
|
|
152
|
+
object ModuleEvents {
|
|
153
|
+
/** Emit `event` for `module` on the main thread (posting if needed). */
|
|
154
|
+
fun emit(module: String, event: String, payload: Any?) {
|
|
155
|
+
val json = ModuleEnvelope.event(event, payload)
|
|
156
|
+
MainThread.runOnMain { PNBridge.callPython("module", 0, module, json) }
|
|
157
|
+
}
|
|
158
|
+
}
|
pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
package com.pythonnative.runtime.modules
|
|
2
|
+
|
|
3
|
+
import android.app.Notification
|
|
4
|
+
import android.app.NotificationChannel
|
|
5
|
+
import android.app.NotificationManager
|
|
6
|
+
import android.content.Context
|
|
7
|
+
import android.os.Build
|
|
8
|
+
import com.pythonnative.runtime.PNBridge
|
|
9
|
+
import com.pythonnative.runtime.bridge.JsonUtil
|
|
10
|
+
import com.pythonnative.runtime.bridge.MainThread
|
|
11
|
+
import com.pythonnative.runtime.bridge.PNLog
|
|
12
|
+
import com.pythonnative.runtime.bridge.str
|
|
13
|
+
import org.json.JSONObject
|
|
14
|
+
import kotlin.math.abs
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* `Notifications`: `request_permission()` (async; `POST_NOTIFICATIONS`
|
|
18
|
+
* on API 33+), `schedule({title, body, delay_seconds, identifier})`
|
|
19
|
+
* (a Handler-delayed local notification, in-process only),
|
|
20
|
+
* `cancel(identifier)`, and `get_device_token()` (`null`; no built-in
|
|
21
|
+
* push on Android).
|
|
22
|
+
*/
|
|
23
|
+
class NotificationsModule : NativeModule {
|
|
24
|
+
override val name = "Notifications"
|
|
25
|
+
private val delayed = HashMap<String, Runnable>()
|
|
26
|
+
|
|
27
|
+
override fun call(method: String, args: JSONObject, promise: Promise) {
|
|
28
|
+
when (method) {
|
|
29
|
+
"request_permission" -> requestPermission(promise)
|
|
30
|
+
"schedule" -> promise.resolve(schedule(args))
|
|
31
|
+
"cancel" -> {
|
|
32
|
+
cancel(args.str("identifier") ?: "")
|
|
33
|
+
promise.resolve(null)
|
|
34
|
+
}
|
|
35
|
+
"get_device_token" -> promise.resolve(null)
|
|
36
|
+
else -> promise.rejectUnknownMethod(method)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private fun requestPermission(promise: Promise) {
|
|
41
|
+
if (Build.VERSION.SDK_INT < 33) return promise.resolve(true)
|
|
42
|
+
BuiltinModules.permissions.request("notifications") { status ->
|
|
43
|
+
promise.resolve(status == PermissionsModule.GRANTED)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private fun schedule(args: JSONObject): Boolean {
|
|
48
|
+
val title = args.str("title") ?: ""
|
|
49
|
+
val body = args.str("body") ?: ""
|
|
50
|
+
val identifier = args.str("identifier") ?: "pn_${System.currentTimeMillis()}"
|
|
51
|
+
val delaySeconds = JsonUtil.toDouble(args.opt("delay_seconds"), 0.0)
|
|
52
|
+
cancel(identifier)
|
|
53
|
+
if (delaySeconds <= 0.0) return post(title, body, identifier)
|
|
54
|
+
val runnable = Runnable {
|
|
55
|
+
delayed.remove(identifier)
|
|
56
|
+
post(title, body, identifier)
|
|
57
|
+
}
|
|
58
|
+
delayed[identifier] = runnable
|
|
59
|
+
MainThread.postDelayed(runnable, (delaySeconds * 1000).toLong())
|
|
60
|
+
return true
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private fun cancel(identifier: String) {
|
|
64
|
+
delayed.remove(identifier)?.let { MainThread.remove(it) }
|
|
65
|
+
try {
|
|
66
|
+
manager()?.cancel(notificationId(identifier))
|
|
67
|
+
} catch (e: Exception) {
|
|
68
|
+
PNLog.swallowed("Notifications.cancel", e)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private fun manager(): NotificationManager? =
|
|
73
|
+
PNBridge.context().getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
|
|
74
|
+
|
|
75
|
+
private fun post(title: String, body: String, identifier: String): Boolean {
|
|
76
|
+
return try {
|
|
77
|
+
val ctx = PNBridge.context()
|
|
78
|
+
val nm = manager() ?: return false
|
|
79
|
+
val builder = if (Build.VERSION.SDK_INT >= 26) {
|
|
80
|
+
nm.createNotificationChannel(NotificationChannel(CHANNEL_ID, "PythonNative", NotificationManager.IMPORTANCE_DEFAULT))
|
|
81
|
+
Notification.Builder(ctx, CHANNEL_ID)
|
|
82
|
+
} else {
|
|
83
|
+
@Suppress("DEPRECATION")
|
|
84
|
+
Notification.Builder(ctx)
|
|
85
|
+
}
|
|
86
|
+
builder.setContentTitle(title).setContentText(body).setSmallIcon(android.R.drawable.ic_dialog_info)
|
|
87
|
+
nm.notify(notificationId(identifier), builder.build())
|
|
88
|
+
true
|
|
89
|
+
} catch (e: Exception) {
|
|
90
|
+
PNLog.swallowed("Notifications.post", e)
|
|
91
|
+
false
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private fun notificationId(identifier: String): Int = abs(identifier.hashCode()) % Int.MAX_VALUE
|
|
96
|
+
|
|
97
|
+
private companion object {
|
|
98
|
+
const val CHANNEL_ID = "pn_default"
|
|
99
|
+
}
|
|
100
|
+
}
|
pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
package com.pythonnative.runtime.modules
|
|
2
|
+
|
|
3
|
+
import android.content.pm.PackageManager
|
|
4
|
+
import android.os.Build
|
|
5
|
+
import androidx.core.app.ActivityCompat
|
|
6
|
+
import androidx.core.content.ContextCompat
|
|
7
|
+
import com.pythonnative.runtime.PNBridge
|
|
8
|
+
import com.pythonnative.runtime.bridge.str
|
|
9
|
+
import org.json.JSONObject
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* `Permissions.check(permission)` (sync) and `request(permission)`
|
|
13
|
+
* (async, routed through `onRequestPermissionsResult`). Statuses are
|
|
14
|
+
* `granted`, `denied`, `blocked`, and `undetermined`.
|
|
15
|
+
*
|
|
16
|
+
* Permission names are the `[permissions]` keys from pythonnative.toml
|
|
17
|
+
* (`camera`, `microphone`, `photo_library`, `location_when_in_use`,
|
|
18
|
+
* `contacts`, `notifications`); the Python facade validates them before
|
|
19
|
+
* the call reaches this module, so an unknown name here is a bug rather
|
|
20
|
+
* than user input, and is rejected rather than answered.
|
|
21
|
+
*/
|
|
22
|
+
class PermissionsModule : NativeModule {
|
|
23
|
+
override val name = "Permissions"
|
|
24
|
+
private val pending = HashMap<Int, Pair<String, (String) -> Unit>>()
|
|
25
|
+
|
|
26
|
+
override fun call(method: String, args: JSONObject, promise: Promise) {
|
|
27
|
+
val permission = args.str("permission") ?: ""
|
|
28
|
+
if (method == "check" || method == "request") {
|
|
29
|
+
if (!MANIFEST.containsKey(permission)) {
|
|
30
|
+
return promise.reject("unknown permission '$permission'", "bad_args")
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
when (method) {
|
|
34
|
+
"check" -> promise.resolve(check(permission))
|
|
35
|
+
"request" -> request(permission) { promise.resolve(it) }
|
|
36
|
+
else -> promise.rejectUnknownMethod(method)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Current status of `permission` without prompting. */
|
|
41
|
+
fun check(permission: String): String {
|
|
42
|
+
val manifest = MANIFEST[permission] ?: return UNDETERMINED
|
|
43
|
+
if (permission == "notifications" && Build.VERSION.SDK_INT < 33) return GRANTED
|
|
44
|
+
if (permission == "photo_library" && Build.VERSION.SDK_INT < 33) {
|
|
45
|
+
return statusOf("android.permission.READ_EXTERNAL_STORAGE")
|
|
46
|
+
}
|
|
47
|
+
return statusOf(manifest)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private fun statusOf(manifest: String): String {
|
|
51
|
+
val ctx = PNBridge.activity() ?: return UNDETERMINED
|
|
52
|
+
val granted = ContextCompat.checkSelfPermission(ctx, manifest) == PackageManager.PERMISSION_GRANTED
|
|
53
|
+
if (granted) return GRANTED
|
|
54
|
+
// "denied" with no rationale after a previous denial means "don't ask again".
|
|
55
|
+
val asked = ctx.getSharedPreferences("pn_permissions", 0).getBoolean(manifest, false)
|
|
56
|
+
return if (asked && !ActivityCompat.shouldShowRequestPermissionRationale(ctx, manifest)) BLOCKED else DENIED
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Prompt for `permission` if needed and report the resulting status to `onDone`. */
|
|
60
|
+
fun request(permission: String, onDone: (String) -> Unit) {
|
|
61
|
+
val manifest = MANIFEST[permission] ?: return onDone(UNDETERMINED)
|
|
62
|
+
if (check(permission) == GRANTED) return onDone(GRANTED)
|
|
63
|
+
val activity = PNBridge.activity() ?: return onDone(check(permission))
|
|
64
|
+
val target = if (permission == "photo_library" && Build.VERSION.SDK_INT < 33) "android.permission.READ_EXTERNAL_STORAGE" else manifest
|
|
65
|
+
val code = RequestCodes.next()
|
|
66
|
+
pending[code] = target to onDone
|
|
67
|
+
try {
|
|
68
|
+
ActivityCompat.requestPermissions(activity, arrayOf(target), code)
|
|
69
|
+
} catch (e: Exception) {
|
|
70
|
+
pending.remove(code)
|
|
71
|
+
onDone(check(permission))
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Route `Activity.onRequestPermissionsResult`; `true` when a pending request matched. */
|
|
76
|
+
fun onRequestPermissionsResult(requestCode: Int, grantResults: IntArray): Boolean {
|
|
77
|
+
val (manifest, onDone) = pending.remove(requestCode) ?: return false
|
|
78
|
+
PNBridge.activity()?.getSharedPreferences("pn_permissions", 0)?.edit()?.putBoolean(manifest, true)?.apply()
|
|
79
|
+
val granted = grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
|
|
80
|
+
onDone(if (granted) GRANTED else statusOf(manifest))
|
|
81
|
+
return true
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
companion object {
|
|
85
|
+
const val GRANTED = "granted"
|
|
86
|
+
const val DENIED = "denied"
|
|
87
|
+
const val BLOCKED = "blocked"
|
|
88
|
+
const val UNDETERMINED = "undetermined"
|
|
89
|
+
|
|
90
|
+
val MANIFEST = mapOf(
|
|
91
|
+
"camera" to "android.permission.CAMERA",
|
|
92
|
+
"microphone" to "android.permission.RECORD_AUDIO",
|
|
93
|
+
"photo_library" to "android.permission.READ_MEDIA_IMAGES",
|
|
94
|
+
"location_when_in_use" to "android.permission.ACCESS_FINE_LOCATION",
|
|
95
|
+
"contacts" to "android.permission.READ_CONTACTS",
|
|
96
|
+
"notifications" to "android.permission.POST_NOTIFICATIONS",
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
package com.pythonnative.runtime.modules
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.SharedPreferences
|
|
5
|
+
import com.pythonnative.runtime.PNBridge
|
|
6
|
+
import com.pythonnative.runtime.bridge.PNLog
|
|
7
|
+
import com.pythonnative.runtime.bridge.str
|
|
8
|
+
import org.json.JSONObject
|
|
9
|
+
|
|
10
|
+
/** `Storage`: `get/set/delete/all_keys/clear` over the `pn_async_storage` SharedPreferences file. */
|
|
11
|
+
class StorageModule : NativeModule {
|
|
12
|
+
override val name = "Storage"
|
|
13
|
+
|
|
14
|
+
private fun prefs(): SharedPreferences =
|
|
15
|
+
PNBridge.context().getSharedPreferences("pn_async_storage", Context.MODE_PRIVATE)
|
|
16
|
+
|
|
17
|
+
override fun call(method: String, args: JSONObject, promise: Promise) {
|
|
18
|
+
val key = args.str("key")
|
|
19
|
+
when (method) {
|
|
20
|
+
"get", "get_item" -> promise.resolve(prefs().getString(key ?: "", null))
|
|
21
|
+
"set", "set_item" -> {
|
|
22
|
+
prefs().edit().putString(key ?: "", args.str("value") ?: "").apply()
|
|
23
|
+
promise.resolve(null)
|
|
24
|
+
}
|
|
25
|
+
"delete", "remove", "remove_item" -> {
|
|
26
|
+
prefs().edit().remove(key ?: "").apply()
|
|
27
|
+
promise.resolve(null)
|
|
28
|
+
}
|
|
29
|
+
"all_keys", "get_all_keys" -> promise.resolve(prefs().all.keys.sorted())
|
|
30
|
+
"clear" -> {
|
|
31
|
+
prefs().edit().clear().apply()
|
|
32
|
+
promise.resolve(null)
|
|
33
|
+
}
|
|
34
|
+
else -> promise.rejectUnknownMethod(method)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* `SecureStore`: `set_item/get_item/delete_item` over `EncryptedSharedPreferences`.
|
|
41
|
+
*
|
|
42
|
+
* security-crypto 1.1 deprecates the whole API in favour of hand-rolled Keystore code, but the
|
|
43
|
+
* file name and schemes must stay identical to what earlier PythonNative releases wrote so that
|
|
44
|
+
* existing secrets remain readable, hence the suppression.
|
|
45
|
+
*/
|
|
46
|
+
@Suppress("DEPRECATION")
|
|
47
|
+
class SecureStoreModule : NativeModule {
|
|
48
|
+
override val name = "SecureStore"
|
|
49
|
+
private var prefs: SharedPreferences? = null
|
|
50
|
+
|
|
51
|
+
private fun prefs(): SharedPreferences? {
|
|
52
|
+
prefs?.let { return it }
|
|
53
|
+
return try {
|
|
54
|
+
val ctx = PNBridge.context()
|
|
55
|
+
val master = androidx.security.crypto.MasterKey.Builder(ctx)
|
|
56
|
+
.setKeyScheme(androidx.security.crypto.MasterKey.KeyScheme.AES256_GCM)
|
|
57
|
+
.build()
|
|
58
|
+
androidx.security.crypto.EncryptedSharedPreferences.create(
|
|
59
|
+
ctx,
|
|
60
|
+
"com.pythonnative.securestore",
|
|
61
|
+
master,
|
|
62
|
+
androidx.security.crypto.EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
|
63
|
+
androidx.security.crypto.EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
|
|
64
|
+
).also { prefs = it }
|
|
65
|
+
} catch (e: Exception) {
|
|
66
|
+
PNLog.rateLimited("securestore", "EncryptedSharedPreferences unavailable", e)
|
|
67
|
+
null
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override fun call(method: String, args: JSONObject, promise: Promise) {
|
|
72
|
+
val key = args.str("key") ?: ""
|
|
73
|
+
val store = prefs()
|
|
74
|
+
when (method) {
|
|
75
|
+
"set_item" -> {
|
|
76
|
+
if (store == null) return promise.resolve(false)
|
|
77
|
+
store.edit().putString(key, args.str("value") ?: "").apply()
|
|
78
|
+
promise.resolve(true)
|
|
79
|
+
}
|
|
80
|
+
"get_item" -> promise.resolve(store?.getString(key, null))
|
|
81
|
+
"delete_item" -> {
|
|
82
|
+
if (store == null) return promise.resolve(false)
|
|
83
|
+
store.edit().remove(key).apply()
|
|
84
|
+
promise.resolve(true)
|
|
85
|
+
}
|
|
86
|
+
else -> promise.rejectUnknownMethod(method)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
package com.pythonnative.runtime.modules
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.BroadcastReceiver
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.Intent
|
|
7
|
+
import android.content.IntentFilter
|
|
8
|
+
import android.net.ConnectivityManager
|
|
9
|
+
import android.net.Network
|
|
10
|
+
import android.net.NetworkCapabilities
|
|
11
|
+
import android.os.BatteryManager
|
|
12
|
+
import com.pythonnative.runtime.PNBridge
|
|
13
|
+
import com.pythonnative.runtime.bridge.MainThread
|
|
14
|
+
import com.pythonnative.runtime.bridge.PNLog
|
|
15
|
+
import org.json.JSONObject
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* `Battery`: `get_level()` (0..1 or -1) and `get_state()`
|
|
19
|
+
* (`unknown|unplugged|charging|full`), plus `change` events from the
|
|
20
|
+
* sticky `ACTION_BATTERY_CHANGED` broadcast.
|
|
21
|
+
*/
|
|
22
|
+
class BatteryModule : NativeModule {
|
|
23
|
+
override val name = "Battery"
|
|
24
|
+
private var receiver: BroadcastReceiver? = null
|
|
25
|
+
|
|
26
|
+
override fun call(method: String, args: JSONObject, promise: Promise) {
|
|
27
|
+
when (method) {
|
|
28
|
+
"get_level" -> promise.resolve(level())
|
|
29
|
+
"get_state" -> promise.resolve(state())
|
|
30
|
+
else -> promise.rejectUnknownMethod(method)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private fun manager(): BatteryManager? =
|
|
35
|
+
PNBridge.context().getSystemService(Context.BATTERY_SERVICE) as? BatteryManager
|
|
36
|
+
|
|
37
|
+
private fun level(): Double {
|
|
38
|
+
val pct = manager()?.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) ?: return -1.0
|
|
39
|
+
return if (pct in 0..100) pct / 100.0 else -1.0
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private fun state(): String = stateName(manager()?.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS) ?: -1)
|
|
43
|
+
|
|
44
|
+
private fun stateName(status: Int): String = when (status) {
|
|
45
|
+
BatteryManager.BATTERY_STATUS_CHARGING -> "charging"
|
|
46
|
+
BatteryManager.BATTERY_STATUS_FULL -> "full"
|
|
47
|
+
BatteryManager.BATTERY_STATUS_DISCHARGING, BatteryManager.BATTERY_STATUS_NOT_CHARGING -> "unplugged"
|
|
48
|
+
else -> "unknown"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
fun attach(activity: Activity) {
|
|
52
|
+
if (receiver != null) return
|
|
53
|
+
val r = object : BroadcastReceiver() {
|
|
54
|
+
override fun onReceive(context: Context?, intent: Intent?) {
|
|
55
|
+
if (intent == null) return
|
|
56
|
+
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
|
|
57
|
+
val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
|
|
58
|
+
val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
|
|
59
|
+
val fraction = if (level >= 0 && scale > 0) level.toDouble() / scale.toDouble() else -1.0
|
|
60
|
+
ModuleEvents.emit(name, "change", JSONObject().put("level", fraction).put("state", stateName(status)))
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
activity.registerReceiver(r, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
|
|
65
|
+
receiver = r
|
|
66
|
+
} catch (e: Exception) {
|
|
67
|
+
PNLog.swallowed("Battery.attach", e)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fun detach(activity: Activity) {
|
|
72
|
+
receiver?.let {
|
|
73
|
+
try {
|
|
74
|
+
activity.unregisterReceiver(it)
|
|
75
|
+
} catch (e: Exception) {
|
|
76
|
+
PNLog.swallowed("Battery.detach", e)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
receiver = null
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* `NetInfo.fetch()` → `{is_connected, type, is_internet_reachable}`;
|
|
85
|
+
* a default `NetworkCallback` emits `change` events on the main thread.
|
|
86
|
+
*/
|
|
87
|
+
class NetInfoModule : NativeModule {
|
|
88
|
+
override val name = "NetInfo"
|
|
89
|
+
private var callback: ConnectivityManager.NetworkCallback? = null
|
|
90
|
+
private var last: JSONObject? = null
|
|
91
|
+
|
|
92
|
+
override fun call(method: String, args: JSONObject, promise: Promise) {
|
|
93
|
+
when (method) {
|
|
94
|
+
"fetch" -> promise.resolve(snapshot())
|
|
95
|
+
else -> promise.rejectUnknownMethod(method)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private fun manager(): ConnectivityManager? =
|
|
100
|
+
PNBridge.context().getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
|
|
101
|
+
|
|
102
|
+
fun snapshot(): JSONObject {
|
|
103
|
+
val offline = JSONObject().put("is_connected", false).put("type", "none").put("is_internet_reachable", false)
|
|
104
|
+
return try {
|
|
105
|
+
val manager = manager() ?: return offline
|
|
106
|
+
val network = manager.activeNetwork ?: return offline
|
|
107
|
+
val caps = manager.getNetworkCapabilities(network) ?: return offline
|
|
108
|
+
val kind = when {
|
|
109
|
+
caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> "wifi"
|
|
110
|
+
caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> "cellular"
|
|
111
|
+
caps.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> "ethernet"
|
|
112
|
+
else -> "other"
|
|
113
|
+
}
|
|
114
|
+
JSONObject()
|
|
115
|
+
.put("is_connected", true)
|
|
116
|
+
.put("type", kind)
|
|
117
|
+
.put("is_internet_reachable", caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET))
|
|
118
|
+
} catch (e: Exception) {
|
|
119
|
+
offline
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
fun attach(activity: Activity) {
|
|
124
|
+
if (callback != null) return
|
|
125
|
+
try {
|
|
126
|
+
val manager = activity.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
|
127
|
+
val cb = object : ConnectivityManager.NetworkCallback() {
|
|
128
|
+
override fun onAvailable(network: Network) = changed()
|
|
129
|
+
override fun onLost(network: Network) = changed()
|
|
130
|
+
override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) = changed()
|
|
131
|
+
}
|
|
132
|
+
manager.registerDefaultNetworkCallback(cb)
|
|
133
|
+
callback = cb
|
|
134
|
+
} catch (e: Exception) {
|
|
135
|
+
PNLog.swallowed("NetInfo.attach", e)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private fun changed() {
|
|
140
|
+
// NetworkCallback fires on a binder thread; hop to main before reading state.
|
|
141
|
+
MainThread.post {
|
|
142
|
+
val current = snapshot()
|
|
143
|
+
if (last?.toString() == current.toString()) return@post
|
|
144
|
+
last = current
|
|
145
|
+
ModuleEvents.emit(name, "change", current)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
fun detach(activity: Activity) {
|
|
150
|
+
callback?.let {
|
|
151
|
+
try {
|
|
152
|
+
(activity.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).unregisterNetworkCallback(it)
|
|
153
|
+
} catch (e: Exception) {
|
|
154
|
+
PNLog.swallowed("NetInfo.detach", e)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
callback = null
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** `AppState.current_state()` plus `change` events (`active|inactive|background`). */
|
|
162
|
+
class AppStateModule : NativeModule {
|
|
163
|
+
override val name = "AppState"
|
|
164
|
+
private var state = "active"
|
|
165
|
+
|
|
166
|
+
override fun call(method: String, args: JSONObject, promise: Promise) {
|
|
167
|
+
when (method) {
|
|
168
|
+
"current_state" -> promise.resolve(state)
|
|
169
|
+
else -> promise.rejectUnknownMethod(method)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
fun transition(next: String) {
|
|
174
|
+
if (state == next) return
|
|
175
|
+
state = next
|
|
176
|
+
ModuleEvents.emit(name, "change", JSONObject().put("state", next))
|
|
177
|
+
}
|
|
178
|
+
}
|
pythonnative/native/android/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.pythonnative.runtime.plugins
|
|
2
|
+
|
|
3
|
+
import com.pythonnative.runtime.bridge.PNRegistry
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Plugin registrations generated by `pn build`.
|
|
7
|
+
*
|
|
8
|
+
* The build tool overwrites this file with one `register` call per
|
|
9
|
+
* plugin entry declared in the project's `pythonnative.plugins` entry
|
|
10
|
+
* points. Nothing else may depend on its content beyond [registerAll].
|
|
11
|
+
*/
|
|
12
|
+
object GeneratedPlugins {
|
|
13
|
+
/** Register every generated plugin with `registry`. */
|
|
14
|
+
@Suppress("UNUSED_PARAMETER")
|
|
15
|
+
fun registerAll(registry: PNRegistry) {}
|
|
16
|
+
}
|